Merge "Refactor PWM to fully capture shortcut gesture" into udc-qpr-dev
diff --git a/core/java/android/content/res/ThemedResourceCache.java b/core/java/android/content/res/ThemedResourceCache.java
index a7cd168..690dfcf 100644
--- a/core/java/android/content/res/ThemedResourceCache.java
+++ b/core/java/android/content/res/ThemedResourceCache.java
@@ -137,8 +137,10 @@
*/
@UnsupportedAppUsage
public void onConfigurationChange(@Config int configChanges) {
- prune(configChanges);
- mGeneration++;
+ synchronized (this) {
+ pruneLocked(configChanges);
+ mGeneration++;
+ }
}
/**
@@ -214,22 +216,20 @@
* simply prune missing weak references
* @return {@code true} if the cache is completely empty after pruning
*/
- private boolean prune(@Config int configChanges) {
- synchronized (this) {
- if (mThemedEntries != null) {
- for (int i = mThemedEntries.size() - 1; i >= 0; i--) {
- if (pruneEntriesLocked(mThemedEntries.valueAt(i), configChanges)) {
- mThemedEntries.removeAt(i);
- }
+ private boolean pruneLocked(@Config int configChanges) {
+ if (mThemedEntries != null) {
+ for (int i = mThemedEntries.size() - 1; i >= 0; i--) {
+ if (pruneEntriesLocked(mThemedEntries.valueAt(i), configChanges)) {
+ mThemedEntries.removeAt(i);
}
}
-
- pruneEntriesLocked(mNullThemedEntries, configChanges);
- pruneEntriesLocked(mUnthemedEntries, configChanges);
-
- return mThemedEntries == null && mNullThemedEntries == null
- && mUnthemedEntries == null;
}
+
+ pruneEntriesLocked(mNullThemedEntries, configChanges);
+ pruneEntriesLocked(mUnthemedEntries, configChanges);
+
+ return mThemedEntries == null && mNullThemedEntries == null
+ && mUnthemedEntries == null;
}
private boolean pruneEntriesLocked(@Nullable LongSparseArray<WeakReference<T>> entries,
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 8eb02a1..dbc1be1 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -432,7 +432,8 @@
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, InsetsState insetsState,
- boolean forceLayout, int displayId, int syncSeqId, boolean dragResizing) {
+ boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
+ int syncSeqId, boolean dragResizing) {
Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
reportDraw ? 1 : 0,
mergedConfiguration);
@@ -1286,9 +1287,9 @@
visibleFrame.intersect(mInsetsState.getDisplayFrame());
WindowInsets windowInsets = mInsetsState.calculateInsets(visibleFrame,
null /* ignoringVisibilityState */, config.isScreenRound(),
- mLayout.softInputMode, mLayout.flags, SYSTEM_UI_FLAG_VISIBLE,
- mLayout.type, config.windowConfiguration.getWindowingMode(),
- null /* idSideMap */);
+ false /* alwaysConsumeSystemBars */, mLayout.softInputMode,
+ mLayout.flags, SYSTEM_UI_FLAG_VISIBLE, mLayout.type,
+ config.windowConfiguration.getWindowingMode(), null /* idSideMap */);
if (!fixedSize) {
final Rect padding = mIWallpaperEngine.mDisplayPadding;
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 33edc27..d554514 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -56,7 +56,8 @@
void resized(in ClientWindowFrames frames, boolean reportDraw,
in MergedConfiguration newMergedConfiguration, in InsetsState insetsState,
- boolean forceLayout, int displayId, int syncSeqId, boolean dragResizing);
+ boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
+ int syncSeqId, boolean dragResizing);
/**
* Called when this window retrieved control over a specified set of insets sources.
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 8813c39..6d96bb94 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -737,8 +737,10 @@
/**
* Called to get the expected window insets.
+ *
+ * @return {@code true} if system bars are always consumed.
*/
- void getWindowInsets(int displayId, in IBinder token, out InsetsState outInsetsState);
+ boolean getWindowInsets(int displayId, in IBinder token, out InsetsState outInsetsState);
/**
* Returns a list of {@link android.view.DisplayInfo} for the logical display. This is not
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 4c50858..6c5f195 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -40,7 +40,6 @@
import static android.view.InsetsState.ISIDE_RIGHT;
import static android.view.InsetsState.ISIDE_TOP;
import static android.view.WindowInsets.Type.ime;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.inputmethod.ImeTracker.DEBUG_IME_VISIBILITY;
import static android.view.inputmethod.ImeTracker.TOKEN_NONE;
@@ -64,6 +63,7 @@
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimation.Bounds;
+import android.view.WindowManager.LayoutParams;
import android.view.animation.Interpolator;
import android.view.inputmethod.ImeTracker;
@@ -401,7 +401,8 @@
private Insets getInsetsFromState(InsetsState state, Rect frame,
@Nullable @InternalInsetsSide SparseIntArray idSideMap) {
return state.calculateInsets(frame, null /* ignoringVisibilityState */,
- false /* isScreenRound */, SOFT_INPUT_ADJUST_RESIZE /* legacySoftInputMode */,
+ false /* isScreenRound */, false /* alwaysConsumeSystemBars */,
+ LayoutParams.SOFT_INPUT_ADJUST_RESIZE /* legacySoftInputMode*/,
0 /* legacyWindowFlags */, 0 /* legacySystemUiFlags */, TYPE_APPLICATION,
WINDOWING_MODE_UNDEFINED, idSideMap).getInsets(mTypes);
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index e5d031b..c1eacb5 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -797,9 +797,9 @@
}
WindowInsets insets = state.calculateInsets(mFrame, mState /* ignoringVisibilityState*/,
- mLastInsets.isRound(), mLastLegacySoftInputMode, mLastLegacyWindowFlags,
- mLastLegacySystemUiFlags, mWindowType, mLastWindowingMode,
- null /* idSideMap */);
+ mLastInsets.isRound(), false /* alwaysConsumeSystemBars */,
+ mLastLegacySoftInputMode, mLastLegacyWindowFlags, mLastLegacySystemUiFlags,
+ mWindowType, mLastWindowingMode, null /* idSideMap */);
mHost.dispatchWindowInsetsAnimationProgress(insets,
Collections.unmodifiableList(runningAnimations));
if (DEBUG) {
@@ -841,7 +841,6 @@
return mLastDispatchedState;
}
- @VisibleForTesting
public boolean onStateChanged(InsetsState state) {
boolean stateChanged = false;
if (!CAPTION_ON_SHELL) {
@@ -955,20 +954,21 @@
}
/**
- * @see InsetsState#calculateInsets(Rect, InsetsState, boolean, int, int, int, int, int,
- * android.util.SparseIntArray)
+ * @see InsetsState#calculateInsets(Rect, InsetsState, boolean, boolean, int, int, int, int,
+ * int, android.util.SparseIntArray)
*/
@VisibleForTesting
- public WindowInsets calculateInsets(boolean isScreenRound, int windowType, int windowingMode,
- int legacySoftInputMode, int legacyWindowFlags, int legacySystemUiFlags) {
+ public WindowInsets calculateInsets(boolean isScreenRound, boolean alwaysConsumeSystemBars,
+ int windowType, int windowingMode, int legacySoftInputMode, int legacyWindowFlags,
+ int legacySystemUiFlags) {
mWindowType = windowType;
mLastWindowingMode = windowingMode;
mLastLegacySoftInputMode = legacySoftInputMode;
mLastLegacyWindowFlags = legacyWindowFlags;
mLastLegacySystemUiFlags = legacySystemUiFlags;
mLastInsets = mState.calculateInsets(mFrame, null /* ignoringVisibilityState*/,
- isScreenRound, legacySoftInputMode, legacyWindowFlags, legacySystemUiFlags,
- windowType, windowingMode, null /* idSideMap */);
+ isScreenRound, alwaysConsumeSystemBars, legacySoftInputMode, legacyWindowFlags,
+ legacySystemUiFlags, windowType, windowingMode, null /* idSideMap */);
return mLastInsets;
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 828938b..c13b9ab 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -40,7 +40,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
-import android.app.WindowConfiguration.WindowingMode;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Parcel;
@@ -137,8 +136,9 @@
* @return The calculated insets.
*/
public WindowInsets calculateInsets(Rect frame, @Nullable InsetsState ignoringVisibilityState,
- boolean isScreenRound, int legacySoftInputMode, int legacyWindowFlags,
- int legacySystemUiFlags, int windowType, @WindowingMode int windowingMode,
+ boolean isScreenRound, boolean alwaysConsumeSystemBars,
+ int legacySoftInputMode, int legacyWindowFlags, int legacySystemUiFlags,
+ int windowType, @WindowConfiguration.WindowingMode int windowingMode,
@Nullable @InternalInsetsSide SparseIntArray idSideMap) {
Insets[] typeInsetsMap = new Insets[Type.SIZE];
Insets[] typeMaxInsetsMap = new Insets[Type.SIZE];
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f51e3a3..f1cde3b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -30744,6 +30744,13 @@
final Rect mCaptionInsets = new Rect();
/**
+ * In multi-window we force show the system bars. Because we don't want that the surface
+ * size changes in this mode, we instead have a flag whether the system bars sizes should
+ * always be consumed, so the app is treated like there are no virtual system bars at all.
+ */
+ boolean mAlwaysConsumeSystemBars;
+
+ /**
* The internal insets given by this window. This value is
* supplied by the client (through
* {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index ef76f4a..bef28b2 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -82,6 +82,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_CANCEL_AND_REDRAW;
+import static android.view.WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
@@ -740,6 +741,7 @@
final Rect mPendingBackDropFrame = new Rect();
+ boolean mPendingAlwaysConsumeSystemBars;
private int mRelayoutSeq;
private final Rect mWinFrameInScreen = new Rect();
private final InsetsState mTempInsets = new InsetsState();
@@ -1364,6 +1366,9 @@
}
}
+ mAttachInfo.mAlwaysConsumeSystemBars =
+ (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS) != 0;
+ mPendingAlwaysConsumeSystemBars = mAttachInfo.mAlwaysConsumeSystemBars;
mInsetsController.onStateChanged(mTempInsets);
mInsetsController.onControlsChanged(mTempControls.get());
final InsetsState state = mInsetsController.getState();
@@ -1877,8 +1882,8 @@
final MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg2;
CompatibilityInfo.applyOverrideScaleIfNeeded(mergedConfiguration);
final boolean forceNextWindowRelayout = args.argi1 != 0;
- final int displayId = args.argi2;
- final boolean dragResizing = args.argi4 != 0;
+ final int displayId = args.argi3;
+ final boolean dragResizing = args.argi5 != 0;
final Rect frame = frames.frame;
final Rect displayFrame = frames.displayFrame;
@@ -1930,7 +1935,8 @@
}
mForceNextWindowRelayout |= forceNextWindowRelayout;
- mSyncSeqId = args.argi3 > mSyncSeqId ? args.argi3 : mSyncSeqId;
+ mPendingAlwaysConsumeSystemBars = args.argi2 != 0;
+ mSyncSeqId = args.argi4 > mSyncSeqId ? args.argi4 : mSyncSeqId;
if (msg == MSG_RESIZED_REPORT) {
reportNextDraw("resized");
@@ -2815,8 +2821,8 @@
if (mLastWindowInsets == null || forceConstruct) {
final Configuration config = getConfiguration();
mLastWindowInsets = mInsetsController.calculateInsets(
- config.isScreenRound(), mWindowAttributes.type,
- config.windowConfiguration.getWindowingMode(),
+ config.isScreenRound(), mAttachInfo.mAlwaysConsumeSystemBars,
+ mWindowAttributes.type, config.windowConfiguration.getWindowingMode(),
mWindowAttributes.softInputMode, mWindowAttributes.flags,
(mWindowAttributes.systemUiVisibility
| mWindowAttributes.subtreeSystemUiVisibility));
@@ -3278,6 +3284,8 @@
surfaceSizeChanged = true;
mLastSurfaceSize.set(mSurfaceSize.x, mSurfaceSize.y);
}
+ final boolean alwaysConsumeSystemBarsChanged =
+ mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars;
updateColorModeIfNeeded(lp.getColorMode());
surfaceCreated = !hadSurface && mSurface.isValid();
surfaceDestroyed = hadSurface && !mSurface.isValid();
@@ -3291,6 +3299,10 @@
if (surfaceReplaced) {
mSurfaceSequenceId++;
}
+ if (alwaysConsumeSystemBarsChanged) {
+ mAttachInfo.mAlwaysConsumeSystemBars = mPendingAlwaysConsumeSystemBars;
+ dispatchApplyInsets = true;
+ }
if (updateCaptionInsets()) {
dispatchApplyInsets = true;
}
@@ -8289,6 +8301,9 @@
CompatibilityInfo.applyOverrideScaleIfNeeded(mPendingMergedConfiguration);
mInsetsController.onStateChanged(mTempInsets);
mInsetsController.onControlsChanged(mTempControls.get());
+
+ mPendingAlwaysConsumeSystemBars =
+ (relayoutResult & RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS) != 0;
}
final int transformHint = SurfaceControl.rotationToBufferTransform(
@@ -8911,7 +8926,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private void dispatchResized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout,
- int displayId, int syncSeqId, boolean dragResizing) {
+ boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing) {
Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
SomeArgs args = SomeArgs.obtain();
final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
@@ -8930,9 +8945,10 @@
? new MergedConfiguration(mergedConfiguration) : mergedConfiguration;
args.arg3 = insetsState;
args.argi1 = forceLayout ? 1 : 0;
- args.argi2 = displayId;
- args.argi3 = syncSeqId;
- args.argi4 = dragResizing ? 1 : 0;
+ args.argi2 = alwaysConsumeSystemBars ? 1 : 0;
+ args.argi3 = displayId;
+ args.argi4 = syncSeqId;
+ args.argi5 = dragResizing ? 1 : 0;
msg.obj = args;
mHandler.sendMessage(msg);
@@ -10326,11 +10342,12 @@
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, InsetsState insetsState,
- boolean forceLayout, int displayId, int syncSeqId, boolean dragResizing) {
+ boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId,
+ boolean dragResizing) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchResized(frames, reportDraw, mergedConfiguration, insetsState,
- forceLayout, displayId, syncSeqId, dragResizing);
+ forceLayout, alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing);
}
}
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 7757c25..57a4161 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -1429,6 +1429,14 @@
/** @hide */
@NonNull
+ public Builder setAlwaysConsumeSystemBars(boolean alwaysConsumeSystemBars) {
+ // TODO (b/277891341): Remove this and related usages. This has been replaced by
+ // #setForceConsumingTypes.
+ return this;
+ }
+
+ /** @hide */
+ @NonNull
public Builder setForceConsumingTypes(@InsetsType int forceConsumingTypes) {
mForceConsumingTypes = forceConsumingTypes;
return this;
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index c9368f1..99a4f6b 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -79,9 +79,16 @@
public static final int RELAYOUT_RES_SURFACE_RESIZED = 1 << 2;
/**
+ * In multi-window we force show the system bars. Because we don't want that the surface size
+ * changes in this mode, we instead have a flag whether the system bar sizes should always be
+ * consumed, so the app is treated like there is no virtual system bars at all.
+ */
+ public static final int RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS = 1 << 3;
+
+ /**
* The window manager has told the window it cannot draw this frame and should retry again.
*/
- public static final int RELAYOUT_RES_CANCEL_AND_REDRAW = 1 << 3;
+ public static final int RELAYOUT_RES_CANCEL_AND_REDRAW = 1 << 4;
/**
* Flag for relayout: the client will be later giving
@@ -92,7 +99,13 @@
public static final int ADD_FLAG_IN_TOUCH_MODE = 0x1;
public static final int ADD_FLAG_APP_VISIBLE = 0x2;
- public static final int ADD_FLAG_USE_BLAST = 0x4;
+ public static final int ADD_FLAG_USE_BLAST = 0x8;
+
+ /**
+ * Like {@link #RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS}, but as a "hint" when adding the
+ * window.
+ */
+ public static final int ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS = 0x4;
public static final int ADD_OKAY = 0;
public static final int ADD_BAD_APP_TOKEN = -1;
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 1efac4d..7d3d283 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -631,8 +631,8 @@
mTmpFrames.displayFrame.set(mTmpFrames.frame);
mTmpConfig.setConfiguration(mConfiguration, mConfiguration);
s.mClient.resized(mTmpFrames, false /* reportDraw */, mTmpConfig, state,
- false /* forceLayout */, s.mDisplayId, Integer.MAX_VALUE,
- false /* dragResizing */);
+ false /* forceLayout */, false /* alwaysConsumeSystemBars */, s.mDisplayId,
+ Integer.MAX_VALUE, false /* dragResizing */);
} catch (RemoteException e) {
// Too bad
}
diff --git a/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl b/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl
index 8a30f8c..a11c6d0 100644
--- a/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl
+++ b/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl
@@ -115,4 +115,13 @@
* @param callback the interface to be called.
*/
void setConnectionCallback(in IWindowMagnificationConnectionCallback callback);
+
+ /**
+ * Notify System UI the magnification scale on the specified display for userId is changed.
+ *
+ * @param userId the user id.
+ * @param displayId the logical display id.
+ * @param scale magnification scale.
+ */
+ void onUserMagnificationScaleChanged(int userId, int displayId, float scale);
}
diff --git a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
index aa9225b..e9d7b9b 100644
--- a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
@@ -1118,7 +1118,7 @@
@InputConnection.CursorUpdateFilter int cursorUpdateFilter, int imeDisplayId) {
final InputConnection ic = getInputConnection();
if (ic == null || !isActive()) {
- Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
+ Log.w(TAG, "requestCursorUpdates on inactive InputConnection");
return false;
}
if (mParentInputMethodManager.mRequestCursorUpdateDisplayIdCheck.get()
diff --git a/core/java/android/window/WindowMetricsController.java b/core/java/android/window/WindowMetricsController.java
index d08d5cf..2858f0a 100644
--- a/core/java/android/window/WindowMetricsController.java
+++ b/core/java/android/window/WindowMetricsController.java
@@ -112,14 +112,15 @@
Rect bounds, boolean isScreenRound, int windowingMode) {
try {
final InsetsState insetsState = new InsetsState();
- WindowManagerGlobal.getWindowManagerService().getWindowInsets(
- displayId, token, insetsState);
+ final boolean alwaysConsumeSystemBars = WindowManagerGlobal.getWindowManagerService()
+ .getWindowInsets(displayId, token, insetsState);
final float overrideInvScale = CompatibilityInfo.getOverrideInvertedScale();
if (overrideInvScale != 1f) {
insetsState.scale(overrideInvScale);
}
return insetsState.calculateInsets(bounds, null /* ignoringVisibilityState */,
- isScreenRound, SOFT_INPUT_ADJUST_NOTHING, 0 /* flags */, SYSTEM_UI_FLAG_VISIBLE,
+ isScreenRound, alwaysConsumeSystemBars, SOFT_INPUT_ADJUST_NOTHING,
+ 0 /* flags */, SYSTEM_UI_FLAG_VISIBLE,
WindowManager.LayoutParams.INVALID_WINDOW_TYPE, windowingMode,
null /* idSideMap */);
} catch (RemoteException e) {
diff --git a/core/java/android/window/WindowProviderService.java b/core/java/android/window/WindowProviderService.java
index f2ae973..611da3c 100644
--- a/core/java/android/window/WindowProviderService.java
+++ b/core/java/android/window/WindowProviderService.java
@@ -34,6 +34,7 @@
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.os.IBinder;
+import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams.WindowType;
@@ -52,6 +53,8 @@
@UiContext
public abstract class WindowProviderService extends Service implements WindowProvider {
+ private static final String TAG = WindowProviderService.class.getSimpleName();
+
private final Bundle mOptions;
private final WindowTokenClient mWindowToken = new WindowTokenClient();
private final WindowContextController mController = new WindowContextController(mWindowToken);
@@ -194,8 +197,16 @@
public final Context createServiceBaseContext(ActivityThread mainThread,
LoadedApk packageInfo) {
final Context context = super.createServiceBaseContext(mainThread, packageInfo);
- final Display display = context.getSystemService(DisplayManager.class)
- .getDisplay(getInitialDisplayId());
+ final DisplayManager displayManager = context.getSystemService(DisplayManager.class);
+ final int initialDisplayId = getInitialDisplayId();
+ Display display = displayManager.getDisplay(initialDisplayId);
+ // Fallback to use the default display if the initial display to start WindowProviderService
+ // is detached.
+ if (display == null) {
+ Log.e(TAG, "Display with id " + initialDisplayId + " not found, falling back to "
+ + "DEFAULT_DISPLAY");
+ display = displayManager.getDisplay(DEFAULT_DISPLAY);
+ }
return context.createTokenContext(mWindowToken, display);
}
diff --git a/core/java/com/android/internal/accessibility/common/MagnificationConstants.java b/core/java/com/android/internal/accessibility/common/MagnificationConstants.java
index 95c3419..2c49303 100644
--- a/core/java/com/android/internal/accessibility/common/MagnificationConstants.java
+++ b/core/java/com/android/internal/accessibility/common/MagnificationConstants.java
@@ -17,7 +17,7 @@
package com.android.internal.accessibility.common;
/**
- * Collection of common constants for accessibility shortcut.
+ * Collection of common constants for accessibility magnification.
*/
public final class MagnificationConstants {
private MagnificationConstants() {}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 0ac7765..600058e 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -53,7 +53,7 @@
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout,
- int displayId, int seqId, boolean dragResizing) {
+ boolean alwaysConsumeSystemBars, int displayId, int seqId, boolean dragResizing) {
if (reportDraw) {
try {
mSession.finishDrawing(this, null /* postDrawTransaction */, seqId);
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index a9c0e41..f45db23 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -81,6 +81,7 @@
Insets.of(10, 10, 10, 10), rect, rect, rect, rect));
mController.calculateInsets(
false,
+ false,
TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
SOFT_INPUT_ADJUST_RESIZE, 0, 0);
mImeConsumer = mController.getImeSourceConsumer();
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 76e4a6b..0692052 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -171,6 +171,7 @@
mController.onStateChanged(state);
mController.calculateInsets(
false,
+ false,
TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
SOFT_INPUT_ADJUST_RESIZE, 0, 0);
mController.onFrameChanged(new Rect(0, 0, 100, 100));
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 6b32350..fde1a6d 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -100,7 +100,7 @@
.setVisible(true);
SparseIntArray typeSideMap = new SparseIntArray();
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+ false, SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
typeSideMap);
assertEquals(Insets.of(0, 100, 0, 100), insets.getSystemWindowInsets());
assertEquals(Insets.of(0, 100, 0, 100), insets.getInsets(Type.all()));
@@ -119,7 +119,8 @@
.setFrame(new Rect(0, 100, 100, 300))
.setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+ false, SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+ null);
assertEquals(100, insets.getStableInsetBottom());
assertEquals(Insets.of(0, 0, 0, 100), insets.getInsetsIgnoringVisibility(systemBars()));
assertEquals(Insets.of(0, 0, 0, 200), insets.getSystemWindowInsets());
@@ -137,7 +138,7 @@
.setFrame(new Rect(80, 0, 100, 300))
.setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+ false, 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(statusBars()));
assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(navigationBars()));
@@ -152,7 +153,7 @@
.setFrame(new Rect(80, 0, 100, 300))
.setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+ false, 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.statusBars()));
assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.navigationBars()));
@@ -167,7 +168,8 @@
.setFrame(new Rect(0, 200, 100, 300))
.setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- SOFT_INPUT_ADJUST_NOTHING, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+ false, SOFT_INPUT_ADJUST_NOTHING, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+ null);
assertEquals(0, insets.getSystemWindowInsetBottom());
assertEquals(100, insets.getInsets(ime()).bottom);
assertTrue(insets.isVisible(ime()));
@@ -182,10 +184,10 @@
.setFrame(new Rect(0, 200, 100, 300))
.setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- SOFT_INPUT_ADJUST_NOTHING, 0, SYSTEM_UI_FLAG_LAYOUT_STABLE, TYPE_APPLICATION,
+ false, SOFT_INPUT_ADJUST_NOTHING, 0, SYSTEM_UI_FLAG_LAYOUT_STABLE, TYPE_APPLICATION,
WINDOWING_MODE_UNDEFINED, null);
assertEquals(100, insets.getSystemWindowInsetTop());
- insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
+ insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false,
SOFT_INPUT_ADJUST_NOTHING, 0, 0 /* legacySystemUiFlags */, TYPE_APPLICATION,
WINDOWING_MODE_UNDEFINED, null);
assertEquals(0, insets.getSystemWindowInsetTop());
@@ -197,10 +199,10 @@
.setFrame(new Rect(0, 0, 100, 100))
.setVisible(false);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- SOFT_INPUT_ADJUST_NOTHING, FLAG_FULLSCREEN, SYSTEM_UI_FLAG_LAYOUT_STABLE,
+ false, SOFT_INPUT_ADJUST_NOTHING, FLAG_FULLSCREEN, SYSTEM_UI_FLAG_LAYOUT_STABLE,
TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
assertEquals(0, insets.getSystemWindowInsetTop());
- insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
+ insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false,
SOFT_INPUT_ADJUST_NOTHING, 0, 0 /* legacySystemUiFlags */, TYPE_APPLICATION,
WINDOWING_MODE_UNDEFINED, null);
assertEquals(0, insets.getSystemWindowInsetTop());
@@ -212,19 +214,19 @@
.setFrame(new Rect(0, 0, 100, 100))
.setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
+ false, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
0 /* legacySystemUiFlags */, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
assertEquals(0, insets.getSystemWindowInsetTop());
insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
+ false, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
0 /* legacySystemUiFlags */, TYPE_SYSTEM_ERROR, WINDOWING_MODE_UNDEFINED, null);
assertEquals(100, insets.getSystemWindowInsetTop());
insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
+ false, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
0 /* legacySystemUiFlags */, TYPE_WALLPAPER, WINDOWING_MODE_UNDEFINED, null);
assertEquals(100, insets.getSystemWindowInsetTop());
insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
+ false, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
0 /* legacySystemUiFlags */, TYPE_APPLICATION, WINDOWING_MODE_FREEFORM, null);
assertEquals(100, insets.getSystemWindowInsetTop());
}
@@ -266,7 +268,7 @@
.setFrame(new Rect(80, 0, 100, 300))
.setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+ false, 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(statusBars()));
assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(navigationBars()));
@@ -281,7 +283,7 @@
.setFrame(new Rect(80, 0, 100, 300))
.setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+ false, 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(statusBars()));
assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(navigationBars()));
@@ -296,7 +298,7 @@
.setFrame(new Rect(0, 200, 100, 300))
.setVisible(true);
mState.removeSource(ID_IME);
- WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
+ WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false,
SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
assertEquals(0, insets.getSystemWindowInsetBottom());
}
@@ -528,7 +530,7 @@
new Rect(0, 0, 1, 2),
new Rect(197, 296, 200, 300),
new Rect(197, 296, 200, 300)));
- DisplayCutout cutout = mState.calculateInsets(new Rect(1, 1, 199, 300), null, false,
+ DisplayCutout cutout = mState.calculateInsets(new Rect(1, 1, 199, 300), null, false, false,
SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
new SparseIntArray()).getDisplayCutout();
assertEquals(0, cutout.getSafeInsetLeft());
@@ -554,7 +556,7 @@
new RoundedCorner(POSITION_BOTTOM_RIGHT, 20, 180, 380),
new RoundedCorner(POSITION_BOTTOM_LEFT, 20, 20, 380)));
WindowInsets windowInsets = mState.calculateInsets(new Rect(1, 2, 197, 396), null, false,
- SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION,
+ false, SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION,
WINDOWING_MODE_UNDEFINED, new SparseIntArray());
assertEquals(new RoundedCorner(POSITION_TOP_LEFT, 10, 9, 8),
windowInsets.getRoundedCorner(POSITION_TOP_LEFT));
@@ -571,7 +573,7 @@
mState.setDisplayFrame(new Rect(0, 0, 200, 400));
mState.setDisplayShape(DisplayShape.createDefaultDisplayShape(200, 400, false));
WindowInsets windowInsets = mState.calculateInsets(new Rect(10, 20, 200, 400), null, false,
- SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION,
+ false, SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION,
WINDOWING_MODE_UNDEFINED, new SparseIntArray());
final DisplayShape expect =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index 586a794..5e42782 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -347,7 +347,8 @@
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration newMergedConfiguration, InsetsState insetsState,
- boolean forceLayout, int displayId, int syncSeqId, boolean dragResizing) {}
+ boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId,
+ boolean dragResizing) {}
@Override
public void insetsControlChanged(InsetsState insetsState,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index 262d487..2dbc444 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -434,7 +434,7 @@
"Set divider bar %s from %s", interactive ? "interactive" : "non-interactive",
from);
mInteractive = interactive;
- if (!mInteractive && mMoving) {
+ if (!mInteractive && hideHandle && mMoving) {
final int position = mSplitLayout.getDividePosition();
mSplitLayout.flingDividePosition(
mLastDraggingPosition,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
index a9ccdf6..2b10377 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
@@ -323,7 +323,11 @@
}
}
if (mShown) {
- fadeOutDecor(()-> animFinishedCallback.accept(true));
+ fadeOutDecor(()-> {
+ if (mRunningAnimationCount == 0 && animFinishedCallback != null) {
+ animFinishedCallback.accept(true);
+ }
+ });
} else {
// Decor surface is hidden so release it directly.
releaseDecor(t);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index f70d3ae..e8fa638 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -593,9 +593,6 @@
void flingDividePosition(int from, int to, int duration,
@Nullable Runnable flingFinishedCallback) {
if (from == to) {
- // No animation run, still callback to stop resizing.
- mSplitLayoutHandler.onLayoutSizeChanged(this);
-
if (flingFinishedCallback != null) {
flingFinishedCallback.run();
}
@@ -773,15 +770,13 @@
ActivityManager.RunningTaskInfo task1, ActivityManager.RunningTaskInfo task2) {
boolean boundsChanged = false;
if (!mBounds1.equals(mWinBounds1) || !task1.token.equals(mWinToken1)) {
- wct.setBounds(task1.token, mBounds1);
- wct.setSmallestScreenWidthDp(task1.token, getSmallestWidthDp(mBounds1));
+ setTaskBounds(wct, task1, mBounds1);
mWinBounds1.set(mBounds1);
mWinToken1 = task1.token;
boundsChanged = true;
}
if (!mBounds2.equals(mWinBounds2) || !task2.token.equals(mWinToken2)) {
- wct.setBounds(task2.token, mBounds2);
- wct.setSmallestScreenWidthDp(task2.token, getSmallestWidthDp(mBounds2));
+ setTaskBounds(wct, task2, mBounds2);
mWinBounds2.set(mBounds2);
mWinToken2 = task2.token;
boundsChanged = true;
@@ -789,6 +784,13 @@
return boundsChanged;
}
+ /** Set bounds to the {@link WindowContainerTransaction} for single task. */
+ public void setTaskBounds(WindowContainerTransaction wct,
+ ActivityManager.RunningTaskInfo task, Rect bounds) {
+ wct.setBounds(task.token, bounds);
+ wct.setSmallestScreenWidthDp(task.token, getSmallestWidthDp(bounds));
+ }
+
private int getSmallestWidthDp(Rect bounds) {
mTempRect.set(bounds);
mTempRect.inset(getDisplayStableInsets(mContext));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
index 0289da9..d7ea1c0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
@@ -89,4 +89,9 @@
int userId1, int userId2) {
return (packageName1 != null && packageName1.equals(packageName2)) && (userId1 == userId2);
}
+
+ /** Generates a common log message for split screen failures */
+ public static String splitFailureMessage(String caller, String reason) {
+ return "(" + caller + ") Splitscreen aborted: " + reason;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 4fda4b7..40ea276 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -286,7 +286,7 @@
visualIndicator?.releaseVisualIndicator(t)
visualIndicator = null
addMoveToFullscreenChanges(callbackWCT, task)
- shellTaskOrganizer.applyTransaction(callbackWCT)
+ transitions.startTransition(TRANSIT_CHANGE, callbackWCT, null /* handler */)
}
} else {
addMoveToFullscreenChanges(wct, task)
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 e294229..3669bce 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
@@ -31,6 +31,7 @@
import static com.android.wm.shell.common.split.SplitScreenUtils.isValidToSplit;
import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
import static com.android.wm.shell.common.split.SplitScreenUtils.samePackage;
+import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMessage;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
@@ -50,6 +51,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArrayMap;
+import android.util.Log;
import android.util.Slog;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
@@ -551,6 +553,8 @@
} else {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
+ Log.w(TAG, splitFailureMessage("startShortcut",
+ "app package " + packageName + " does not support multi-instance"));
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
return;
@@ -580,6 +584,8 @@
taskId = INVALID_TASK_ID;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
+ Log.w(TAG, splitFailureMessage("startShortcutAndTaskWithLegacyTransition",
+ "app package " + packageName1 + " does not support multi-instance"));
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
}
@@ -612,6 +618,8 @@
taskId = INVALID_TASK_ID;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
+ Log.w(TAG, splitFailureMessage("startShortcutAndTask",
+ "app package " + packageName1 + " does not support multi-instance"));
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
}
@@ -647,6 +655,8 @@
taskId = INVALID_TASK_ID;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
+ Log.w(TAG, splitFailureMessage("startIntentAndTaskWithLegacyTransition",
+ "app package " + packageName1 + " does not support multi-instance"));
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
}
@@ -677,6 +687,8 @@
taskId = INVALID_TASK_ID;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
+ Log.w(TAG, splitFailureMessage("startIntentAndTask",
+ "app package " + packageName1 + " does not support multi-instance"));
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
}
@@ -705,6 +717,8 @@
pendingIntent2 = null;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
+ Log.w(TAG, splitFailureMessage("startIntentsWithLegacyTransition",
+ "app package " + packageName1 + " does not support multi-instance"));
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
}
@@ -734,6 +748,8 @@
pendingIntent2 = null;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
+ Log.w(TAG, splitFailureMessage("startIntents",
+ "app package " + packageName1 + " does not support multi-instance"));
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
}
@@ -780,6 +796,8 @@
} else {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
+ Log.w(TAG, splitFailureMessage("startIntent",
+ "app package " + packageName1 + " does not support multi-instance"));
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
return;
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 bf70d48..6961dab 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
@@ -28,6 +28,7 @@
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.TRANSIT_CHANGE;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.transitTypeToString;
@@ -41,6 +42,7 @@
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.common.split.SplitScreenConstants.splitPositionToString;
import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
+import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMessage;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
@@ -473,6 +475,8 @@
if (isEnteringSplit && mSideStage.getChildCount() == 0) {
mMainExecutor.execute(() -> exitSplitScreen(
null /* childrenToTop */, EXIT_REASON_UNKNOWN));
+ Log.w(TAG, splitFailureMessage("startShortcut",
+ "side stage was not populated"));
mSplitUnsupportedToast.show();
}
@@ -560,6 +564,8 @@
if (isEnteringSplit && mSideStage.getChildCount() == 0) {
mMainExecutor.execute(() -> exitSplitScreen(
null /* childrenToTop */, EXIT_REASON_UNKNOWN));
+ Log.w(TAG, splitFailureMessage("startIntentLegacy",
+ "side stage was not populated"));
mSplitUnsupportedToast.show();
}
@@ -1090,6 +1096,8 @@
mMainExecutor.execute(() ->
exitSplitScreen(mMainStage.getChildCount() == 0
? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
+ Log.w(TAG, splitFailureMessage("onRemoteAnimationFinishedOrCancelled",
+ "main or side stage was not populated."));
mSplitUnsupportedToast.show();
} else {
mSyncQueue.queue(evictWct);
@@ -1109,6 +1117,8 @@
if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
mMainExecutor.execute(() -> exitSplitScreen(mMainStage.getChildCount() == 0
? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
+ Log.w(TAG, splitFailureMessage("onRemoteAnimationFinished",
+ "main or side stage was not populated"));
mSplitUnsupportedToast.show();
return;
}
@@ -1293,20 +1303,12 @@
final boolean mainStageVisible = mMainStage.mRootTaskInfo.isVisible;
final boolean oneStageVisible =
mMainStage.mRootTaskInfo.isVisible != mSideStage.mRootTaskInfo.isVisible;
- if (oneStageVisible) {
+ if (oneStageVisible && !ENABLE_SHELL_TRANSITIONS) {
// Dismiss split because there's show-when-locked activity showing on top of keyguard.
// Also make sure the task contains show-when-locked activity remains on top after split
// dismissed.
- if (!ENABLE_SHELL_TRANSITIONS) {
- final StageTaskListener toTop = mainStageVisible ? mMainStage : mSideStage;
- exitSplitScreen(toTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
- } else {
- final int dismissTop = mainStageVisible ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- prepareExitSplitScreen(dismissTop, wct);
- mSplitTransitions.startDismissTransition(wct, this, dismissTop,
- EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
- }
+ final StageTaskListener toTop = mainStageVisible ? mMainStage : mSideStage;
+ exitSplitScreen(toTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
}
}
@@ -1561,6 +1563,8 @@
// split bounds.
wct.setSmallestScreenWidthDp(mMainStage.mRootTaskInfo.token,
SMALLEST_SCREEN_WIDTH_DP_UNDEFINED);
+ mSplitLayout.getInvisibleBounds(mTempRect1);
+ mSplitLayout.setTaskBounds(wct, mSideStage.mRootTaskInfo, mTempRect1);
}
wct.reorder(mRootTaskInfo.token, true);
setRootForceTranslucent(false, wct);
@@ -2376,6 +2380,15 @@
// so appends operations to exit split.
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
}
+ } else if (type == TRANSIT_KEYGUARD_OCCLUDE && triggerTask.topActivity != null
+ && isSplitScreenVisible()) {
+ // Split include show when lock activity case, check the top activity under which
+ // stage and move it to the top.
+ int top = triggerTask.topActivity.equals(mMainStage.mRootTaskInfo.topActivity)
+ ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
+ prepareExitSplitScreen(top, out);
+ mSplitTransitions.setDismissTransition(transition, top,
+ EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
}
// When split in the background, it should be only opening/dismissing transition and
@@ -2704,12 +2717,13 @@
}
} else {
if (mainChild == null || sideChild == null) {
- Log.w(TAG, "Launched 2 tasks in split, but didn't receive"
- + " 2 tasks in transition. Possibly one of them failed to launch");
final int dismissTop = mainChild != null ? STAGE_TYPE_MAIN :
(sideChild != null ? STAGE_TYPE_SIDE : STAGE_TYPE_UNDEFINED);
mSplitTransitions.mPendingEnter.cancel(
(cancelWct, cancelT) -> prepareExitSplitScreen(dismissTop, cancelWct));
+ Log.w(TAG, splitFailureMessage("startPendingEnterAnimation",
+ "launched 2 tasks in split, but didn't receive "
+ + "2 tasks in transition. Possibly one of them failed to launch"));
mSplitUnsupportedToast.show();
return true;
}
@@ -3169,7 +3183,7 @@
}
@Override
- public void onNoLongerSupportMultiWindow() {
+ public void onNoLongerSupportMultiWindow(ActivityManager.RunningTaskInfo taskInfo) {
if (mMainStage.isActive()) {
final boolean isMainStage = mMainStageListener == this;
if (!ENABLE_SHELL_TRANSITIONS) {
@@ -3184,6 +3198,9 @@
prepareExitSplitScreen(stageType, wct);
mSplitTransitions.startDismissTransition(wct, StageCoordinator.this, stageType,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
+ Log.w(TAG, splitFailureMessage("onNoLongerSupportMultiWindow",
+ "app package " + taskInfo.baseActivity.getPackageName()
+ + " does not support splitscreen, or is a controlled activity type"));
mSplitUnsupportedToast.show();
}
}
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 3ef4f02..e2c55e4 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
@@ -81,7 +81,7 @@
void onRootTaskVanished();
- void onNoLongerSupportMultiWindow();
+ void onNoLongerSupportMultiWindow(ActivityManager.RunningTaskInfo taskInfo);
}
private final Context mContext;
@@ -226,7 +226,7 @@
taskInfo.getWindowingMode())) {
// Leave split screen if the task no longer supports multi window or have
// uncontrolled task.
- mCallbacks.onNoLongerSupportMultiWindow();
+ mCallbacks.onNoLongerSupportMultiWindow(taskInfo);
return;
}
mChildrenTaskInfo.put(taskInfo.taskId, taskInfo);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index 1d879a13..c2f15f6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -214,7 +214,8 @@
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, InsetsState insetsState,
- boolean forceLayout, int displayId, int seqId, boolean dragResizing) {
+ boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int seqId,
+ boolean dragResizing) {
final TaskSnapshotWindow snapshot = mOuter.get();
if (snapshot == null) {
return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskView.java
index 4faa929..0d77a2e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskView.java
@@ -26,6 +26,7 @@
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
+import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.Region;
import android.view.SurfaceControl;
@@ -69,8 +70,10 @@
private final Rect mTmpRect = new Rect();
private final Rect mTmpRootRect = new Rect();
private final int[] mTmpLocation = new int[2];
+ private final Rect mBoundsOnScreen = new Rect();
private final TaskViewTaskController mTaskViewTaskController;
private Region mObscuredTouchRegion;
+ private Insets mCaptionInsets;
public TaskView(Context context, TaskViewTaskController taskViewTaskController) {
super(context, null, 0, 0, true /* disableBackgroundLayer */);
@@ -169,6 +172,25 @@
}
/**
+ * Sets a region of the task to inset to allow for a caption bar. Currently only top insets
+ * are supported.
+ * <p>
+ * This region will be factored in as an area of taskview that is not touchable activity
+ * content (i.e. you don't need to additionally set {@link #setObscuredTouchRect(Rect)} for
+ * the caption area).
+ *
+ * @param captionInsets the insets to apply to task view.
+ */
+ public void setCaptionInsets(Insets captionInsets) {
+ mCaptionInsets = captionInsets;
+ if (captionInsets == null) {
+ // If captions are null we can set them now; otherwise they'll get set in
+ // onComputeInternalInsets.
+ mTaskViewTaskController.setCaptionInsets(null);
+ }
+ }
+
+ /**
* Call when view position or size has changed. Do not call when animating.
*/
public void onLocationChanged() {
@@ -230,6 +252,15 @@
getLocationInWindow(mTmpLocation);
mTmpRect.set(mTmpLocation[0], mTmpLocation[1],
mTmpLocation[0] + getWidth(), mTmpLocation[1] + getHeight());
+ if (mCaptionInsets != null) {
+ mTmpRect.inset(mCaptionInsets);
+ getBoundsOnScreen(mBoundsOnScreen);
+ mTaskViewTaskController.setCaptionInsets(new Rect(
+ mBoundsOnScreen.left,
+ mBoundsOnScreen.top,
+ mBoundsOnScreen.right + getWidth(),
+ mBoundsOnScreen.top + mCaptionInsets.top));
+ }
inoutInfo.touchableRegion.op(mTmpRect, Region.Op.DIFFERENCE);
if (mObscuredTouchRegion != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
index 163cf50..064af04 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
@@ -33,6 +33,7 @@
import android.util.CloseGuard;
import android.util.Slog;
import android.view.SurfaceControl;
+import android.view.WindowInsets;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -82,6 +83,10 @@
private TaskView.Listener mListener;
private Executor mListenerExecutor;
+ /** Used to inset the activity content to allow space for a caption bar. */
+ private final Binder mCaptionInsetsOwner = new Binder();
+ private Rect mCaptionInsets;
+
public TaskViewTaskController(Context context, ShellTaskOrganizer organizer,
TaskViewTransitions taskViewTransitions, SyncTransactionQueue syncQueue) {
mContext = context;
@@ -436,6 +441,32 @@
mTaskViewTransitions.closeTaskView(wct, this);
}
+ /**
+ * Sets a region of the task to inset to allow for a caption bar.
+ *
+ * @param captionInsets the rect for the insets in screen coordinates.
+ */
+ void setCaptionInsets(Rect captionInsets) {
+ if (mCaptionInsets != null && mCaptionInsets.equals(captionInsets)) {
+ return;
+ }
+ mCaptionInsets = captionInsets;
+ applyCaptionInsetsIfNeeded();
+ }
+
+ void applyCaptionInsetsIfNeeded() {
+ if (mTaskToken == null) return;
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (mCaptionInsets != null) {
+ wct.addInsetsSource(mTaskToken, mCaptionInsetsOwner, 0,
+ WindowInsets.Type.captionBar(), mCaptionInsets);
+ } else {
+ wct.removeInsetsSource(mTaskToken, mCaptionInsetsOwner, 0,
+ WindowInsets.Type.captionBar());
+ }
+ mTaskOrganizer.applyTransaction(wct);
+ }
+
/** Should be called when the client surface is destroyed. */
public void surfaceDestroyed() {
mSurfaceCreated = false;
@@ -564,6 +595,7 @@
mTaskViewTransitions.updateBoundsState(this, boundsOnScreen);
mTaskViewTransitions.updateVisibilityState(this, true /* visible */);
wct.setBounds(mTaskToken, boundsOnScreen);
+ applyCaptionInsetsIfNeeded();
} else {
// The surface has already been destroyed before the task has appeared,
// so go ahead and hide the task entirely
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index b217bd3..ce81910 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -145,7 +145,9 @@
mDisplay.getDisplayId(),
0 /* taskCornerRadius */,
mDecorationContainerSurface,
- mDragPositioningCallback);
+ mDragPositioningCallback,
+ mSurfaceControlBuilderSupplier,
+ mSurfaceControlTransactionSupplier);
}
final int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext())
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index bc89385..a359395 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -234,7 +234,9 @@
mDisplay.getDisplayId(),
mRelayoutParams.mCornerRadius,
mDecorationContainerSurface,
- mDragPositioningCallback);
+ mDragPositioningCallback,
+ mSurfaceControlBuilderSupplier,
+ mSurfaceControlTransactionSupplier);
}
final int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext())
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java
index 4e98f0c..941617d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java
@@ -22,7 +22,9 @@
* Callback called when receiving drag-resize or drag-move related input events.
*/
public interface DragPositioningCallback {
- @IntDef({CTRL_TYPE_UNDEFINED, CTRL_TYPE_LEFT, CTRL_TYPE_RIGHT, CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM})
+ @IntDef(flag = true, value = {
+ CTRL_TYPE_UNDEFINED, CTRL_TYPE_LEFT, CTRL_TYPE_RIGHT, CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM
+ })
@interface CtrlType {}
int CTRL_TYPE_UNDEFINED = 0;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index e5fc66a..336d95e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -18,8 +18,11 @@
import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
+import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_SPY;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM;
import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_LEFT;
@@ -48,6 +51,8 @@
import com.android.internal.view.BaseIWindow;
+import java.util.function.Supplier;
+
/**
* An input event listener registered to InputDispatcher to receive input events on task edges and
* and corners. Converts them to drag resize requests.
@@ -60,6 +65,7 @@
private final Handler mHandler;
private final Choreographer mChoreographer;
private final InputManager mInputManager;
+ private final Supplier<SurfaceControl.Transaction> mSurfaceControlTransactionSupplier;
private final int mDisplayId;
private final BaseIWindow mFakeWindow;
@@ -69,6 +75,10 @@
private final TaskResizeInputEventReceiver mInputEventReceiver;
private final DragPositioningCallback mCallback;
+ private final SurfaceControl mInputSinkSurface;
+ private final BaseIWindow mFakeSinkWindow;
+ private final InputChannel mSinkInputChannel;
+
private int mTaskWidth;
private int mTaskHeight;
private int mResizeHandleThickness;
@@ -90,15 +100,18 @@
int displayId,
int taskCornerRadius,
SurfaceControl decorationSurface,
- DragPositioningCallback callback) {
+ DragPositioningCallback callback,
+ Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier,
+ Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier) {
mInputManager = context.getSystemService(InputManager.class);
mHandler = handler;
mChoreographer = choreographer;
+ mSurfaceControlTransactionSupplier = surfaceControlTransactionSupplier;
mDisplayId = displayId;
mTaskCornerRadius = taskCornerRadius;
mDecorationSurface = decorationSurface;
- // Use a fake window as the backing surface is a container layer and we don't want to create
- // a buffer layer for it so we can't use ViewRootImpl.
+ // Use a fake window as the backing surface is a container layer, and we don't want to
+ // create a buffer layer for it, so we can't use ViewRootImpl.
mFakeWindow = new BaseIWindow();
mFakeWindow.setSession(mWindowSession);
mFocusGrantToken = new Binder();
@@ -111,7 +124,7 @@
null /* hostInputToken */,
FLAG_NOT_FOCUSABLE,
PRIVATE_FLAG_TRUSTED_OVERLAY,
- 0 /* inputFeatures */,
+ INPUT_FEATURE_SPY,
TYPE_APPLICATION,
null /* windowToken */,
mFocusGrantToken,
@@ -126,6 +139,35 @@
mCallback = callback;
mDragDetector = new DragDetector(mInputEventReceiver);
mDragDetector.setTouchSlop(ViewConfiguration.get(context).getScaledTouchSlop());
+
+ mInputSinkSurface = surfaceControlBuilderSupplier.get()
+ .setName("TaskInputSink of " + decorationSurface)
+ .setContainerLayer()
+ .setParent(mDecorationSurface)
+ .build();
+ mSurfaceControlTransactionSupplier.get()
+ .setLayer(mInputSinkSurface, WindowDecoration.INPUT_SINK_Z_ORDER)
+ .show(mInputSinkSurface)
+ .apply();
+ mFakeSinkWindow = new BaseIWindow();
+ mSinkInputChannel = new InputChannel();
+ try {
+ mWindowSession.grantInputChannel(
+ mDisplayId,
+ mInputSinkSurface,
+ mFakeSinkWindow,
+ null /* hostInputToken */,
+ FLAG_NOT_FOCUSABLE,
+ 0 /* privateFlags */,
+ INPUT_FEATURE_NO_INPUT_CHANNEL,
+ TYPE_INPUT_CONSUMER,
+ null /* windowToken */,
+ mFocusGrantToken,
+ "TaskInputSink of " + decorationSurface,
+ mSinkInputChannel);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
}
/**
@@ -219,7 +261,35 @@
mDecorationSurface,
FLAG_NOT_FOCUSABLE,
PRIVATE_FLAG_TRUSTED_OVERLAY,
- 0 /* inputFeatures */,
+ INPUT_FEATURE_SPY,
+ touchRegion);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+
+ mSurfaceControlTransactionSupplier.get()
+ .setWindowCrop(mInputSinkSurface, mTaskWidth, mTaskHeight)
+ .apply();
+ // The touch region of the TaskInputSink should be the touch region of this
+ // DragResizeInputHandler minus the task bounds. Pilfering events isn't enough to prevent
+ // input windows from handling down events, which will bring tasks in the back to front.
+ //
+ // Note not the entire touch region responds to both mouse and touchscreen events.
+ // Therefore, in the region that only responds to one of them, it would be a no-op to
+ // perform a gesture in the other type of events. We currently only have a mouse-only region
+ // out of the task bounds, and due to the roughness of touchscreen events, it's not a severe
+ // issue. However, were there touchscreen-only a region out of the task bounds, mouse
+ // gestures will become no-op in that region, even though the mouse gestures may appear to
+ // be performed on the input window behind the resize handle.
+ touchRegion.op(0, 0, mTaskWidth, mTaskHeight, Region.Op.DIFFERENCE);
+ try {
+ mWindowSession.updateInputChannel(
+ mSinkInputChannel.getToken(),
+ mDisplayId,
+ mInputSinkSurface,
+ FLAG_NOT_FOCUSABLE,
+ 0 /* privateFlags */,
+ INPUT_FEATURE_NO_INPUT_CHANNEL,
touchRegion);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
@@ -248,6 +318,16 @@
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
+
+ mSinkInputChannel.dispose();
+ try {
+ mWindowSession.remove(mFakeSinkWindow);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ mSurfaceControlTransactionSupplier.get()
+ .remove(mInputSinkSurface)
+ .apply();
}
private class TaskResizeInputEventReceiver extends InputEventReceiver
@@ -316,6 +396,8 @@
mShouldHandleEvents = isInResizeHandleBounds(x, y);
}
if (mShouldHandleEvents) {
+ mInputManager.pilferPointers(mInputChannel.getToken());
+
mDragPointerId = e.getPointerId(0);
float rawX = e.getRawX(0);
float rawY = e.getRawY(0);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
index 917abf5..e1b6db5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
@@ -63,8 +63,6 @@
mDragStartListener = dragStartListener;
mTransactionSupplier = supplier;
mDisallowedAreaForEndBoundsHeight = disallowedAreaForEndBoundsHeight;
- mDisplayController.getDisplayLayout(windowDecoration.mDisplay.getDisplayId())
- .getStableBounds(mStableBounds);
}
@Override
@@ -80,6 +78,10 @@
mTaskOrganizer.applyTransaction(wct);
}
mRepositionTaskBounds.set(mTaskBoundsAtDragStart);
+ if (mStableBounds.isEmpty()) {
+ mDisplayController.getDisplayLayout(mWindowDecoration.mDisplay.getDisplayId())
+ .getStableBounds(mStableBounds);
+ }
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
index bf3ff3f..ae3b5eb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
@@ -80,8 +80,6 @@
mTransactionSupplier = supplier;
mTransitions = transitions;
mDisallowedAreaForEndBoundsHeight = disallowedAreaForEndBoundsHeight;
- mDisplayController.getDisplayLayout(windowDecoration.mDisplay.getDisplayId())
- .getStableBounds(mStableBounds);
}
@Override
@@ -100,6 +98,10 @@
}
mDragStartListener.onDragStart(mDesktopWindowDecoration.mTaskInfo.taskId);
mRepositionTaskBounds.set(mTaskBoundsAtDragStart);
+ if (mStableBounds.isEmpty()) {
+ mDisplayController.getDisplayLayout(mDesktopWindowDecoration.mDisplay.getDisplayId())
+ .getStableBounds(mStableBounds);
+ }
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index ddc7fef..0b0d9d5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -64,6 +64,24 @@
implements AutoCloseable {
/**
+ * The Z-order of {@link #mCaptionContainerSurface}.
+ * <p>
+ * We use {@link #mDecorationContainerSurface} to define input window for task resizing; by
+ * layering it in front of {@link #mCaptionContainerSurface}, we can allow it to handle input
+ * prior to caption view itself, treating corner inputs as resize events rather than
+ * repositioning.
+ */
+ static final int CAPTION_LAYER_Z_ORDER = -1;
+ /**
+ * The Z-order of the task input sink in {@link DragPositioningCallback}.
+ * <p>
+ * This task input sink is used to prevent undesired dispatching of motion events out of task
+ * bounds; by layering it behind {@link #mCaptionContainerSurface}, we allow captions to handle
+ * input events first.
+ */
+ static final int INPUT_SINK_Z_ORDER = -2;
+
+ /**
* System-wide context. Only used to create context with overridden configurations.
*/
final Context mContext;
@@ -238,11 +256,8 @@
final int captionHeight = loadDimensionPixelSize(resources, params.mCaptionHeightId);
final int captionWidth = taskBounds.width();
- // We use mDecorationContainerSurface to define input window for task resizing; by layering
- // it in front of mCaptionContainerSurface, we can allow it to handle input prior to
- // caption view itself, treating corner inputs as resize events rather than repositioning.
startT.setWindowCrop(mCaptionContainerSurface, captionWidth, captionHeight)
- .setLayer(mCaptionContainerSurface, -1)
+ .setLayer(mCaptionContainerSurface, CAPTION_LAYER_Z_ORDER)
.show(mCaptionContainerSurface);
if (ViewRootImpl.CAPTION_ON_SHELL) {
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
index e382a0f..89747df 100644
--- a/libs/WindowManager/Shell/tests/flicker/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -30,19 +30,26 @@
filegroup {
name: "WMShellFlickerTestsBubbles-src",
- srcs: ["src/**/bubble/*.kt"],
+ srcs: ["src/com/android/wm/shell/flicker/bubble/*.kt"],
}
filegroup {
name: "WMShellFlickerTestsPip-src",
- srcs: ["src/**/pip/*.kt"],
+ srcs: ["src/com/android/wm/shell/flicker/pip/*.kt"],
}
filegroup {
name: "WMShellFlickerTestsSplitScreen-src",
srcs: [
- "src/**/splitscreen/*.kt",
- "src/**/splitscreen/benchmark/*.kt",
+ "src/com/android/wm/shell/flicker/splitscreen/*.kt",
+ "src/com/android/wm/shell/flicker/splitscreen/benchmark/*.kt",
+ ],
+}
+
+filegroup {
+ name: "WMShellFlickerServiceTests-src",
+ srcs: [
+ "src/com/android/wm/shell/flicker/service/**/*.kt",
],
}
@@ -88,6 +95,7 @@
":WMShellFlickerTestsBubbles-src",
":WMShellFlickerTestsPip-src",
":WMShellFlickerTestsSplitScreen-src",
+ ":WMShellFlickerServiceTests-src",
],
}
@@ -126,3 +134,15 @@
":WMShellFlickerTestsSplitScreen-src",
],
}
+
+android_test {
+ name: "WMShellFlickerServiceTests",
+ defaults: ["WMShellFlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestSplitScreen.xml"],
+ package_name: "com.android.wm.shell.flicker.service",
+ instrumentation_target_package: "com.android.wm.shell.flicker.service",
+ srcs: [
+ ":WMShellFlickerTestsBase-src",
+ ":WMShellFlickerServiceTests-src",
+ ],
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/SplitScreenUtils.kt
similarity index 98%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/SplitScreenUtils.kt
index 863cae3..fd56a6e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/SplitScreenUtils.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker.splitscreen
+package com.android.wm.shell.flicker
import android.app.Instrumentation
import android.graphics.Point
@@ -40,8 +40,6 @@
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
import com.android.server.wm.flicker.testapp.ActivityOptions.SplitScreen.Primary
-import com.android.wm.shell.flicker.LAUNCHER_UI_PACKAGE_NAME
-import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
import org.junit.Assert.assertNotNull
internal object SplitScreenUtils {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt
index 6fe88ca..d3f3c5b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt
@@ -18,10 +18,10 @@
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.RequiresDevice
-import android.tools.common.flicker.assertions.FlickerTest
import android.tools.common.NavBar
import android.tools.common.Rotation
import android.tools.common.datatypes.Rect
+import android.tools.common.flicker.assertions.FlickerTest
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
@@ -45,7 +45,6 @@
* Swipe right from the bottom of the screen to quick switch back to the app
* ```
*/
-
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@@ -152,9 +151,8 @@
@Test
fun appWindowBecomesAndStaysVisible() {
flicker.assertWm {
- this.isAppWindowInvisible(letterboxApp)
- .then()
- .isAppWindowVisible(letterboxApp) }
+ this.isAppWindowInvisible(letterboxApp).then().isAppWindowVisible(letterboxApp)
+ }
}
/**
@@ -245,7 +243,8 @@
.isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true)
.then()
.isVisible(letterboxApp)
- .isVisible(ComponentNameMatcher.LETTERBOX) }
+ .isVisible(ComponentNameMatcher.LETTERBOX)
+ }
}
/** {@inheritDoc} */
@@ -273,4 +272,4 @@
)
}
}
-}
\ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt
index 36bbafb..8bd44c3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt
@@ -16,12 +16,9 @@
package com.android.wm.shell.flicker.pip
-import android.app.Instrumentation
-import android.os.SystemClock
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.common.Rotation
-import android.tools.device.apphelpers.StandardAppHelper
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
@@ -29,13 +26,9 @@
import android.tools.device.helpers.WindowUtils
import android.tools.device.traces.parsers.toFlickerComponent
import androidx.test.filters.RequiresDevice
-import androidx.test.uiautomator.By
-import androidx.test.uiautomator.BySelector
-import androidx.test.uiautomator.UiObject2
-import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
-import com.android.wm.shell.flicker.LAUNCHER_UI_PACKAGE_NAME
+import com.android.wm.shell.flicker.SplitScreenUtils
import org.junit.Assume
import org.junit.FixMethodOrder
import org.junit.Test
@@ -73,8 +66,7 @@
AutoEnterPipOnGoToHomeTest(flicker) {
private val portraitDisplayBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
/** Second app used to enter split screen mode */
- protected val secondAppForSplitScreen = getSplitScreenApp(instrumentation)
- fun getSplitScreenApp(instrumentation: Instrumentation): StandardAppHelper =
+ private val secondAppForSplitScreen =
SimpleAppHelper(
instrumentation,
ActivityOptions.SplitScreen.Primary.LABEL,
@@ -88,14 +80,7 @@
secondAppForSplitScreen.launchViaIntent(wmHelper)
pipApp.launchViaIntent(wmHelper)
tapl.goHome()
- enterSplitScreen()
- // wait until split screen is established
- wmHelper
- .StateSyncBuilder()
- .withWindowSurfaceAppeared(pipApp)
- .withWindowSurfaceAppeared(secondAppForSplitScreen)
- .withSplitDividerVisible()
- .waitForAndVerify()
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, pipApp, secondAppForSplitScreen)
pipApp.enableAutoEnterForPipActivity()
}
teardown {
@@ -107,46 +92,6 @@
transitions { tapl.goHome() }
}
- // TODO(b/285400227) merge the code in a common utility - this is copied from SplitScreenUtils
- private val TIMEOUT_MS = 3_000L
- private val overviewSnapshotSelector: BySelector
- get() = By.res(LAUNCHER_UI_PACKAGE_NAME, "snapshot")
- private fun enterSplitScreen() {
- // Note: The initial split position in landscape is different between tablet and phone.
- // In landscape, tablet will let the first app split to right side, and phone will
- // split to left side.
- if (tapl.isTablet) {
- // TAPL's currentTask on tablet is sometimes not what we expected if the overview
- // contains more than 3 task views. We need to use uiautomator directly to find the
- // second task to split.
- tapl.workspace.switchToOverview().overviewActions.clickSplit()
- val snapshots =
- tapl.device.wait(Until.findObjects(overviewSnapshotSelector), TIMEOUT_MS)
- if (snapshots == null || snapshots.size < 1) {
- error("Fail to find a overview snapshot to split.")
- }
-
- // Find the second task in the upper right corner in split select mode by sorting
- // 'left' in descending order and 'top' in ascending order.
- snapshots.sortWith { t1: UiObject2, t2: UiObject2 ->
- t2.getVisibleBounds().left - t1.getVisibleBounds().left
- }
- snapshots.sortWith { t1: UiObject2, t2: UiObject2 ->
- t1.getVisibleBounds().top - t2.getVisibleBounds().top
- }
- snapshots[0].click()
- } else {
- tapl.workspace
- .switchToOverview()
- .currentTask
- .tapMenu()
- .tapSplitMenuItem()
- .currentTask
- .open()
- }
- SystemClock.sleep(TIMEOUT_MS)
- }
-
@Presubmit
@Test
override fun pipOverlayLayerAppearThenDisappear() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/SplitScreenUtils.kt
similarity index 96%
copy from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
copy to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/SplitScreenUtils.kt
index 863cae3..e640dc4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/SplitScreenUtils.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker.splitscreen
+package com.android.wm.shell.flicker.service.splitscreen
import android.app.Instrumentation
import android.graphics.Point
@@ -39,12 +39,11 @@
import com.android.server.wm.flicker.helpers.NotificationAppHelper
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
-import com.android.server.wm.flicker.testapp.ActivityOptions.SplitScreen.Primary
import com.android.wm.shell.flicker.LAUNCHER_UI_PACKAGE_NAME
import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
import org.junit.Assert.assertNotNull
-internal object SplitScreenUtils {
+object SplitScreenUtils {
private const val TIMEOUT_MS = 3_000L
private const val DRAG_DURATION_MS = 1_000L
private const val NOTIFICATION_SCROLLER = "notification_stack_scroller"
@@ -113,16 +112,6 @@
waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
}
- fun enterSplitViaIntent(
- wmHelper: WindowManagerStateHelper,
- primaryApp: StandardAppHelper,
- secondaryApp: StandardAppHelper
- ) {
- val stringExtras = mapOf(Primary.EXTRA_LAUNCH_ADJACENT to "true")
- primaryApp.launchViaIntent(wmHelper, null, null, stringExtras)
- waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
- }
-
fun splitFromOverview(tapl: LauncherInstrumentation, device: UiDevice) {
// Note: The initial split position in landscape is different between tablet and phone.
// In landscape, tablet will let the first app split to right side, and phone will
@@ -158,6 +147,17 @@
SystemClock.sleep(TIMEOUT_MS)
}
+ fun enterSplitViaIntent(
+ wmHelper: WindowManagerStateHelper,
+ primaryApp: StandardAppHelper,
+ secondaryApp: StandardAppHelper
+ ) {
+ val stringExtras =
+ mapOf(ActivityOptions.SplitScreen.Primary.EXTRA_LAUNCH_ADJACENT to "true")
+ primaryApp.launchViaIntent(wmHelper, null, null, stringExtras)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+
fun dragFromNotificationToSplit(
instrumentation: Instrumentation,
device: UiDevice,
@@ -325,14 +325,14 @@
dividerBar.drag(
Point(
if (dragToRight) {
- displayBounds.right
+ displayBounds.width * 4 / 5
} else {
- displayBounds.left
+ displayBounds.width * 1 / 5
},
if (dragToBottom) {
- displayBounds.bottom
+ displayBounds.height * 4 / 5
} else {
- displayBounds.top
+ displayBounds.height * 1 / 5
}
)
)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/CopyContentInSplitGesturalNavLandscapeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/CopyContentInSplitGesturalNavLandscapeBenchmark.kt
new file mode 100644
index 0000000..566adec
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/CopyContentInSplitGesturalNavLandscapeBenchmark.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit
+import org.junit.Test
+
+@RequiresDevice
+class CopyContentInSplitGesturalNavLandscapeBenchmark : CopyContentInSplit(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun copyContentInSplit() = super.copyContentInSplit()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/CopyContentInSplitGesturalNavPortraitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/CopyContentInSplitGesturalNavPortraitBenchmark.kt
new file mode 100644
index 0000000..92b6227
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/CopyContentInSplitGesturalNavPortraitBenchmark.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit
+import org.junit.Test
+
+@RequiresDevice
+class CopyContentInSplitGesturalNavPortraitBenchmark : CopyContentInSplit(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun copyContentInSplit() = super.copyContentInSplit()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/DismissSplitScreenByDividerGesturalNavLandscapeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/DismissSplitScreenByDividerGesturalNavLandscapeBenchmark.kt
new file mode 100644
index 0000000..e6d56b5
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/DismissSplitScreenByDividerGesturalNavLandscapeBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider
+import org.junit.Test
+
+@RequiresDevice
+class DismissSplitScreenByDividerGesturalNavLandscapeBenchmark :
+ DismissSplitScreenByDivider(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun dismissSplitScreenByDivider() = super.dismissSplitScreenByDivider()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/DismissSplitScreenByDividerGesturalNavPortraitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/DismissSplitScreenByDividerGesturalNavPortraitBenchmark.kt
new file mode 100644
index 0000000..6752c58
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/DismissSplitScreenByDividerGesturalNavPortraitBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider
+import org.junit.Test
+
+@RequiresDevice
+class DismissSplitScreenByDividerGesturalNavPortraitBenchmark :
+ DismissSplitScreenByDivider(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun dismissSplitScreenByDivider() = super.dismissSplitScreenByDivider()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/DismissSplitScreenByGoHomeGesturalNavLandscapeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/DismissSplitScreenByGoHomeGesturalNavLandscapeBenchmark.kt
new file mode 100644
index 0000000..7c9ab99
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/DismissSplitScreenByGoHomeGesturalNavLandscapeBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome
+import org.junit.Test
+
+@RequiresDevice
+class DismissSplitScreenByGoHomeGesturalNavLandscapeBenchmark :
+ DismissSplitScreenByGoHome(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun dismissSplitScreenByGoHome() = super.dismissSplitScreenByGoHome()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/DismissSplitScreenByGoHomeGesturalNavPortraitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/DismissSplitScreenByGoHomeGesturalNavPortraitBenchmark.kt
new file mode 100644
index 0000000..4b79571
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/DismissSplitScreenByGoHomeGesturalNavPortraitBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome
+import org.junit.Test
+
+@RequiresDevice
+class DismissSplitScreenByGoHomeGesturalNavPortraitBenchmark :
+ DismissSplitScreenByGoHome(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun dismissSplitScreenByGoHome() = super.dismissSplitScreenByGoHome()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/DragDividerToResizeGesturalNavLandscapeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/DragDividerToResizeGesturalNavLandscapeBenchmark.kt
new file mode 100644
index 0000000..0495079
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/DragDividerToResizeGesturalNavLandscapeBenchmark.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize
+import org.junit.Test
+
+@RequiresDevice
+class DragDividerToResizeGesturalNavLandscapeBenchmark : DragDividerToResize(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun dragDividerToResize() = super.dragDividerToResize()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/DragDividerToResizeGesturalNavPortraitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/DragDividerToResizeGesturalNavPortraitBenchmark.kt
new file mode 100644
index 0000000..71ef48b
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/DragDividerToResizeGesturalNavPortraitBenchmark.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize
+import org.junit.Test
+
+@RequiresDevice
+class DragDividerToResizeGesturalNavPortraitBenchmark : DragDividerToResize(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun dragDividerToResize() = super.dragDividerToResize()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsGesturalNavLandscapeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsGesturalNavLandscapeBenchmark.kt
new file mode 100644
index 0000000..c78729c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsGesturalNavLandscapeBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps
+import org.junit.Test
+
+@RequiresDevice
+class EnterSplitScreenByDragFromAllAppsGesturalNavLandscapeBenchmark :
+ EnterSplitScreenByDragFromAllApps(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenByDragFromAllApps() = super.enterSplitScreenByDragFromAllApps()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsGesturalNavPortraitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsGesturalNavPortraitBenchmark.kt
new file mode 100644
index 0000000..30bce2f6
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsGesturalNavPortraitBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps
+import org.junit.Test
+
+@RequiresDevice
+class EnterSplitScreenByDragFromAllAppsGesturalNavPortraitBenchmark :
+ EnterSplitScreenByDragFromAllApps(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenByDragFromAllApps() = super.enterSplitScreenByDragFromAllApps()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationGesturalNavLandscapeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationGesturalNavLandscapeBenchmark.kt
new file mode 100644
index 0000000..b33ea7c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationGesturalNavLandscapeBenchmark.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification
+import org.junit.Test
+
+@RequiresDevice
+class EnterSplitScreenByDragFromNotificationGesturalNavLandscapeBenchmark :
+ EnterSplitScreenByDragFromNotification(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenByDragFromNotification() =
+ super.enterSplitScreenByDragFromNotification()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationGesturalNavPortraitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationGesturalNavPortraitBenchmark.kt
new file mode 100644
index 0000000..07a86a5
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationGesturalNavPortraitBenchmark.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification
+import org.junit.Test
+
+@RequiresDevice
+class EnterSplitScreenByDragFromNotificationGesturalNavPortraitBenchmark :
+ EnterSplitScreenByDragFromNotification(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenByDragFromNotification() =
+ super.enterSplitScreenByDragFromNotification()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutGesturalNavLandscapeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutGesturalNavLandscapeBenchmark.kt
new file mode 100644
index 0000000..9a1d127
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutGesturalNavLandscapeBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut
+import org.junit.Test
+
+@RequiresDevice
+class EnterSplitScreenByDragFromShortcutGesturalNavLandscapeBenchmark :
+ EnterSplitScreenByDragFromShortcut(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenByDragFromShortcut() = super.enterSplitScreenByDragFromShortcut()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutGesturalNavPortraitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutGesturalNavPortraitBenchmark.kt
new file mode 100644
index 0000000..266e268
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutGesturalNavPortraitBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut
+import org.junit.Test
+
+@RequiresDevice
+class EnterSplitScreenByDragFromShortcutGesturalNavPortraitBenchmark :
+ EnterSplitScreenByDragFromShortcut(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenByDragFromShortcut() = super.enterSplitScreenByDragFromShortcut()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarGesturalNavLandscapeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarGesturalNavLandscapeBenchmark.kt
new file mode 100644
index 0000000..83fc30b
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarGesturalNavLandscapeBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar
+import org.junit.Test
+
+@RequiresDevice
+class EnterSplitScreenByDragFromTaskbarGesturalNavLandscapeBenchmark :
+ EnterSplitScreenByDragFromTaskbar(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenByDragFromTaskbar() = super.enterSplitScreenByDragFromTaskbar()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarGesturalNavPortraitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarGesturalNavPortraitBenchmark.kt
new file mode 100644
index 0000000..b2f1929
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarGesturalNavPortraitBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar
+import org.junit.Test
+
+@RequiresDevice
+class EnterSplitScreenByDragFromTaskbarGesturalNavPortraitBenchmark :
+ EnterSplitScreenByDragFromTaskbar(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenByDragFromTaskbar() = super.enterSplitScreenByDragFromTaskbar()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenFromOverviewGesturalNavLandscapeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenFromOverviewGesturalNavLandscapeBenchmark.kt
new file mode 100644
index 0000000..dae92dd
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenFromOverviewGesturalNavLandscapeBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview
+import org.junit.Test
+
+@RequiresDevice
+class EnterSplitScreenFromOverviewGesturalNavLandscapeBenchmark :
+ EnterSplitScreenFromOverview(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenFromOverview() = super.enterSplitScreenFromOverview()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenFromOverviewGesturalNavPortraitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenFromOverviewGesturalNavPortraitBenchmark.kt
new file mode 100644
index 0000000..732047b
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/EnterSplitScreenFromOverviewGesturalNavPortraitBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview
+import org.junit.Test
+
+@RequiresDevice
+class EnterSplitScreenFromOverviewGesturalNavPortraitBenchmark :
+ EnterSplitScreenFromOverview(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun enterSplitScreenFromOverview() = super.enterSplitScreenFromOverview()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchAppByDoubleTapDividerGesturalNavLandscapeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchAppByDoubleTapDividerGesturalNavLandscapeBenchmark.kt
new file mode 100644
index 0000000..1de7efd
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchAppByDoubleTapDividerGesturalNavLandscapeBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider
+import org.junit.Test
+
+@RequiresDevice
+class SwitchAppByDoubleTapDividerGesturalNavLandscapeBenchmark :
+ SwitchAppByDoubleTapDivider(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchAppByDoubleTapDivider() = super.switchAppByDoubleTapDivider()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchAppByDoubleTapDividerGesturalNavPortraitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchAppByDoubleTapDividerGesturalNavPortraitBenchmark.kt
new file mode 100644
index 0000000..1a046aa
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchAppByDoubleTapDividerGesturalNavPortraitBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider
+import org.junit.Test
+
+@RequiresDevice
+class SwitchAppByDoubleTapDividerGesturalNavPortraitBenchmark :
+ SwitchAppByDoubleTapDivider(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchAppByDoubleTapDivider() = super.switchAppByDoubleTapDivider()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppGesturalNavLandscapeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppGesturalNavLandscapeBenchmark.kt
new file mode 100644
index 0000000..6e88f0e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppGesturalNavLandscapeBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp
+import org.junit.Test
+
+@RequiresDevice
+class SwitchBackToSplitFromAnotherAppGesturalNavLandscapeBenchmark :
+ SwitchBackToSplitFromAnotherApp(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchBackToSplitFromAnotherApp() = super.switchBackToSplitFromAnotherApp()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppGesturalNavPortraitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppGesturalNavPortraitBenchmark.kt
new file mode 100644
index 0000000..d26a29c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppGesturalNavPortraitBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp
+import org.junit.Test
+
+@RequiresDevice
+class SwitchBackToSplitFromAnotherAppGesturalNavPortraitBenchmark :
+ SwitchBackToSplitFromAnotherApp(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchBackToSplitFromAnotherApp() = super.switchBackToSplitFromAnotherApp()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBackToSplitFromHomeGesturalNavLandscapeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBackToSplitFromHomeGesturalNavLandscapeBenchmark.kt
new file mode 100644
index 0000000..4a552b0
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBackToSplitFromHomeGesturalNavLandscapeBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome
+import org.junit.Test
+
+@RequiresDevice
+class SwitchBackToSplitFromHomeGesturalNavLandscapeBenchmark :
+ SwitchBackToSplitFromHome(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchBackToSplitFromHome() = super.switchBackToSplitFromHome()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBackToSplitFromHomeGesturalNavPortraitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBackToSplitFromHomeGesturalNavPortraitBenchmark.kt
new file mode 100644
index 0000000..b7376ea
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBackToSplitFromHomeGesturalNavPortraitBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome
+import org.junit.Test
+
+@RequiresDevice
+class SwitchBackToSplitFromHomeGesturalNavPortraitBenchmark :
+ SwitchBackToSplitFromHome(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchBackToSplitFromHome() = super.switchBackToSplitFromHome()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBackToSplitFromRecentGesturalNavLandscapeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBackToSplitFromRecentGesturalNavLandscapeBenchmark.kt
new file mode 100644
index 0000000..b2d05e4
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBackToSplitFromRecentGesturalNavLandscapeBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent
+import org.junit.Test
+
+@RequiresDevice
+class SwitchBackToSplitFromRecentGesturalNavLandscapeBenchmark :
+ SwitchBackToSplitFromRecent(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchBackToSplitFromRecent() = super.switchBackToSplitFromRecent()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBackToSplitFromRecentGesturalNavPortraitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBackToSplitFromRecentGesturalNavPortraitBenchmark.kt
new file mode 100644
index 0000000..6de31b1
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBackToSplitFromRecentGesturalNavPortraitBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent
+import org.junit.Test
+
+@RequiresDevice
+class SwitchBackToSplitFromRecentGesturalNavPortraitBenchmark :
+ SwitchBackToSplitFromRecent(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchBackToSplitFromRecent() = super.switchBackToSplitFromRecent()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBetweenSplitPairsGesturalNavLandscapeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBetweenSplitPairsGesturalNavLandscapeBenchmark.kt
new file mode 100644
index 0000000..aab18a6
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBetweenSplitPairsGesturalNavLandscapeBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs
+import org.junit.Test
+
+@RequiresDevice
+class SwitchBetweenSplitPairsGesturalNavLandscapeBenchmark :
+ SwitchBetweenSplitPairs(Rotation.ROTATION_90) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchBetweenSplitPairs() = super.switchBetweenSplitPairs()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBetweenSplitPairsGesturalNavPortraitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBetweenSplitPairsGesturalNavPortraitBenchmark.kt
new file mode 100644
index 0000000..b074f2c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/SwitchBetweenSplitPairsGesturalNavPortraitBenchmark.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs
+import org.junit.Test
+
+@RequiresDevice
+class SwitchBetweenSplitPairsGesturalNavPortraitBenchmark :
+ SwitchBetweenSplitPairs(Rotation.ROTATION_0) {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun switchBetweenSplitPairs() = super.switchBetweenSplitPairs()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/UnlockKeyguardToSplitScreenGesturalNavLandscapeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/UnlockKeyguardToSplitScreenGesturalNavLandscapeBenchmark.kt
new file mode 100644
index 0000000..c402aa4
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/UnlockKeyguardToSplitScreenGesturalNavLandscapeBenchmark.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.UnlockKeyguardToSplitScreen
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+@RequiresDevice
+@RunWith(BlockJUnit4ClassRunner::class)
+class UnlockKeyguardToSplitScreenGesturalNavLandscapeBenchmark : UnlockKeyguardToSplitScreen() {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun unlockKeyguardToSplitScreen() = super.unlockKeyguardToSplitScreen()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/UnlockKeyguardToSplitScreenGesturalNavPortraitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/UnlockKeyguardToSplitScreenGesturalNavPortraitBenchmark.kt
new file mode 100644
index 0000000..840401c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/benchmark/UnlockKeyguardToSplitScreenGesturalNavPortraitBenchmark.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.benchmark
+
+import android.platform.test.annotations.PlatinumTest
+import android.platform.test.annotations.Presubmit
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.UnlockKeyguardToSplitScreen
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+@RequiresDevice
+@RunWith(BlockJUnit4ClassRunner::class)
+class UnlockKeyguardToSplitScreenGesturalNavPortraitBenchmark : UnlockKeyguardToSplitScreen() {
+ @PlatinumTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ override fun unlockKeyguardToSplitScreen() = super.unlockKeyguardToSplitScreen()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt
new file mode 100644
index 0000000..a5c5122
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class CopyContentInSplitGesturalNavLandscape : CopyContentInSplit(Rotation.ROTATION_90) {
+ @ExpectedScenarios([]) @Test override fun copyContentInSplit() = super.copyContentInSplit()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt
new file mode 100644
index 0000000..092fb67
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class CopyContentInSplitGesturalNavPortrait : CopyContentInSplit(Rotation.ROTATION_0) {
+ @ExpectedScenarios([]) @Test override fun copyContentInSplit() = super.copyContentInSplit()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt
new file mode 100644
index 0000000..8cb25fe
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class DismissSplitScreenByDividerGesturalNavLandscape :
+ DismissSplitScreenByDivider(Rotation.ROTATION_90) {
+
+ @ExpectedScenarios(["SPLIT_SCREEN_EXIT"])
+ @Test
+ override fun dismissSplitScreenByDivider() = super.dismissSplitScreenByDivider()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt
new file mode 100644
index 0000000..fa1be63
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class DismissSplitScreenByDividerGesturalNavPortrait :
+ DismissSplitScreenByDivider(Rotation.ROTATION_0) {
+
+ @ExpectedScenarios(["SPLIT_SCREEN_EXIT"])
+ @Test
+ override fun dismissSplitScreenByDivider() = super.dismissSplitScreenByDivider()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
new file mode 100644
index 0000000..aa35237
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class DismissSplitScreenByGoHomeGesturalNavLandscape :
+ DismissSplitScreenByGoHome(Rotation.ROTATION_90) {
+
+ @ExpectedScenarios(["SPLIT_SCREEN_EXIT"])
+ @Test
+ override fun dismissSplitScreenByGoHome() = super.dismissSplitScreenByGoHome()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
new file mode 100644
index 0000000..e195360
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class DismissSplitScreenByGoHomeGesturalNavPortrait :
+ DismissSplitScreenByGoHome(Rotation.ROTATION_0) {
+
+ @ExpectedScenarios(["SPLIT_SCREEN_EXIT"])
+ @Test
+ override fun dismissSplitScreenByGoHome() = super.dismissSplitScreenByGoHome()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt
new file mode 100644
index 0000000..c1b3aad
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class DragDividerToResizeGesturalNavLandscape : DragDividerToResize(Rotation.ROTATION_90) {
+
+ @ExpectedScenarios(["SPLIT_SCREEN_RESIZE"])
+ @Test
+ override fun dragDividerToResize() = super.dragDividerToResize()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt
new file mode 100644
index 0000000..c6e2e85
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class DragDividerToResizeGesturalNavPortrait : DragDividerToResize(Rotation.ROTATION_0) {
+
+ @ExpectedScenarios(["SPLIT_SCREEN_RESIZE"])
+ @Test
+ override fun dragDividerToResize() = super.dragDividerToResize()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
new file mode 100644
index 0000000..5f771c7
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenByDragFromAllAppsGesturalNavLandscape :
+ EnterSplitScreenByDragFromAllApps(Rotation.ROTATION_90) {
+
+ @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+ @Test
+ override fun enterSplitScreenByDragFromAllApps() = super.enterSplitScreenByDragFromAllApps()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
new file mode 100644
index 0000000..729a401
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenByDragFromAllAppsGesturalNavPortrait :
+ EnterSplitScreenByDragFromAllApps(Rotation.ROTATION_0) {
+
+ @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+ @Test
+ override fun enterSplitScreenByDragFromAllApps() = super.enterSplitScreenByDragFromAllApps()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
new file mode 100644
index 0000000..6e4cf9f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenByDragFromNotificationGesturalNavLandscape :
+ EnterSplitScreenByDragFromNotification(Rotation.ROTATION_90) {
+
+ @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+ @Test
+ override fun enterSplitScreenByDragFromNotification() =
+ super.enterSplitScreenByDragFromNotification()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
new file mode 100644
index 0000000..cc28702
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenByDragFromNotificationGesturalNavPortrait :
+ EnterSplitScreenByDragFromNotification(Rotation.ROTATION_0) {
+
+ @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+ @Test
+ override fun enterSplitScreenByDragFromNotification() =
+ super.enterSplitScreenByDragFromNotification()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
new file mode 100644
index 0000000..736604f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenByDragFromShortcutGesturalNavLandscape :
+ EnterSplitScreenByDragFromShortcut(Rotation.ROTATION_90) {
+
+ @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+ @Test
+ override fun enterSplitScreenByDragFromShortcut() = super.enterSplitScreenByDragFromShortcut()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
new file mode 100644
index 0000000..8df8dfa
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenByDragFromShortcutGesturalNavPortrait :
+ EnterSplitScreenByDragFromShortcut(Rotation.ROTATION_0) {
+
+ @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+ @Test
+ override fun enterSplitScreenByDragFromShortcut() = super.enterSplitScreenByDragFromShortcut()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
new file mode 100644
index 0000000..378f055
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenByDragFromTaskbarGesturalNavLandscape :
+ EnterSplitScreenByDragFromTaskbar(Rotation.ROTATION_90) {
+
+ @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+ @Test
+ override fun enterSplitScreenByDragFromTaskbar() = super.enterSplitScreenByDragFromTaskbar()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
new file mode 100644
index 0000000..b33d262
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenByDragFromTaskbarGesturalNavPortrait :
+ EnterSplitScreenByDragFromTaskbar(Rotation.ROTATION_0) {
+
+ @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+ @Test
+ override fun enterSplitScreenByDragFromTaskbar() = super.enterSplitScreenByDragFromTaskbar()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
new file mode 100644
index 0000000..b1d3858
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenFromOverviewGesturalNavLandscape :
+ EnterSplitScreenFromOverview(Rotation.ROTATION_90) {
+
+ @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+ @Test
+ override fun enterSplitScreenFromOverview() = super.enterSplitScreenFromOverview()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
new file mode 100644
index 0000000..6d824c7
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenFromOverviewGesturalNavPortrait :
+ EnterSplitScreenFromOverview(Rotation.ROTATION_0) {
+
+ @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+ @Test
+ override fun enterSplitScreenFromOverview() = super.enterSplitScreenFromOverview()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
new file mode 100644
index 0000000..f1d3d0c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchAppByDoubleTapDividerGesturalNavLandscape :
+ SwitchAppByDoubleTapDivider(Rotation.ROTATION_90) {
+
+ @ExpectedScenarios([])
+ @Test
+ override fun switchAppByDoubleTapDivider() = super.switchAppByDoubleTapDivider()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
new file mode 100644
index 0000000..a867bac
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchAppByDoubleTapDividerGesturalNavPortrait :
+ SwitchAppByDoubleTapDivider(Rotation.ROTATION_0) {
+
+ @ExpectedScenarios([])
+ @Test
+ override fun switchAppByDoubleTapDivider() = super.switchAppByDoubleTapDivider()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
new file mode 100644
index 0000000..76247ba
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchBackToSplitFromAnotherAppGesturalNavLandscape :
+ SwitchBackToSplitFromAnotherApp(Rotation.ROTATION_90) {
+
+ @ExpectedScenarios(["QUICKSWITCH"])
+ @Test
+ override fun switchBackToSplitFromAnotherApp() = super.switchBackToSplitFromAnotherApp()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
new file mode 100644
index 0000000..e179da8
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchBackToSplitFromAnotherAppGesturalNavPortrait :
+ SwitchBackToSplitFromAnotherApp(Rotation.ROTATION_0) {
+
+ @ExpectedScenarios(["QUICKSWITCH"])
+ @Test
+ override fun switchBackToSplitFromAnotherApp() = super.switchBackToSplitFromAnotherApp()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
new file mode 100644
index 0000000..20f554f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchBackToSplitFromHomeGesturalNavLandscape :
+ SwitchBackToSplitFromHome(Rotation.ROTATION_90) {
+
+ @ExpectedScenarios(["QUICKSWITCH"])
+ @Test
+ override fun switchBackToSplitFromHome() = super.switchBackToSplitFromHome()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
new file mode 100644
index 0000000..f7776ee
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchBackToSplitFromHomeGesturalNavPortrait :
+ SwitchBackToSplitFromHome(Rotation.ROTATION_0) {
+
+ @ExpectedScenarios(["QUICKSWITCH"])
+ @Test
+ override fun switchBackToSplitFromHome() = super.switchBackToSplitFromHome()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
new file mode 100644
index 0000000..00f6073
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchBackToSplitFromRecentGesturalNavLandscape :
+ SwitchBackToSplitFromRecent(Rotation.ROTATION_90) {
+
+ @ExpectedScenarios(["QUICKSWITCH"])
+ @Test
+ override fun switchBackToSplitFromRecent() = super.switchBackToSplitFromRecent()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
new file mode 100644
index 0000000..b3340e7
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchBackToSplitFromRecentGesturalNavPortrait :
+ SwitchBackToSplitFromRecent(Rotation.ROTATION_0) {
+
+ @ExpectedScenarios(["QUICKSWITCH"])
+ @Test
+ override fun switchBackToSplitFromRecent() = super.switchBackToSplitFromRecent()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt
new file mode 100644
index 0000000..3da61e5
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchBetweenSplitPairsGesturalNavLandscape : SwitchBetweenSplitPairs(Rotation.ROTATION_90) {
+
+ @ExpectedScenarios(["QUICKSWITCH"])
+ @Test
+ override fun switchBetweenSplitPairs() = super.switchBetweenSplitPairs()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt
new file mode 100644
index 0000000..627ae18
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchBetweenSplitPairsGesturalNavPortrait : SwitchBetweenSplitPairs(Rotation.ROTATION_0) {
+
+ @ExpectedScenarios(["QUICKSWITCH"])
+ @Test
+ override fun switchBetweenSplitPairs() = super.switchBetweenSplitPairs()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
new file mode 100644
index 0000000..7cbc1c3
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.UnlockKeyguardToSplitScreen
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class UnlockKeyguardToSplitScreenGesturalNavLandscape : UnlockKeyguardToSplitScreen() {
+
+ @ExpectedScenarios(["QUICKSWITCH"])
+ @Test
+ override fun unlockKeyguardToSplitScreen() = super.unlockKeyguardToSplitScreen()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
new file mode 100644
index 0000000..2eb81e0
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.UnlockKeyguardToSplitScreen
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class UnlockKeyguardToSplitScreenGesturalNavPortrait : UnlockKeyguardToSplitScreen() {
+
+ @ExpectedScenarios(["QUICKSWITCH"])
+ @Test
+ override fun unlockKeyguardToSplitScreen() = super.unlockKeyguardToSplitScreen()
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
index a43ad9b..1d4c4d2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.common.traces.component.EdgeExtensionComponentMatcher
@@ -28,13 +27,9 @@
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
-import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
import com.android.wm.shell.flicker.appWindowKeepVisible
import com.android.wm.shell.flicker.layerKeepVisible
import com.android.wm.shell.flicker.splitAppLayerBoundsKeepVisible
-import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtStart
import com.android.wm.shell.flicker.splitscreen.benchmark.CopyContentInSplitBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
@@ -60,21 +55,6 @@
thisTransition(this)
}
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- override fun cujCompleted() {
- flicker.appWindowIsVisibleAtStart(primaryApp)
- flicker.appWindowIsVisibleAtStart(textEditApp)
- flicker.splitScreenDividerIsVisibleAtStart()
-
- flicker.appWindowIsVisibleAtEnd(primaryApp)
- flicker.appWindowIsVisibleAtEnd(textEditApp)
- flicker.splitScreenDividerIsVisibleAtEnd()
-
- // The validation of copied text is already done in SplitScreenUtils.copyContentInSplit()
- }
-
@Presubmit
@Test
fun splitScreenDividerKeepVisible() = flicker.layerKeepVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
index a118c08..0d967eb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
@@ -26,13 +25,9 @@
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
-import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
import com.android.wm.shell.flicker.appWindowKeepVisible
import com.android.wm.shell.flicker.layerKeepVisible
import com.android.wm.shell.flicker.splitAppLayerBoundsChanges
-import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtStart
import com.android.wm.shell.flicker.splitscreen.benchmark.DragDividerToResizeBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
@@ -58,19 +53,6 @@
thisTransition(this)
}
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- override fun cujCompleted() {
- flicker.appWindowIsVisibleAtStart(primaryApp)
- flicker.appWindowIsVisibleAtStart(secondaryApp)
- flicker.splitScreenDividerIsVisibleAtStart()
-
- flicker.appWindowIsVisibleAtEnd(primaryApp)
- flicker.appWindowIsVisibleAtEnd(secondaryApp)
- flicker.splitScreenDividerIsVisibleAtEnd()
- }
-
@Presubmit
@Test
fun splitScreenDividerKeepVisible() = flicker.layerKeepVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
index 580b153..d3434a5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
@@ -21,6 +21,7 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import com.android.server.wm.flicker.helpers.setRotation
import com.android.wm.shell.flicker.BaseBenchmarkTest
+import com.android.wm.shell.flicker.SplitScreenUtils
abstract class SplitScreenBase(flicker: LegacyFlickerTest) : BaseBenchmarkTest(flicker) {
protected val context: Context = instrumentation.context
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
index e0a47b3..f236c2d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.splitscreen
-import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
@@ -28,12 +27,9 @@
import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
-import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
import com.android.wm.shell.flicker.layerIsVisibleAtEnd
import com.android.wm.shell.flicker.layerKeepVisible
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtStart
import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchAppByDoubleTapDividerBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
@@ -59,19 +55,6 @@
thisTransition(this)
}
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- override fun cujCompleted() {
- flicker.appWindowIsVisibleAtStart(primaryApp)
- flicker.appWindowIsVisibleAtStart(secondaryApp)
- flicker.splitScreenDividerIsVisibleAtStart()
-
- flicker.appWindowIsVisibleAtEnd(primaryApp)
- flicker.appWindowIsVisibleAtEnd(secondaryApp)
- flicker.splitScreenDividerIsVisibleAtEnd()
- }
-
@Presubmit
@Test
fun splitScreenDividerKeepVisible() = flicker.layerKeepVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
index 8f867df..8aaa98a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
@@ -28,15 +27,10 @@
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.appWindowBecomesInvisible
import com.android.wm.shell.flicker.appWindowBecomesVisible
-import com.android.wm.shell.flicker.appWindowIsInvisibleAtEnd
-import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
-import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
import com.android.wm.shell.flicker.layerBecomesInvisible
import com.android.wm.shell.flicker.layerBecomesVisible
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitAppLayerBoundsSnapToDivider
-import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtStart
import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBetweenSplitPairsBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
@@ -62,21 +56,6 @@
thisTransition(this)
}
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- override fun cujCompleted() {
- flicker.appWindowIsVisibleAtStart(thirdApp)
- flicker.appWindowIsVisibleAtStart(fourthApp)
- flicker.splitScreenDividerIsVisibleAtStart()
-
- flicker.appWindowIsVisibleAtEnd(primaryApp)
- flicker.appWindowIsVisibleAtEnd(secondaryApp)
- flicker.appWindowIsInvisibleAtEnd(thirdApp)
- flicker.appWindowIsInvisibleAtEnd(fourthApp)
- flicker.splitScreenDividerIsVisibleAtEnd()
- }
-
@Presubmit
@Test
fun splitScreenDividerInvisibleAtMiddle() =
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt
index d1ca9ea..d9d22de 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt
@@ -16,18 +16,15 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.SplitScreenUtils
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -36,7 +33,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CopyContentInSplitBenchmark(override val flicker: LegacyFlickerTest) :
+abstract class CopyContentInSplitBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val textEditApp = SplitScreenUtils.getIme(instrumentation)
protected val magnifierLayer = ComponentNameMatcher("", "magnifier surface bbq wrapper#")
@@ -54,21 +51,6 @@
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- open fun cujCompleted() {
- // The validation of copied text is already done in SplitScreenUtils.copyContentInSplit()
- }
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt
index 73acb1f..7e8d60b4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt
@@ -16,18 +16,14 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenDismissed
+import com.android.wm.shell.flicker.SplitScreenUtils
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -36,7 +32,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class DismissSplitScreenByDividerBenchmark(override val flicker: LegacyFlickerTest) :
+abstract class DismissSplitScreenByDividerBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -61,19 +57,6 @@
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenDismissed(primaryApp, secondaryApp, toHome = false)
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt
index 86ffd2a..770e032 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt
@@ -16,18 +16,14 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenDismissed
+import com.android.wm.shell.flicker.SplitScreenUtils
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -36,7 +32,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class DismissSplitScreenByGoHomeBenchmark(override val flicker: LegacyFlickerTest) :
+abstract class DismissSplitScreenByGoHomeBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -47,19 +43,6 @@
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenDismissed(primaryApp, secondaryApp, toHome = true)
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt
index dfde3b6..46570fd 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt
@@ -16,19 +16,16 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.SplitScreenUtils
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
import org.junit.Assume
import org.junit.Before
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -37,7 +34,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class DragDividerToResizeBenchmark(override val flicker: LegacyFlickerTest) :
+abstract class DragDividerToResizeBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -45,27 +42,11 @@
transitions { SplitScreenUtils.dragDividerToResizeAndWait(device, wmHelper) }
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
@Before
fun before() {
Assume.assumeTrue(tapl.isTablet || !flicker.scenario.isLandscapeOrSeascapeAtStart)
}
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- open fun cujCompleted() {
- // TODO(b/246490534): Add validation for resized app after withAppTransitionIdle is
- // robust enough to get the correct end state.
- }
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
index d13e413..5c3d4ff 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
@@ -16,21 +16,17 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.SplitScreenUtils
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
import org.junit.Assume
import org.junit.Before
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -39,7 +35,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterSplitScreenByDragFromAllAppsBenchmark(override val flicker: LegacyFlickerTest) :
+abstract class EnterSplitScreenByDragFromAllAppsBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
@@ -57,30 +53,11 @@
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
@Before
fun before() {
Assume.assumeTrue(tapl.isTablet)
}
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() =
- flicker.splitScreenEntered(
- primaryApp,
- secondaryApp,
- fromOtherApp = false,
- appExistAtStart = false
- )
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt
index 1d41669..6b122c6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt
@@ -16,21 +16,17 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.SplitScreenUtils
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
import org.junit.Assume
import org.junit.Before
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -39,7 +35,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterSplitScreenByDragFromNotificationBenchmark(
+abstract class EnterSplitScreenByDragFromNotificationBenchmark(
override val flicker: LegacyFlickerTest
) : SplitScreenBase(flicker) {
protected val sendNotificationApp = SplitScreenUtils.getSendNotification(instrumentation)
@@ -59,21 +55,6 @@
teardown { sendNotificationApp.exit(wmHelper) }
}
- /** {@inheritDoc} */
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() =
- flicker.splitScreenEntered(primaryApp, sendNotificationApp, fromOtherApp = false)
-
@Before
fun before() {
Assume.assumeTrue(tapl.isTablet)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
index b4bafa7..78f9bab 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
@@ -16,21 +16,17 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.SplitScreenUtils
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
import org.junit.Assume
import org.junit.Before
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -39,8 +35,9 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterSplitScreenByDragFromShortcutBenchmark(override val flicker: LegacyFlickerTest) :
- SplitScreenBase(flicker) {
+abstract class EnterSplitScreenByDragFromShortcutBenchmark(
+ override val flicker: LegacyFlickerTest
+) : SplitScreenBase(flicker) {
@Before
fun before() {
Assume.assumeTrue(tapl.isTablet)
@@ -62,25 +59,6 @@
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() =
- flicker.splitScreenEntered(
- primaryApp,
- secondaryApp,
- fromOtherApp = false,
- appExistAtStart = false
- )
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
index da44ecd..78907f0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
@@ -16,21 +16,17 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.SplitScreenUtils
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
import org.junit.Assume
import org.junit.Before
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -39,7 +35,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterSplitScreenByDragFromTaskbarBenchmark(override val flicker: LegacyFlickerTest) :
+abstract class EnterSplitScreenByDragFromTaskbarBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -56,26 +52,6 @@
}
}
- /** {@inheritDoc} */
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() =
- flicker.splitScreenEntered(
- primaryApp,
- secondaryApp,
- fromOtherApp = false,
- appExistAtStart = false
- )
-
@Before
fun before() {
Assume.assumeTrue(tapl.isTablet)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt
index af06d6d..2c91e84 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt
@@ -16,18 +16,14 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.SplitScreenUtils
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -36,7 +32,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterSplitScreenFromOverviewBenchmark(override val flicker: LegacyFlickerTest) :
+abstract class EnterSplitScreenFromOverviewBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -56,19 +52,6 @@
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
index 23156b5..fa09c2e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
@@ -16,8 +16,6 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
@@ -27,10 +25,9 @@
import android.tools.device.helpers.WindowUtils
import android.tools.device.traces.parsers.WindowManagerStateHelper
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.SplitScreenUtils
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -39,7 +36,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SwitchAppByDoubleTapDividerBenchmark(override val flicker: LegacyFlickerTest) :
+abstract class SwitchAppByDoubleTapDividerBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -53,14 +50,6 @@
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
private fun waitForWindowsToSwitch(wmHelper: WindowManagerStateHelper) {
wmHelper
.StateSyncBuilder()
@@ -134,14 +123,6 @@
return displayBounds.width > displayBounds.height
}
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- open fun cujCompleted() {
- // TODO(b/246490534): Add validation for switched app after withAppTransitionIdle is
- // robust enough to get the correct end state.
- }
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt
index 2d810d3..ff22006 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt
@@ -16,19 +16,15 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.SplitScreenUtils
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -37,7 +33,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SwitchBackToSplitFromAnotherAppBenchmark(override val flicker: LegacyFlickerTest) :
+abstract class SwitchBackToSplitFromAnotherAppBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
private val thirdApp = SplitScreenUtils.getNonResizeable(instrumentation)
@@ -55,19 +51,6 @@
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt
index f6df1e4..5787b02 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt
@@ -16,19 +16,15 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.SplitScreenUtils
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -37,7 +33,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SwitchBackToSplitFromHomeBenchmark(override val flicker: LegacyFlickerTest) :
+abstract class SwitchBackToSplitFromHomeBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -53,19 +49,6 @@
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt
index ba46bdc..b2d5091 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt
@@ -16,19 +16,15 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.SplitScreenUtils
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -37,7 +33,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SwitchBackToSplitFromRecentBenchmark(override val flicker: LegacyFlickerTest) :
+abstract class SwitchBackToSplitFromRecentBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -53,19 +49,6 @@
}
}
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- withoutTracing(this)
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
- @PlatinumTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt
index 4197550..f234e46 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt
@@ -16,17 +16,14 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.PlatinumTest
-import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.SplitScreenUtils
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -35,7 +32,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SwitchBetweenSplitPairsBenchmark(override val flicker: LegacyFlickerTest) :
+abstract class SwitchBetweenSplitPairsBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thirdApp = SplitScreenUtils.getIme(instrumentation)
protected val fourthApp = SplitScreenUtils.getSendNotification(instrumentation)
@@ -64,8 +61,6 @@
thisTransition(this)
}
- @PlatinumTest(focusArea = "sysui") @Presubmit @Test open fun cujCompleted() {}
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt
index 7952b71..61c3679 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt
@@ -22,8 +22,8 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.SplitScreenUtils
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
-import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -33,7 +33,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class UnlockKeyguardToSplitScreenBenchmark(override val flicker: LegacyFlickerTest) :
+abstract class UnlockKeyguardToSplitScreenBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -47,14 +47,6 @@
}
}
- /** {@inheritDoc} */
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- defaultSetup(this)
- defaultTeardown(this)
- thisTransition(this)
- }
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
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 df1e2e1..946a7ef 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
@@ -161,7 +161,7 @@
childTask.supportsMultiWindow = false;
mStageTaskListener.onTaskInfoChanged(childTask);
- verify(mCallbacks).onNoLongerSupportMultiWindow();
+ verify(mCallbacks).onNoLongerSupportMultiWindow(childTask);
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java
index 1b38956..50435a0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java
@@ -40,6 +40,7 @@
import android.app.ActivityOptions;
import android.app.PendingIntent;
import android.content.Context;
+import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.Region;
import android.testing.AndroidTestingRunner;
@@ -563,4 +564,47 @@
mTaskViewTaskController.onTaskAppeared(mTaskInfo, mLeash);
verify(mTaskViewTaskController, never()).cleanUpPendingTask();
}
+
+ @Test
+ public void testSetCaptionInsets_noTaskInitially() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+
+ Rect insets = new Rect(0, 400, 0, 0);
+ mTaskView.setCaptionInsets(Insets.of(insets));
+ mTaskView.onComputeInternalInsets(new ViewTreeObserver.InternalInsetsInfo());
+
+ verify(mTaskViewTaskController).applyCaptionInsetsIfNeeded();
+ verify(mOrganizer, never()).applyTransaction(any());
+
+ mTaskView.surfaceCreated(mock(SurfaceHolder.class));
+ reset(mOrganizer);
+ reset(mTaskViewTaskController);
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ mTaskViewTaskController.prepareOpenAnimation(true /* newTask */,
+ new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo,
+ mLeash, wct);
+ mTaskView.onComputeInternalInsets(new ViewTreeObserver.InternalInsetsInfo());
+
+ verify(mTaskViewTaskController).applyCaptionInsetsIfNeeded();
+ verify(mOrganizer).applyTransaction(any());
+ }
+
+ @Test
+ public void testSetCaptionInsets_withTask() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+
+ mTaskView.surfaceCreated(mock(SurfaceHolder.class));
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ mTaskViewTaskController.prepareOpenAnimation(true /* newTask */,
+ new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo,
+ mLeash, wct);
+ reset(mTaskViewTaskController);
+ reset(mOrganizer);
+
+ Rect insets = new Rect(0, 400, 0, 0);
+ mTaskView.setCaptionInsets(Insets.of(insets));
+ mTaskView.onComputeInternalInsets(new ViewTreeObserver.InternalInsetsInfo());
+ verify(mTaskViewTaskController).applyCaptionInsetsIfNeeded();
+ verify(mOrganizer).applyTransaction(any());
+ }
}
diff --git a/packages/CarrierDefaultApp/assets/slice_purchase_test.html b/packages/CarrierDefaultApp/assets/slice_purchase_test.html
index 917276b..ad18a9d 100644
--- a/packages/CarrierDefaultApp/assets/slice_purchase_test.html
+++ b/packages/CarrierDefaultApp/assets/slice_purchase_test.html
@@ -81,5 +81,7 @@
Dismiss flow
</button>
<p id="dismiss_flow"></p>
+
+ <h2>Test <a href="http://www.google.com">hyperlink</a></h2>
</body>
</html>
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
index 2530257d6..b100980 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
@@ -29,6 +29,7 @@
import android.view.KeyEvent;
import android.webkit.CookieManager;
import android.webkit.WebView;
+import android.webkit.WebViewClient;
import com.android.phone.slice.SlicePurchaseController;
@@ -113,8 +114,10 @@
return;
}
- // Create and configure WebView
- setupWebView();
+ // Clear any cookies that might be persisted from previous sessions before loading WebView
+ CookieManager.getInstance().removeAllCookies(value -> {
+ setupWebView();
+ });
}
protected void onPurchaseSuccessful() {
@@ -176,12 +179,7 @@
private void setupWebView() {
// Create WebView
mWebView = new WebView(this);
-
- // Clear any cookies and state that might be saved from previous sessions
- CookieManager.getInstance().removeAllCookies(null);
- CookieManager.getInstance().flush();
- mWebView.clearCache(true);
- mWebView.clearHistory();
+ mWebView.setWebViewClient(new WebViewClient());
// Enable JavaScript for the carrier purchase website to send results back to
// the slice purchase application.
diff --git a/packages/SettingsLib/tests/robotests/Android.bp b/packages/SettingsLib/tests/robotests/Android.bp
index 5c55a43..c037c40 100644
--- a/packages/SettingsLib/tests/robotests/Android.bp
+++ b/packages/SettingsLib/tests/robotests/Android.bp
@@ -42,7 +42,10 @@
name: "SettingsLibRoboTests",
srcs: ["src/**/*.java"],
static_libs: [
+ "Settings_robolectric_meta_service_file",
+ "Robolectric_shadows_androidx_fragment_upstream",
"SettingsLib-robo-testutils",
+ "androidx.fragment_fragment",
"androidx.test.core",
"androidx.core_core",
"testng", // TODO: remove once JUnit on Android provides assertThrows
@@ -53,6 +56,20 @@
test_options: {
timeout: 36000,
},
+ upstream: true,
+}
+
+java_genrule {
+ name: "Settings_robolectric_meta_service_file",
+ out: ["robolectric_meta_service_file.jar"],
+ tools: ["soong_zip"],
+ cmd: "mkdir -p $(genDir)/META-INF/services/ && touch $(genDir)/META-INF/services/org.robolectric.internal.ShadowProvider &&" +
+ "echo -e 'org.robolectric.Shadows' >> $(genDir)/META-INF/services/org.robolectric.internal.ShadowProvider && " +
+ "echo -e 'org.robolectric.shadows.multidex.Shadows' >> $(genDir)/META-INF/services/org.robolectric.internal.ShadowProvider && " +
+ "echo -e 'org.robolectric.shadows.httpclient.Shadows' >> $(genDir)/META-INF/services/org.robolectric.internal.ShadowProvider && " +
+ //"echo -e 'com.android.settings.testutils.shadow.Shadows' >> $(genDir)/META-INF/services/org.robolectric.internal.ShadowProvider && " +
+ "echo -e 'com.android.settingslib.testutils.shadow.Shadows' >> $(genDir)/META-INF/services/org.robolectric.internal.ShadowProvider && " +
+ "$(location soong_zip) -o $(out) -C $(genDir) -D $(genDir)/META-INF/services/",
}
java_library {
@@ -60,9 +77,23 @@
srcs: [
"testutils/com/android/settingslib/testutils/**/*.java",
],
-
+ javacflags: [
+ "-Aorg.robolectric.annotation.processing.shadowPackage=com.android.settingslib.testutils.shadow",
+ "-Aorg.robolectric.annotation.processing.sdkCheckMode=ERROR",
+ // Uncomment the below to debug annotation processors not firing.
+ //"-verbose",
+ //"-XprintRounds",
+ //"-XprintProcessorInfo",
+ //"-Xlint",
+ //"-J-verbose",
+ ],
+ plugins: [
+ "auto_value_plugin_1.9",
+ "auto_value_builder_plugin_1.9",
+ "Robolectric_processor_upstream",
+ ],
libs: [
- "Robolectric_all-target",
+ "Robolectric_all-target_upstream",
"mockito-robolectric-prebuilt",
"truth-prebuilt",
],
diff --git a/packages/SettingsLib/tests/robotests/config/robolectric.properties b/packages/SettingsLib/tests/robotests/config/robolectric.properties
index fab7251..2a9e50d 100644
--- a/packages/SettingsLib/tests/robotests/config/robolectric.properties
+++ b/packages/SettingsLib/tests/robotests/config/robolectric.properties
@@ -1 +1,2 @@
sdk=NEWEST_SDK
+instrumentedPackages=androidx.preference
diff --git a/packages/SettingsLib/tests/robotests/fragment/Android.bp b/packages/SettingsLib/tests/robotests/fragment/Android.bp
new file mode 100644
index 0000000..3e67156
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/fragment/Android.bp
@@ -0,0 +1,40 @@
+//#############################################
+// Compile Robolectric shadows framework misapplied to androidx
+//#############################################
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+java_library {
+ name: "Robolectric_shadows_androidx_fragment_upstream",
+ srcs: [
+ "src/main/java/**/*.java",
+ "src/main/java/**/*.kt",
+ ],
+ javacflags: [
+ "-Aorg.robolectric.annotation.processing.shadowPackage=org.robolectric.shadows.androidx.fragment",
+ "-Aorg.robolectric.annotation.processing.sdkCheckMode=ERROR",
+ // Uncomment the below to debug annotation processors not firing.
+ //"-verbose",
+ //"-XprintRounds",
+ //"-XprintProcessorInfo",
+ //"-Xlint",
+ //"-J-verbose",
+ ],
+ libs: [
+ "Robolectric_all-target_upstream",
+ "androidx.fragment_fragment",
+ ],
+ plugins: [
+ "auto_value_plugin_1.9",
+ "auto_value_builder_plugin_1.9",
+ "Robolectric_processor_upstream",
+ ],
+
+}
diff --git a/packages/SettingsLib/tests/robotests/fragment/BUILD b/packages/SettingsLib/tests/robotests/fragment/BUILD
new file mode 100644
index 0000000..393a02e
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/fragment/BUILD
@@ -0,0 +1,69 @@
+load("//third_party/java/android/android_sdk_linux/extras/android/compatibility/jetify:jetify.bzl", "jetify_android_library", "jetify_android_local_test")
+
+package(
+ default_applicable_licenses = ["//third_party/java_src/robolectric:license"],
+ default_visibility = ["//third_party/java_src/robolectric:__subpackages__"],
+)
+
+licenses(["notice"])
+
+#==============================================================================
+# Test resources library
+#==============================================================================
+jetify_android_library(
+ name = "test_resources",
+ custom_package = "org.robolectric.shadows.androidx.fragment",
+ manifest = "src/test/AndroidManifest.xml",
+ resource_files = glob(
+ ["src/test/resources/**/*"],
+ ),
+)
+
+#==============================================================================
+# AndroidX fragment module library
+#==============================================================================
+jetify_android_library(
+ name = "androidx_fragment",
+ testonly = 1,
+ srcs = glob(
+ ["src/main/java/**"],
+ ),
+ custom_package = "org.robolectric.shadows.androidx.fragment",
+ javacopts = [
+ "-Aorg.robolectric.annotation.processing.shadowPackage=org.robolectric.shadows.androidx.fragment",
+ ],
+ jetify_sources = True,
+ plugins = [
+ "//java/com/google/thirdparty/robolectric/processor",
+ ],
+ deps = [
+ "//third_party/java/androidx/core",
+ "//third_party/java/androidx/fragment",
+ "//third_party/java/androidx/lifecycle",
+ "//third_party/java_src/robolectric/shadowapi",
+ "//third_party/java_src/robolectric/shadows/framework",
+ ],
+)
+
+[
+ jetify_android_local_test(
+ name = "test_" + src.rstrip(".java"),
+ size = "small",
+ srcs = glob(
+ ["src/test/java/**/*.java"],
+ ),
+ jetify_sources = True,
+ deps = [
+ ":androidx_fragment",
+ ":test_resources",
+ "//third_party/java/androidx/fragment",
+ "//third_party/java/androidx/loader",
+ "//third_party/java/mockito",
+ "//third_party/java/robolectric",
+ "//third_party/java/truth",
+ ],
+ )
+ for src in glob(
+ ["src/test/java/**/*Test.java"],
+ )
+]
diff --git a/packages/SettingsLib/tests/robotests/fragment/build.gradle b/packages/SettingsLib/tests/robotests/fragment/build.gradle
new file mode 100644
index 0000000..d9dcd84
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/fragment/build.gradle
@@ -0,0 +1,48 @@
+plugins {
+ id "net.ltgt.errorprone" version "0.0.13"
+}
+
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 28
+
+ android {
+ sourceSets {
+ main {
+ res.srcDirs = ['src/test/resources/res']
+ }
+ }
+ testOptions {
+ unitTests {
+ includeAndroidResources = true
+ }
+ }
+ }
+}
+
+dependencies {
+ // Project dependencies
+ compileOnly project(":robolectric")
+
+ // Compile dependencies
+ compileOnly AndroidSdk.MAX_SDK.coordinates
+ compileOnly "androidx.core:core:1.0.0-rc02"
+ compileOnly 'androidx.fragment:fragment:1.0.0-rc02'
+ compileOnly "androidx.lifecycle:lifecycle-viewmodel:2.0.0-rc01"
+ compileOnly "androidx.lifecycle:lifecycle-common:2.0.0-beta01"
+
+ // Testing dependencies
+ testImplementation "com.google.truth:truth:0.44"
+ testImplementation "org.mockito:mockito-core:2.5.4"
+ testImplementation "androidx.arch.core:core-common:2.0.0-beta01"
+ testImplementation "androidx.arch.core:core-runtime:2.0.0-rc01"
+ testImplementation "androidx.collection:collection:1.0.0-rc01"
+ testImplementation "androidx.core:core:1.0.0-rc02"
+ testImplementation 'androidx.fragment:fragment:1.0.0-rc02'
+ testImplementation "androidx.lifecycle:lifecycle-viewmodel:2.0.0-rc01"
+ testImplementation "androidx.lifecycle:lifecycle-common:2.0.0-beta01"
+ testImplementation "androidx.lifecycle:lifecycle-runtime:2.0.0-rc01"
+ testImplementation "androidx.lifecycle:lifecycle-livedata-core:2.0.0-rc01"
+ testImplementation "androidx.loader:loader:1.0.0-rc02"
+}
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/FragmentController.java b/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/FragmentController.java
new file mode 100644
index 0000000..c688683
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/FragmentController.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.robolectric.shadows.androidx.fragment;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+
+import org.robolectric.android.controller.ActivityController;
+import org.robolectric.android.controller.ComponentController;
+import org.robolectric.util.ReflectionHelpers;
+
+/** A Controller that can be used to drive the lifecycle of a {@link Fragment} */
+public class FragmentController<F extends Fragment>
+ extends ComponentController<FragmentController<F>, F> {
+
+ private final F mFragment;
+ private final ActivityController<? extends FragmentActivity> mActivityController;
+
+ private FragmentController(F fragment, Class<? extends FragmentActivity> activityClass) {
+ this(fragment, activityClass, null /*intent*/, null /*arguments*/);
+ }
+
+ private FragmentController(
+ F fragment, Class<? extends FragmentActivity> activityClass, Intent intent) {
+ this(fragment, activityClass, intent, null /*arguments*/);
+ }
+
+ private FragmentController(
+ F fragment, Class<? extends FragmentActivity> activityClass, Bundle arguments) {
+ this(fragment, activityClass, null /*intent*/, arguments);
+ }
+
+ private FragmentController(
+ F fragment,
+ Class<? extends FragmentActivity> activityClass,
+ Intent intent,
+ Bundle arguments) {
+ super(fragment, intent);
+ this.mFragment = fragment;
+ if (arguments != null) {
+ this.mFragment.setArguments(arguments);
+ }
+ this.mActivityController =
+ ActivityController.of(ReflectionHelpers.callConstructor(activityClass), intent);
+ }
+
+ /**
+ * Generate the {@link FragmentController} for specific fragment.
+ *
+ * @param fragment the fragment which you'd like to drive lifecycle
+ * @return {@link FragmentController}
+ */
+ public static <F extends Fragment> FragmentController<F> of(F fragment) {
+ return new FragmentController<>(fragment, FragmentControllerActivity.class);
+ }
+
+ /**
+ * Generate the {@link FragmentController} for specific fragment and intent.
+ *
+ * @param fragment the fragment which you'd like to drive lifecycle
+ * @param intent the intent which will be retained by activity
+ * @return {@link FragmentController}
+ */
+ public static <F extends Fragment> FragmentController<F> of(F fragment, Intent intent) {
+ return new FragmentController<>(fragment, FragmentControllerActivity.class, intent);
+ }
+
+ /**
+ * Generate the {@link FragmentController} for specific fragment and arguments.
+ *
+ * @param fragment the fragment which you'd like to drive lifecycle
+ * @param arguments the arguments which will be retained by fragment
+ * @return {@link FragmentController}
+ */
+ public static <F extends Fragment> FragmentController<F> of(F fragment, Bundle arguments) {
+ return new FragmentController<>(fragment, FragmentControllerActivity.class, arguments);
+ }
+
+ /**
+ * Generate the {@link FragmentController} for specific fragment and activity class.
+ *
+ * @param fragment the fragment which you'd like to drive lifecycle
+ * @param activityClass the activity which will be attached by fragment
+ * @return {@link FragmentController}
+ */
+ public static <F extends Fragment> FragmentController<F> of(
+ F fragment, Class<? extends FragmentActivity> activityClass) {
+ return new FragmentController<>(fragment, activityClass);
+ }
+
+ /**
+ * Generate the {@link FragmentController} for specific fragment, intent and arguments.
+ *
+ * @param fragment the fragment which you'd like to drive lifecycle
+ * @param intent the intent which will be retained by activity
+ * @param arguments the arguments which will be retained by fragment
+ * @return {@link FragmentController}
+ */
+ public static <F extends Fragment> FragmentController<F> of(
+ F fragment, Intent intent, Bundle arguments) {
+ return new FragmentController<>(fragment, FragmentControllerActivity.class, intent,
+ arguments);
+ }
+
+ /**
+ * Generate the {@link FragmentController} for specific fragment, activity class and intent.
+ *
+ * @param fragment the fragment which you'd like to drive lifecycle
+ * @param activityClass the activity which will be attached by fragment
+ * @param intent the intent which will be retained by activity
+ * @return {@link FragmentController}
+ */
+ public static <F extends Fragment> FragmentController<F> of(
+ F fragment, Class<? extends FragmentActivity> activityClass, Intent intent) {
+ return new FragmentController<>(fragment, activityClass, intent);
+ }
+
+ /**
+ * Generate the {@link FragmentController} for specific fragment, activity class and arguments.
+ *
+ * @param fragment the fragment which you'd like to drive lifecycle
+ * @param activityClass the activity which will be attached by fragment
+ * @param arguments the arguments which will be retained by fragment
+ * @return {@link FragmentController}
+ */
+ public static <F extends Fragment> FragmentController<F> of(
+ F fragment, Class<? extends FragmentActivity> activityClass, Bundle arguments) {
+ return new FragmentController<>(fragment, activityClass, arguments);
+ }
+
+ /**
+ * Generate the {@link FragmentController} for specific fragment, activity class, intent and
+ * arguments.
+ *
+ * @param fragment the fragment which you'd like to drive lifecycle
+ * @param activityClass the activity which will be attached by fragment
+ * @param intent the intent which will be retained by activity
+ * @param arguments the arguments which will be retained by fragment
+ * @return {@link FragmentController}
+ */
+ public static <F extends Fragment> FragmentController<F> of(
+ F fragment,
+ Class<? extends FragmentActivity> activityClass,
+ Intent intent,
+ Bundle arguments) {
+ return new FragmentController<>(fragment, activityClass, intent, arguments);
+ }
+
+ /**
+ * Sets up the given fragment by attaching it to an activity, calling its onCreate() through
+ * onResume() lifecycle methods, and then making it visible. Note that the fragment will be
+ * added
+ * to the view with ID 1.
+ */
+ public static <F extends Fragment> F setupFragment(F fragment) {
+ return FragmentController.of(fragment).create().start().resume().visible().get();
+ }
+
+ /**
+ * Sets up the given fragment by attaching it to an activity, calling its onCreate() through
+ * onResume() lifecycle methods, and then making it visible. Note that the fragment will be
+ * added
+ * to the view with ID 1.
+ */
+ public static <F extends Fragment> F setupFragment(
+ F fragment, Class<? extends FragmentActivity> fragmentActivityClass) {
+ return FragmentController.of(fragment, fragmentActivityClass)
+ .create()
+ .start()
+ .resume()
+ .visible()
+ .get();
+ }
+
+ /**
+ * Sets up the given fragment by attaching it to an activity created with the given bundle,
+ * calling its onCreate() through onResume() lifecycle methods, and then making it visible. Note
+ * that the fragment will be added to the view with ID 1.
+ */
+ public static <F extends Fragment> F setupFragment(
+ F fragment, Class<? extends FragmentActivity> fragmentActivityClass, Bundle bundle) {
+ return FragmentController.of(fragment, fragmentActivityClass)
+ .create(bundle)
+ .start()
+ .resume()
+ .visible()
+ .get();
+ }
+
+ /**
+ * Sets up the given fragment by attaching it to an activity created with the given bundle and
+ * container id, calling its onCreate() through onResume() lifecycle methods, and then making it
+ * visible.
+ */
+ public static <F extends Fragment> F setupFragment(
+ F fragment,
+ Class<? extends FragmentActivity> fragmentActivityClass,
+ int containerViewId,
+ Bundle bundle) {
+ return FragmentController.of(fragment, fragmentActivityClass)
+ .create(containerViewId, bundle)
+ .start()
+ .resume()
+ .visible()
+ .get();
+ }
+
+ /**
+ * Creates the activity with {@link Bundle} and adds the fragment to the view with ID {@code
+ * contentViewId}.
+ */
+ public FragmentController<F> create(final int contentViewId, final Bundle bundle) {
+ shadowMainLooper.runPaused(
+ new Runnable() {
+ @Override
+ public void run() {
+ mActivityController
+ .create(bundle)
+ .get()
+ .getSupportFragmentManager()
+ .beginTransaction()
+ .add(contentViewId, mFragment)
+ .commit();
+ }
+ });
+ return this;
+ }
+
+ /**
+ * Creates the activity with {@link Bundle} and adds the fragment to it. Note that the fragment
+ * will be added to the view with ID 1.
+ */
+ public FragmentController<F> create(final Bundle bundle) {
+ return create(1, bundle);
+ }
+
+ /**
+ * Creates the {@link Fragment} in a newly initialized state and hence will receive a null
+ * savedInstanceState {@link Bundle parameter}
+ */
+ @Override
+ public FragmentController<F> create() {
+ return create(null);
+ }
+
+ /** Drive lifecycle of activity to Start lifetime */
+ public FragmentController<F> start() {
+ shadowMainLooper.runPaused(
+ new Runnable() {
+ @Override
+ public void run() {
+ mActivityController.start();
+ }
+ });
+ return this;
+ }
+
+ /** Drive lifecycle of activity to Resume lifetime */
+ public FragmentController<F> resume() {
+ shadowMainLooper.runPaused(
+ new Runnable() {
+ @Override
+ public void run() {
+ mActivityController.resume();
+ }
+ });
+ return this;
+ }
+
+ /** Drive lifecycle of activity to Pause lifetime */
+ public FragmentController<F> pause() {
+ shadowMainLooper.runPaused(
+ new Runnable() {
+ @Override
+ public void run() {
+ mActivityController.pause();
+ }
+ });
+ return this;
+ }
+
+ /** Drive lifecycle of activity to Stop lifetime */
+ public FragmentController<F> stop() {
+ shadowMainLooper.runPaused(
+ new Runnable() {
+ @Override
+ public void run() {
+ mActivityController.stop();
+ }
+ });
+ return this;
+ }
+
+ /** Drive lifecycle of activity to Destroy lifetime */
+ @Override
+ public FragmentController<F> destroy() {
+ shadowMainLooper.runPaused(
+ new Runnable() {
+ @Override
+ public void run() {
+ mActivityController.destroy();
+ }
+ });
+ return this;
+ }
+
+ /** Let activity can be visible lifetime */
+ public FragmentController<F> visible() {
+ shadowMainLooper.runPaused(
+ new Runnable() {
+ @Override
+ public void run() {
+ mActivityController.visible();
+ }
+ });
+ return this;
+ }
+
+ private static class FragmentControllerActivity extends FragmentActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ LinearLayout view = new LinearLayout(this);
+ view.setId(1);
+
+ setContentView(view);
+ }
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java b/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java
new file mode 100644
index 0000000..dd89441
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Testing infrastructure for androidx.fragment library.
+ *
+ * <p>To use this in your project, add the artifact {@code
+ * org.robolectric:shadows-androidx-fragment} to your project.
+ */
+package org.robolectric.shadows.androidx.fragment;
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/test/AndroidManifest.xml b/packages/SettingsLib/tests/robotests/fragment/src/test/AndroidManifest.xml
new file mode 100644
index 0000000..8493c02
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/fragment/src/test/AndroidManifest.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.robolectric.shadows.androidx.fragment">
+
+ <uses-sdk android:targetSdkVersion="28"/>
+</manifest>
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/test/java/org/robolectric/shadows/androidx/fragment/FragmentControllerTest.java b/packages/SettingsLib/tests/robotests/fragment/src/test/java/org/robolectric/shadows/androidx/fragment/FragmentControllerTest.java
new file mode 100644
index 0000000..ef63058
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/fragment/src/test/java/org/robolectric/shadows/androidx/fragment/FragmentControllerTest.java
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.robolectric.shadows.androidx.fragment;
+
+import static android.os.Looper.getMainLooper;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.robolectric.Shadows.shadowOf;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Tests for {@link FragmentController} */
+@RunWith(RobolectricTestRunner.class)
+public class FragmentControllerTest {
+
+ @After
+ public void tearDown() {
+ TranscriptFragment.clearLifecycleEvents();
+ }
+
+ @Test
+ public void initialNotAttached() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment());
+
+ assertThat(controller.get().getView()).isNull();
+ assertThat(controller.get().getActivity()).isNull();
+ assertThat(controller.get().isAdded()).isFalse();
+ }
+
+ @Test
+ public void initialNotAttached_customActivity() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), TestActivity.class);
+
+ assertThat(controller.get().getView()).isNull();
+ assertThat(controller.get().getActivity()).isNull();
+ assertThat(controller.get().isAdded()).isFalse();
+ }
+
+ @Test
+ public void attachedAfterCreate() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment());
+
+ controller.create();
+ shadowOf(getMainLooper()).idle();
+
+ assertThat(controller.get().getActivity()).isNotNull();
+ assertThat(controller.get().isAdded()).isTrue();
+ assertThat(controller.get().isResumed()).isFalse();
+ }
+
+ @Test
+ public void attachedAfterCreate_customActivity() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), TestActivity.class);
+
+ controller.create();
+ shadowOf(getMainLooper()).idle();
+
+ assertThat(controller.get().getActivity()).isNotNull();
+ assertThat(controller.get().getActivity()).isInstanceOf(TestActivity.class);
+ assertThat(controller.get().isAdded()).isTrue();
+ assertThat(controller.get().isResumed()).isFalse();
+ }
+
+ @Test
+ public void attachedAfterCreate_customizedViewId() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), CustomizedViewIdTestActivity.class);
+
+ controller.create(R.id.custom_activity_view, null).start();
+
+ assertThat(controller.get().getView()).isNotNull();
+ assertThat(controller.get().getActivity()).isNotNull();
+ assertThat(controller.get().isAdded()).isTrue();
+ assertThat(controller.get().isResumed()).isFalse();
+ assertThat((TextView) controller.get().getView().findViewById(R.id.tacos)).isNotNull();
+ }
+
+ @Test
+ public void hasViewAfterStart() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment());
+
+ controller.create().start();
+
+ assertThat(controller.get().getView()).isNotNull();
+ }
+
+ @Test
+ public void isResumed() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), TestActivity.class);
+
+ controller.create().start().resume();
+
+ assertThat(controller.get().getView()).isNotNull();
+ assertThat(controller.get().getActivity()).isNotNull();
+ assertThat(controller.get().isAdded()).isTrue();
+ assertThat(controller.get().isResumed()).isTrue();
+ assertThat((TextView) controller.get().getView().findViewById(R.id.tacos)).isNotNull();
+ }
+
+ @Test
+ public void isPaused() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), TestActivity.class);
+
+ controller.create().start().resume().pause();
+
+ assertThat(controller.get().getView()).isNotNull();
+ assertThat(controller.get().getActivity()).isNotNull();
+ assertThat(controller.get().isAdded()).isTrue();
+ assertThat(controller.get().isResumed()).isFalse();
+ assertThat(controller.get().getLifecycleEvents())
+ .containsExactly("onCreate", "onStart", "onResume", "onPause")
+ .inOrder();
+ }
+
+ @Test
+ public void isStopped() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), TestActivity.class);
+
+ controller.create().start().resume().pause().stop();
+
+ assertThat(controller.get().getView()).isNotNull();
+ assertThat(controller.get().getActivity()).isNotNull();
+ assertThat(controller.get().isAdded()).isTrue();
+ assertThat(controller.get().isResumed()).isFalse();
+ assertThat(controller.get().getLifecycleEvents())
+ .containsExactly("onCreate", "onStart", "onResume", "onPause", "onStop")
+ .inOrder();
+ }
+
+ @Test
+ public void withIntent() {
+ final Intent intent = generateTestIntent();
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), TestActivity.class, intent);
+
+ controller.create();
+ shadowOf(getMainLooper()).idle();
+ final Intent intentInFragment = controller.get().getActivity().getIntent();
+
+ assertThat(intentInFragment.getAction()).isEqualTo("test_action");
+ assertThat(intentInFragment.getExtras().getString("test_key")).isEqualTo("test_value");
+ }
+
+ @Test
+ public void withArguments() {
+ final Bundle bundle = generateTestBundle();
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), TestActivity.class, bundle);
+
+ controller.create();
+ final Bundle args = controller.get().getArguments();
+
+ assertThat(args.getString("test_key")).isEqualTo("test_value");
+ }
+
+ @Test
+ public void withIntentAndArguments() {
+ final Bundle bundle = generateTestBundle();
+ final Intent intent = generateTestIntent();
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), TestActivity.class, intent, bundle);
+
+ controller.create();
+ shadowOf(getMainLooper()).idle();
+ final Intent intentInFragment = controller.get().getActivity().getIntent();
+ final Bundle args = controller.get().getArguments();
+
+ assertThat(intentInFragment.getAction()).isEqualTo("test_action");
+ assertThat(intentInFragment.getExtras().getString("test_key")).isEqualTo("test_value");
+ assertThat(args.getString("test_key")).isEqualTo("test_value");
+ }
+
+ @Test
+ public void visible() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), TestActivity.class);
+
+ controller.create().start().resume();
+
+ assertThat(controller.get().isVisible()).isFalse();
+
+ controller.visible();
+
+ assertThat(controller.get().isVisible()).isTrue();
+ }
+
+ @Test
+ public void setupFragmentWithFragment_fragmentHasCorrectLifecycle() {
+ TranscriptFragment fragment = FragmentController.setupFragment(new TranscriptFragment());
+
+ assertThat(fragment.getLifecycleEvents())
+ .containsExactly("onCreate", "onStart", "onResume")
+ .inOrder();
+ assertThat(fragment.isVisible()).isTrue();
+ }
+
+ @Test
+ public void setupFragmentWithFragmentAndActivity_fragmentHasCorrectLifecycle() {
+ TranscriptFragment fragment =
+ FragmentController.setupFragment(new TranscriptFragment(), TestActivity.class);
+
+ assertThat(fragment.getLifecycleEvents())
+ .containsExactly("onCreate", "onStart", "onResume")
+ .inOrder();
+ assertThat(fragment.isVisible()).isTrue();
+ }
+
+ @Test
+ public void setupFragmentWithFragmentAndActivityAndBundle_HasCorrectLifecycle() {
+ Bundle testBundle = generateTestBundle();
+ TranscriptFragment fragment =
+ FragmentController.setupFragment(new TranscriptFragment(), TestActivity.class,
+ testBundle);
+
+ assertThat(fragment.getLifecycleEvents())
+ .containsExactly("onCreate", "onStart", "onResume")
+ .inOrder();
+ assertThat(fragment.isVisible()).isTrue();
+ }
+
+ @Test
+ public void
+ setupFragmentWithFragment_Activity_ContainViewIdAndBundle_HasCorrectLifecycle() {
+ Bundle testBundle = generateTestBundle();
+ TranscriptFragment fragment =
+ FragmentController.setupFragment(
+ new TranscriptFragment(),
+ CustomizedViewIdTestActivity.class,
+ R.id.custom_activity_view,
+ testBundle);
+
+ assertThat(fragment.getLifecycleEvents())
+ .containsExactly("onCreate", "onStart", "onResume")
+ .inOrder();
+ assertThat(fragment.isVisible()).isTrue();
+ }
+
+ private Intent generateTestIntent() {
+ final Intent testIntent = new Intent("test_action").putExtra("test_key", "test_value");
+ return testIntent;
+ }
+
+ private Bundle generateTestBundle() {
+ final Bundle testBundle = new Bundle();
+ testBundle.putString("test_key", "test_value");
+
+ return testBundle;
+ }
+
+ /** A Fragment which can record lifecycle status for test. */
+ public static class TranscriptFragment extends Fragment {
+
+ public static final List<String> sLifecycleEvents = new ArrayList<>();
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ sLifecycleEvents.add("onCreate");
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ sLifecycleEvents.add("onStart");
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ sLifecycleEvents.add("onResume");
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ sLifecycleEvents.add("onPause");
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ sLifecycleEvents.add("onStop");
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_contents, container, false);
+ }
+
+ public List<String> getLifecycleEvents() {
+ return sLifecycleEvents;
+ }
+
+ public static void clearLifecycleEvents() {
+ sLifecycleEvents.clear();
+ }
+ }
+
+ /** A Activity which set a default view for test. */
+ public static class TestActivity extends FragmentActivity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ LinearLayout view = new LinearLayout(this);
+ view.setId(1);
+
+ setContentView(view);
+ }
+ }
+
+ /** A Activity which has a custom view for test. */
+ public static class CustomizedViewIdTestActivity extends FragmentActivity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.custom_activity_view);
+ }
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/custom_activity_view.xml b/packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/custom_activity_view.xml
new file mode 100644
index 0000000..c074f30
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/custom_activity_view.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/custom_activity_view"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+
+</LinearLayout>
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/fragment_contents.xml b/packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/fragment_contents.xml
new file mode 100644
index 0000000..425b2bb
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/fragment_contents.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/tacos"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TACOS"/>
+
+ <TextView
+ android:id="@+id/burritos"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="BURRITOS"/>
+
+</LinearLayout>
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index 4a913c8..bb72375 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -25,7 +25,6 @@
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
@@ -58,12 +57,10 @@
import org.robolectric.shadows.ShadowSettings;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {UtilsTest.ShadowSecure.class, UtilsTest.ShadowLocationManager.class})
+@Config(shadows = {UtilsTest.ShadowLocationManager.class})
public class UtilsTest {
private static final double[] TEST_PERCENTAGES = {0, 0.4, 0.5, 0.6, 49, 49.3, 49.8, 50, 100};
private static final String TAG = "UtilsTest";
@@ -94,7 +91,7 @@
mContext = spy(RuntimeEnvironment.application);
when(mContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn(mLocationManager);
when(mContext.getSystemService(UsbManager.class)).thenReturn(mUsbManager);
- ShadowSecure.reset();
+ ShadowSettings.ShadowSecure.reset();
mAudioManager = mContext.getSystemService(AudioManager.class);
}
@@ -111,15 +108,16 @@
Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.LOCATION_CHANGER, Settings.Secure.LOCATION_CHANGER_UNKNOWN))
- .isEqualTo(Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
+ Settings.Secure.LOCATION_CHANGER,
+ Settings.Secure.LOCATION_CHANGER_UNKNOWN)).isEqualTo(
+ Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
}
@Test
public void testFormatPercentage_RoundTrue_RoundUpIfPossible() {
- final String[] expectedPercentages = {PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_1,
- PERCENTAGE_1, PERCENTAGE_49, PERCENTAGE_49, PERCENTAGE_50, PERCENTAGE_50,
- PERCENTAGE_100};
+ final String[] expectedPercentages =
+ {PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_1, PERCENTAGE_1, PERCENTAGE_49,
+ PERCENTAGE_49, PERCENTAGE_50, PERCENTAGE_50, PERCENTAGE_100};
for (int i = 0, size = TEST_PERCENTAGES.length; i < size; i++) {
final String percentage = Utils.formatPercentage(TEST_PERCENTAGES[i], true);
@@ -129,9 +127,9 @@
@Test
public void testFormatPercentage_RoundFalse_NoRound() {
- final String[] expectedPercentages = {PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_0,
- PERCENTAGE_0, PERCENTAGE_49, PERCENTAGE_49, PERCENTAGE_49, PERCENTAGE_50,
- PERCENTAGE_100};
+ final String[] expectedPercentages =
+ {PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_49,
+ PERCENTAGE_49, PERCENTAGE_49, PERCENTAGE_50, PERCENTAGE_100};
for (int i = 0, size = TEST_PERCENTAGES.length; i < size; i++) {
final String percentage = Utils.formatPercentage(TEST_PERCENTAGES[i], false);
@@ -143,12 +141,7 @@
public void testGetDefaultStorageManagerDaysToRetain_storageManagerDaysToRetainUsesResources() {
Resources resources = mock(Resources.class);
when(resources.getInteger(
- eq(
- com.android
- .internal
- .R
- .integer
- .config_storageManagerDaystoRetainDefault)))
+ eq(com.android.internal.R.integer.config_storageManagerDaystoRetainDefault)))
.thenReturn(60);
assertThat(Utils.getDefaultStorageManagerDaysToRetain(resources)).isEqualTo(60);
}
@@ -163,31 +156,6 @@
return intent -> TextUtils.equals(expected, intent.getAction());
}
- @Implements(value = Settings.Secure.class)
- public static class ShadowSecure extends ShadowSettings.ShadowSecure {
- private static Map<String, Integer> map = new HashMap<>();
-
- @Implementation
- public static boolean putIntForUser(ContentResolver cr, String name, int value,
- int userHandle) {
- map.put(name, value);
- return true;
- }
-
- @Implementation
- public static int getIntForUser(ContentResolver cr, String name, int def, int userHandle) {
- if (map.containsKey(name)) {
- return map.get(name);
- } else {
- return def;
- }
- }
-
- public static void reset() {
- map.clear();
- }
- }
-
@Implements(value = LocationManager.class)
public static class ShadowLocationManager {
@@ -337,9 +305,8 @@
@Test
public void getBatteryStatus_statusIsFull_returnFullString() {
- final Intent intent = new Intent()
- .putExtra(BatteryManager.EXTRA_LEVEL, 100)
- .putExtra(BatteryManager.EXTRA_SCALE, 100);
+ final Intent intent = new Intent().putExtra(BatteryManager.EXTRA_LEVEL, 100).putExtra(
+ BatteryManager.EXTRA_SCALE, 100);
final Resources resources = mContext.getResources();
assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false)).isEqualTo(
@@ -348,9 +315,8 @@
@Test
public void getBatteryStatus_statusIsFullAndUseCompactStatus_returnFullyChargedString() {
- final Intent intent = new Intent()
- .putExtra(BatteryManager.EXTRA_LEVEL, 100)
- .putExtra(BatteryManager.EXTRA_SCALE, 100);
+ final Intent intent = new Intent().putExtra(BatteryManager.EXTRA_LEVEL, 100).putExtra(
+ BatteryManager.EXTRA_SCALE, 100);
final Resources resources = mContext.getResources();
assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ true)).isEqualTo(
@@ -516,7 +482,6 @@
when(mUsbPort.getStatus()).thenReturn(mUsbPortStatus);
when(mUsbPort.supportsComplianceWarnings()).thenReturn(true);
when(mUsbPortStatus.isConnected()).thenReturn(true);
- when(mUsbPortStatus.getComplianceWarnings())
- .thenReturn(new int[]{complianceWarningType});
+ when(mUsbPortStatus.getComplianceWarnings()).thenReturn(new int[]{complianceWarningType});
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java
index 44fdaec..3de8446 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java
@@ -23,13 +23,17 @@
import android.os.UserHandle;
import android.provider.Settings;
+import com.android.settingslib.testutils.shadow.ShadowSecure;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowSecure.class})
public class AccessibilityUtilsTest {
private Context mContext;
@@ -46,7 +50,7 @@
@Test
public void getEnabledServicesFromSettings_badFormat_emptyResult() {
- Settings.Secure.putStringForUser(
+ ShadowSecure.putStringForUser(
mContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
":",
UserHandle.myUserId());
@@ -57,7 +61,7 @@
@Test
public void getEnabledServicesFromSettings_1Service_1result() {
final ComponentName cn = new ComponentName("pkg", "serv");
- Settings.Secure.putStringForUser(
+ ShadowSecure.putStringForUser(
mContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
cn.flattenToString() + ":",
UserHandle.myUserId());
@@ -70,7 +74,7 @@
public void getEnabledServicesFromSettings_2Services_2results() {
final ComponentName cn1 = new ComponentName("pkg", "serv");
final ComponentName cn2 = new ComponentName("pkg", "serv2");
- Settings.Secure.putStringForUser(
+ ShadowSecure.putStringForUser(
mContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
cn1.flattenToString() + ":" + cn2.flattenToString(),
UserHandle.myUserId());
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java
index cb62a73..f9505dd 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java
@@ -37,6 +37,8 @@
import android.os.UserManager;
import android.util.LongSparseArray;
+import com.android.settingslib.testutils.shadow.ShadowPermissionChecker;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,7 +47,6 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowPermissionChecker;
import java.time.Clock;
import java.util.ArrayList;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
index dd8d54a..a2e8c59 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
@@ -38,6 +38,7 @@
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.LooperMode;
import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
@@ -167,6 +168,7 @@
}
@Test
+ @LooperMode(LooperMode.Mode.PAUSED)
public void getAttribution_notSet_shouldReturnUnknown() {
final Activity activity = Robolectric.setupActivity(Activity.class);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java
index d67d44b..25833b3 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java
@@ -36,6 +36,7 @@
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.jank.InteractionJankMonitor.CujType;
+import com.android.settingslib.testutils.OverpoweredReflectionHelper;
import com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor;
import org.junit.Before;
@@ -51,7 +52,6 @@
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
-import org.robolectric.util.ReflectionHelpers;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -83,8 +83,10 @@
public void setUp() {
ShadowInteractionJankMonitor.reset();
when(ShadowInteractionJankMonitor.MOCK_INSTANCE.begin(any())).thenReturn(true);
- ReflectionHelpers.setStaticField(SettingsJankMonitor.class, "scheduledExecutorService",
- mScheduledExecutorService);
+ OverpoweredReflectionHelper
+ .setStaticField(SettingsJankMonitor.class,
+ "scheduledExecutorService",
+ mScheduledExecutorService);
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/HideNonSystemOverlayMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/HideNonSystemOverlayMixinTest.java
index cf702b53..471dac0 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/HideNonSystemOverlayMixinTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/HideNonSystemOverlayMixinTest.java
@@ -37,8 +37,10 @@
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.android.controller.ActivityController;
+import org.robolectric.annotation.LooperMode;
@RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.PAUSED)
public class HideNonSystemOverlayMixinTest {
private ActivityController<TestActivity> mActivityController;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java
index 3475ff7..b009abd 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java
@@ -22,13 +22,14 @@
import android.os.UserManager;
import android.provider.Settings;
+import com.android.settingslib.testutils.shadow.ShadowUserManager;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.ShadowUserManager;
@RunWith(RobolectricTestRunner.class)
public class DevelopmentSettingsEnablerTest {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
index 8e33ca3..0cabab2 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
@@ -21,6 +21,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.LooperMode;
import org.xmlpull.v1.XmlPullParserException;
import java.io.ByteArrayInputStream;
@@ -269,6 +270,7 @@
}
@Test
+ @LooperMode(LooperMode.Mode.PAUSED)
public void testGenerateHtmlWithCustomHeading() throws Exception {
List<File> xmlFiles = new ArrayList<>();
Map<String, Map<String, Set<String>>> fileNameToLibraryToContentIdMap = new HashMap<>();
@@ -292,6 +294,7 @@
}
@Test
+ @LooperMode(LooperMode.Mode.PAUSED)
public void testGenerateNewHtmlWithCustomHeading() throws Exception {
List<File> xmlFiles = new ArrayList<>();
Map<String, Map<String, Set<String>>> fileNameToLibraryToContentIdMap = new HashMap<>();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/package-info.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/package-info.java
new file mode 100644
index 0000000..9e9725f
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@LooperMode(LooperMode.Mode.LEGACY)
+package com.android.settingslib;
+
+import org.robolectric.annotation.LooperMode;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java
index d41d511..faec02f7 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java
@@ -27,6 +27,7 @@
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.LooperMode;
@RunWith(RobolectricTestRunner.class)
public class AnimatedImageViewTest {
@@ -40,6 +41,7 @@
}
@Test
+ @LooperMode(LooperMode.Mode.PAUSED)
public void testAnimation_ViewVisible_AnimationRunning() {
mAnimatedImageView.setVisibility(View.VISIBLE);
mAnimatedImageView.setAnimating(true);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java
index 0a48f19..0d88913 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java
@@ -41,6 +41,8 @@
import androidx.preference.PreferenceViewHolder;
import androidx.preference.R;
+import com.android.settingslib.testutils.OverpoweredReflectionHelper;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -502,14 +504,18 @@
private void assumeAndroidR() {
ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", 30);
ReflectionHelpers.setStaticField(Build.VERSION.class, "CODENAME", "R");
- ReflectionHelpers.setStaticField(BannerMessagePreference.class, "IS_AT_LEAST_S", false);
+ OverpoweredReflectionHelper
+ .setStaticField(BannerMessagePreference.class, "IS_AT_LEAST_S", false);
// Reset view holder to use correct layout.
}
+
+
private void assumeAndroidS() {
ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", 31);
ReflectionHelpers.setStaticField(Build.VERSION.class, "CODENAME", "S");
- ReflectionHelpers.setStaticField(BannerMessagePreference.class, "IS_AT_LEAST_S", true);
+ OverpoweredReflectionHelper
+ .setStaticField(BannerMessagePreference.class, "IS_AT_LEAST_S", true);
// Re-inflate view to update layout.
setUpViewHolder();
}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/OverpoweredReflectionHelper.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/OverpoweredReflectionHelper.java
new file mode 100644
index 0000000..4fcc5a1
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/OverpoweredReflectionHelper.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.testutils;
+
+import org.robolectric.util.ReflectionHelpers;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+public class OverpoweredReflectionHelper extends ReflectionHelpers {
+
+ /**
+ * Robolectric upstream does not rely on or encourage this behaviour.
+ *
+ * @param field
+ */
+ private static void makeFieldVeryAccessible(Field field) {
+ field.setAccessible(true);
+ // remove 'final' modifier if present
+ if ((field.getModifiers() & Modifier.FINAL) == Modifier.FINAL) {
+ Field modifiersField = getModifiersField();
+ modifiersField.setAccessible(true);
+ try {
+ modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
+ } catch (IllegalAccessException e) {
+
+ throw new AssertionError(e);
+ }
+ }
+ }
+
+ private static Field getModifiersField() {
+ try {
+ return Field.class.getDeclaredField("modifiers");
+ } catch (NoSuchFieldException e) {
+ try {
+ Method getFieldsMethod =
+ Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class);
+ getFieldsMethod.setAccessible(true);
+ Field[] fields = (Field[]) getFieldsMethod.invoke(Field.class, false);
+ for (Field modifiersField : fields) {
+ if ("modifiers".equals(modifiersField.getName())) {
+ return modifiersField;
+ }
+ }
+ } catch (ReflectiveOperationException innerE) {
+ throw new AssertionError(innerE);
+ }
+ }
+ throw new AssertionError();
+ }
+
+ /**
+ * Reflectively set the value of a static field.
+ *
+ * @param field Field object.
+ * @param fieldNewValue The new value.
+ */
+ public static void setStaticField(Field field, Object fieldNewValue) {
+ try {
+ makeFieldVeryAccessible(field);
+ field.setAccessible(true);
+ field.set(null, fieldNewValue);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Reflectively set the value of a static field.
+ *
+ * @param clazz Target class.
+ * @param fieldName The field name.
+ * @param fieldNewValue The new value.
+ */
+ public static void setStaticField(Class<?> clazz, String fieldName, Object fieldNewValue) {
+ try {
+ setStaticField(clazz.getDeclaredField(fieldName), fieldNewValue);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowActivityManager.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowActivityManager.java
index 924eb04..0b9ba8d 100644
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowActivityManager.java
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowActivityManager.java
@@ -16,23 +16,27 @@
package com.android.settingslib.testutils.shadow;
+import static android.os.Build.VERSION_CODES.O;
+
import android.app.ActivityManager;
+import android.app.IActivityManager;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
import org.robolectric.shadow.api.Shadow;
+import org.robolectric.util.ReflectionHelpers;
@Implements(ActivityManager.class)
public class ShadowActivityManager {
private static int sCurrentUserId = 0;
- private int mUserSwitchedTo = -1;
+ private static int sUserSwitchedTo = -1;
@Resetter
- public void reset() {
+ public static void reset() {
sCurrentUserId = 0;
- mUserSwitchedTo = 0;
+ sUserSwitchedTo = 0;
}
@Implementation
@@ -42,16 +46,21 @@
@Implementation
protected boolean switchUser(int userId) {
- mUserSwitchedTo = userId;
+ sUserSwitchedTo = userId;
return true;
}
+ @Implementation(minSdk = O)
+ protected static IActivityManager getService() {
+ return ReflectionHelpers.createNullProxy(IActivityManager.class);
+ }
+
public boolean getSwitchUserCalled() {
- return mUserSwitchedTo != -1;
+ return sUserSwitchedTo != -1;
}
public int getUserSwitchedTo() {
- return mUserSwitchedTo;
+ return sUserSwitchedTo;
}
public static void setCurrentUser(int userId) {
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java
index 2c0792f..bbfdb7f 100644
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java
@@ -29,7 +29,7 @@
private static String sDefaultDialer;
@Resetter
- public void reset() {
+ public static void reset() {
sDefaultDialer = null;
}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowPermissionChecker.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowPermissionChecker.java
new file mode 100644
index 0000000..fae3aea
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowPermissionChecker.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.testutils.shadow;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.AttributionSource;
+import android.content.Context;
+import android.content.PermissionChecker;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+import java.util.HashMap;
+import java.util.Map;
+/** Shadow class of {@link PermissionChecker}. */
+@Implements(PermissionChecker.class)
+public class ShadowPermissionChecker {
+ private static final Map<String, Map<String, Integer>> RESULTS = new HashMap<>();
+ /** Set the result of permission check for a specific permission. */
+ public static void setResult(String packageName, String permission, int result) {
+ if (!RESULTS.containsKey(packageName)) {
+ RESULTS.put(packageName, new HashMap<>());
+ }
+ RESULTS.get(packageName).put(permission, result);
+ }
+ /** Check the permission of calling package. */
+ @Implementation
+ public static int checkCallingPermissionForDataDelivery(
+ Context context,
+ String permission,
+ String packageName,
+ String attributionTag,
+ String message) {
+ return RESULTS.containsKey(packageName) && RESULTS.get(packageName).containsKey(permission)
+ ? RESULTS.get(packageName).get(permission)
+ : PermissionChecker.checkCallingPermissionForDataDelivery(
+ context, permission, packageName, attributionTag, message);
+ }
+ /** Check general permission. */
+ @Implementation
+ public static int checkPermissionForDataDelivery(
+ Context context,
+ String permission,
+ int pid,
+ int uid,
+ String packageName,
+ String attributionTag,
+ String message) {
+ return RESULTS.containsKey(packageName) && RESULTS.get(packageName).containsKey(permission)
+ ? RESULTS.get(packageName).get(permission)
+ : PermissionChecker.checkPermissionForDataDelivery(
+ context, permission, pid, uid, packageName, attributionTag, message);
+ }
+ /** Check general permission. */
+ @Implementation
+ public static int checkPermissionForPreflight(@NonNull Context context,
+ @NonNull String permission, int pid, int uid, @Nullable String packageName) {
+ return checkPermissionForPreflight(context, permission, new AttributionSource(
+ uid, packageName, null /*attributionTag*/));
+ }
+ /** Check general permission. */
+ @Implementation
+ public static int checkPermissionForPreflight(@NonNull Context context,
+ @NonNull String permission, @NonNull AttributionSource attributionSource) {
+ final String packageName = attributionSource.getPackageName();
+ return RESULTS.containsKey(packageName) && RESULTS.get(packageName).containsKey(permission)
+ ? RESULTS.get(packageName).get(permission)
+ : PermissionChecker.checkPermissionForPreflight(
+ context, permission, attributionSource);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSecure.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSecure.java
new file mode 100644
index 0000000..70ebc67
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSecure.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.testutils.shadow;
+
+import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+
+import android.content.ContentResolver;
+import android.provider.Settings;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowSettings;
+
+@Implements(value = Settings.Secure.class)
+public class ShadowSecure extends ShadowSettings.ShadowSecure {
+ @Implementation(minSdk = JELLY_BEAN_MR1)
+ public static boolean putStringForUser(ContentResolver cr, String name, String value,
+ int userHandle) {
+ return putString(cr, name, value);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java
index 381d072..5ac0a87 100644
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java
@@ -31,7 +31,7 @@
private static ComponentName sDefaultSmsApplication;
@Resetter
- public void reset() {
+ public static void reset() {
sDefaultSmsApplication = null;
}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowUserManager.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowUserManager.java
index ca1eefc..60d7721 100644
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowUserManager.java
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowUserManager.java
@@ -16,20 +16,28 @@
package com.android.settingslib.testutils.shadow;
+import static android.os.Build.VERSION_CODES.N_MR1;
+
import android.annotation.UserIdInt;
import android.content.Context;
import android.content.pm.UserInfo;
+import android.content.pm.UserProperties;
+import android.os.UserHandle;
import android.os.UserManager;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowBuild;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
@Implements(value = UserManager.class)
public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager {
private List<UserInfo> mUserInfos = addProfile(0, "Owner");
+ private final Map<Integer, UserProperties> mUserPropertiesMap = new HashMap<>();
@Implementation
protected static UserManager get(Context context) {
@@ -62,4 +70,37 @@
protected List<UserInfo> getProfiles(@UserIdInt int userHandle) {
return getProfiles();
}
+
+ /**
+ * @return {@code false} by default, or the value specified via {@link #setIsAdminUser(boolean)}
+ */
+ @Implementation(minSdk = N_MR1)
+ public boolean isAdminUser() {
+ return getUserInfo(UserHandle.myUserId()).isAdmin();
+ }
+
+ /**
+ * Sets that the current user is an admin user; controls the return value of
+ * {@link UserManager#isAdminUser}.
+ */
+ public void setIsAdminUser(boolean isAdminUser) {
+ UserInfo userInfo = getUserInfo(UserHandle.myUserId());
+ if (isAdminUser) {
+ userInfo.flags |= UserInfo.FLAG_ADMIN;
+ } else {
+ userInfo.flags &= ~UserInfo.FLAG_ADMIN;
+ }
+ }
+
+ public void setupUserProperty(int userId, int showInSettings) {
+ UserProperties userProperties = new UserProperties(new UserProperties.Builder()
+ .setShowInSettings(showInSettings).build());
+ mUserPropertiesMap.putIfAbsent(userId, userProperties);
+ }
+
+ @Implementation(minSdk = ShadowBuild.UPSIDE_DOWN_CAKE)
+ protected UserProperties getUserProperties(UserHandle user) {
+ return mUserPropertiesMap.getOrDefault(user.getIdentifier(),
+ new UserProperties(new UserProperties.Builder().build()));
+ }
}
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index a443b5c..73fb0f0 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -65,6 +65,7 @@
"androidx.compose.runtime_runtime",
"androidx.compose.material3_material3",
"androidx.activity_activity-compose",
+ "androidx.compose.animation_animation-graphics",
],
// By default, Compose is disabled and we compile the ComposeFacade
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeInitializerImpl.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeInitializerImpl.kt
index fbd7f83..1674591 100644
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeInitializerImpl.kt
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeInitializerImpl.kt
@@ -17,9 +17,9 @@
package com.android.systemui.compose
import android.view.View
+import androidx.lifecycle.findViewTreeLifecycleOwner
+import androidx.lifecycle.setViewTreeLifecycleOwner
import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.ViewTreeLifecycleOwner
-import androidx.savedstate.SavedStateRegistry
import androidx.savedstate.SavedStateRegistryController
import androidx.savedstate.SavedStateRegistryOwner
import com.android.compose.animation.ViewTreeSavedStateRegistryOwner
@@ -27,7 +27,7 @@
internal object ComposeInitializerImpl : ComposeInitializer {
override fun onAttachedToWindow(root: View) {
- if (ViewTreeLifecycleOwner.get(root) != null) {
+ if (root.findViewTreeLifecycleOwner() != null) {
error("root $root already has a LifecycleOwner")
}
@@ -54,7 +54,8 @@
override val savedStateRegistry = savedStateRegistryController.savedStateRegistry
- override fun getLifecycle(): Lifecycle = lifecycleOwner.lifecycle
+ override val lifecycle: Lifecycle
+ get() = lifecycleOwner.lifecycle
}
// We must call [ViewLifecycleOwner.onCreate] after creating the [SavedStateRegistryOwner]
@@ -64,13 +65,13 @@
// Set the owners on the root. They will be reused by any ComposeView inside the root
// hierarchy.
- ViewTreeLifecycleOwner.set(root, lifecycleOwner)
+ root.setViewTreeLifecycleOwner(lifecycleOwner)
ViewTreeSavedStateRegistryOwner.set(root, savedStateRegistryOwner)
}
override fun onDetachedFromWindow(root: View) {
- (ViewTreeLifecycleOwner.get(root) as ViewLifecycleOwner).onDestroy()
- ViewTreeLifecycleOwner.set(root, null)
+ (root.findViewTreeLifecycleOwner() as ViewLifecycleOwner).onDestroy()
+ root.setViewTreeLifecycleOwner(null)
ViewTreeSavedStateRegistryOwner.set(root, null)
}
}
diff --git a/packages/SystemUI/compose/features/Android.bp b/packages/SystemUI/compose/features/Android.bp
index 8f8bb1b..c6438c9 100644
--- a/packages/SystemUI/compose/features/Android.bp
+++ b/packages/SystemUI/compose/features/Android.bp
@@ -34,6 +34,7 @@
"PlatformComposeCore",
"androidx.compose.runtime_runtime",
+ "androidx.compose.animation_animation-graphics",
"androidx.compose.material3_material3",
"androidx.activity_activity-compose",
],
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
index 323fed0..85178bc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-@file:OptIn(ExperimentalAnimationApi::class)
+@file:OptIn(ExperimentalAnimationApi::class, ExperimentalAnimationGraphicsApi::class)
package com.android.systemui.bouncer.ui.composable
@@ -29,11 +29,14 @@
import androidx.compose.animation.core.animateDp
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloatAsState
-import androidx.compose.animation.core.keyframes
import androidx.compose.animation.core.snap
import androidx.compose.animation.core.tween
import androidx.compose.animation.core.updateTransition
-import androidx.compose.foundation.Canvas
+import androidx.compose.animation.graphics.ExperimentalAnimationGraphicsApi
+import androidx.compose.animation.graphics.res.animatedVectorResource
+import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter
+import androidx.compose.animation.graphics.vector.AnimatedImageVector
+import androidx.compose.foundation.Image
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -61,8 +64,10 @@
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.unit.Constraints
@@ -70,6 +75,7 @@
import androidx.compose.ui.unit.dp
import com.android.compose.animation.Easings
import com.android.compose.grid.VerticalGrid
+import com.android.internal.R.id.image
import com.android.systemui.R
import com.android.systemui.bouncer.ui.viewmodel.ActionButtonAppearance
import com.android.systemui.bouncer.ui.viewmodel.EnteredKey
@@ -139,7 +145,8 @@
else -> EntryVisibility.Hidden
}
- ObscuredInputEntry(updateTransition(visibility, label = "Pin Entry $entry"))
+ val shape = viewModel.pinShapes.getShape(entry.sequenceNumber)
+ PinInputEntry(shape, updateTransition(visibility, label = "Pin Entry $entry"))
LaunchedEffect(entry) {
// Remove entry from visiblePinEntries once the hide transition completed.
@@ -171,15 +178,11 @@
}
@Composable
-private fun ObscuredInputEntry(transition: Transition<EntryVisibility>) {
+private fun PinInputEntry(shapeResourceId: Int, transition: Transition<EntryVisibility>) {
// spec: http://shortn/_DEhE3Xl2bi
- val shapePadding = 6.dp
- val shapeOvershootSize = 22.dp
val dismissStaggerDelayMs = 33
val dismissDurationMs = 450
val expansionDurationMs = 250
- val shapeExpandDurationMs = 83
- val shapeRetractDurationMs = 167
val shapeCollapseDurationMs = 200
val animatedEntryWidth by
@@ -194,19 +197,17 @@
},
label = "entry space"
) { state ->
- if (state == EntryVisibility.Shown) entryShapeSize + (shapePadding * 2) else 0.dp
+ if (state == EntryVisibility.Shown) entryShapeSize else 0.dp
}
val animatedShapeSize by
transition.animateDp(
transitionSpec = {
when {
- EntryVisibility.Hidden isTransitioningTo EntryVisibility.Shown ->
- keyframes {
- durationMillis = shapeExpandDurationMs + shapeRetractDurationMs
- 0.dp at 0 with Easings.Linear
- shapeOvershootSize at shapeExpandDurationMs with Easings.Legacy
- }
+ EntryVisibility.Hidden isTransitioningTo EntryVisibility.Shown -> {
+ // The AVD contains the entry transition.
+ snap()
+ }
targetState is EntryVisibility.BulkHidden -> {
val target = targetState as EntryVisibility.BulkHidden
tween(
@@ -220,17 +221,21 @@
},
label = "shape size"
) { state ->
- when (state) {
- EntryVisibility.Shown -> entryShapeSize
- else -> 0.dp
- }
+ if (state == EntryVisibility.Shown) entryShapeSize else 0.dp
}
val dotColor = MaterialTheme.colorScheme.onSurfaceVariant
Layout(
content = {
- // TODO(b/282730134): add support for dot shapes.
- Canvas(Modifier) { drawCircle(dotColor) }
+ val image = AnimatedImageVector.animatedVectorResource(shapeResourceId)
+ var atEnd by remember { mutableStateOf(false) }
+ Image(
+ painter = rememberAnimatedVectorPainter(image, atEnd),
+ contentDescription = null,
+ contentScale = ContentScale.Crop,
+ colorFilter = ColorFilter.tint(dotColor),
+ )
+ LaunchedEffect(Unit) { atEnd = true }
}
) { measurables, _ ->
val shapeSizePx = animatedShapeSize.roundToPx()
@@ -507,7 +512,7 @@
}
}
-private val entryShapeSize = 16.dp
+private val entryShapeSize = 30.dp
private val pinButtonSize = 84.dp
private val pinButtonErrorShrinkFactor = 67.dp / pinButtonSize
diff --git a/packages/SystemUI/res/drawable/pin_dot_avd.xml b/packages/SystemUI/res/drawable/pin_dot_avd.xml
index 1c16251..710ba83 100644
--- a/packages/SystemUI/res/drawable/pin_dot_avd.xml
+++ b/packages/SystemUI/res/drawable/pin_dot_avd.xml
@@ -1 +1,40 @@
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"><aapt:attr name="android:drawable"><vector android:height="30dp" android:width="30dp" android:viewportHeight="30" android:viewportWidth="30"><group android:name="_R_G"><group android:name="_R_G_L_0_G" android:translateX="28.237000000000002" android:translateY="23.112000000000002"><path android:name="_R_G_L_0_G_D_0_P_0" android:strokeColor="#ffffff" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M-13.24 -12.11 C-11.03,-12.11 -9.24,-10.32 -9.24,-8.11 C-9.24,-5.9 -11.03,-4.11 -13.24,-4.11 C-15.44,-4.11 -17.24,-5.9 -17.24,-8.11 C-17.24,-10.32 -15.44,-12.11 -13.24,-12.11c "/></group></group><group android:name="time_group"/></vector></aapt:attr><target android:name="time_group"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="translateX" android:duration="500" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target></animated-vector>
\ No newline at end of file
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="30dp"
+ android:width="30dp"
+ android:viewportHeight="30"
+ android:viewportWidth="30">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="28.237000000000002"
+ android:translateY="23.112000000000002">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:strokeColor="#ffffff"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2"
+ android:strokeAlpha="1"
+ android:pathData=" M-13.24 -12.11 C-11.03,-12.11 -9.24,-10.32 -9.24,-8.11 C-9.24,-5.9 -11.03,-4.11 -13.24,-4.11 C-15.44,-4.11 -17.24,-5.9 -17.24,-8.11 C-17.24,-10.32 -15.44,-12.11 -13.24,-12.11c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="500"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pin_dot_delete_avd.xml b/packages/SystemUI/res/drawable/pin_dot_delete_avd.xml
index 0f8703f..72a03bf 100644
--- a/packages/SystemUI/res/drawable/pin_dot_delete_avd.xml
+++ b/packages/SystemUI/res/drawable/pin_dot_delete_avd.xml
@@ -1 +1,130 @@
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"><aapt:attr name="android:drawable"><vector android:height="30dp" android:width="30dp" android:viewportHeight="30" android:viewportWidth="30"><group android:name="_R_G"><group android:name="_R_G_L_0_G" android:translateX="28.54" android:translateY="23.54"><path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-13.54 -16.54 C-9.12,-16.54 -5.54,-12.96 -5.54,-8.54 C-5.54,-4.12 -9.12,-0.54 -13.54,-0.54 C-17.96,-0.54 -21.54,-4.12 -21.54,-8.54 C-21.54,-12.96 -17.96,-16.54 -13.54,-16.54c "/><path android:name="_R_G_L_0_G_D_1_P_0" android:strokeColor="#ffffff" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="0" android:strokeAlpha="1" android:pathData=" M-13.54 -16.54 C-9.12,-16.54 -5.54,-12.96 -5.54,-8.54 C-5.54,-4.12 -9.12,-0.54 -13.54,-0.54 C-17.96,-0.54 -21.54,-4.12 -21.54,-8.54 C-21.54,-12.96 -17.96,-16.54 -13.54,-16.54c "/></group></group><group android:name="time_group"/></vector></aapt:attr><target android:name="_R_G_L_0_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="fillAlpha" android:duration="150" android:startOffset="0" android:valueFrom="1" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="fillAlpha" android:duration="200" android:startOffset="150" android:valueFrom="1" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="pathData" android:duration="150" android:startOffset="0" android:valueFrom="M-13.54 -16.54 C-9.12,-16.54 -5.54,-12.96 -5.54,-8.54 C-5.54,-4.12 -9.12,-0.54 -13.54,-0.54 C-17.96,-0.54 -21.54,-4.12 -21.54,-8.54 C-21.54,-12.96 -17.96,-16.54 -13.54,-16.54c " android:valueTo="M-13.54 -11.54 C-11.88,-11.54 -10.54,-10.2 -10.54,-8.54 C-10.54,-6.88 -11.88,-5.54 -13.54,-5.54 C-15.2,-5.54 -16.54,-6.88 -16.54,-8.54 C-16.54,-10.2 -15.2,-11.54 -13.54,-11.54c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="pathData" android:duration="200" android:startOffset="150" android:valueFrom="M-13.54 -11.54 C-11.88,-11.54 -10.54,-10.2 -10.54,-8.54 C-10.54,-6.88 -11.88,-5.54 -13.54,-5.54 C-15.2,-5.54 -16.54,-6.88 -16.54,-8.54 C-16.54,-10.2 -15.2,-11.54 -13.54,-11.54c " android:valueTo="M-13.54 -12.54 C-11.33,-12.54 -9.54,-10.75 -9.54,-8.54 C-9.54,-6.33 -11.33,-4.54 -13.54,-4.54 C-15.75,-4.54 -17.54,-6.33 -17.54,-8.54 C-17.54,-10.75 -15.75,-12.54 -13.54,-12.54c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G_D_1_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="strokeWidth" android:duration="150" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="strokeWidth" android:duration="50" android:startOffset="150" android:valueFrom="0" android:valueTo="2" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G_D_1_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="pathData" android:duration="150" android:startOffset="0" android:valueFrom="M-13.54 -16.54 C-9.12,-16.54 -5.54,-12.96 -5.54,-8.54 C-5.54,-4.12 -9.12,-0.54 -13.54,-0.54 C-17.96,-0.54 -21.54,-4.12 -21.54,-8.54 C-21.54,-12.96 -17.96,-16.54 -13.54,-16.54c " android:valueTo="M-13.54 -11.54 C-11.88,-11.54 -10.54,-10.2 -10.54,-8.54 C-10.54,-6.88 -11.88,-5.54 -13.54,-5.54 C-15.2,-5.54 -16.54,-6.88 -16.54,-8.54 C-16.54,-10.2 -15.2,-11.54 -13.54,-11.54c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="pathData" android:duration="200" android:startOffset="150" android:valueFrom="M-13.54 -11.54 C-11.88,-11.54 -10.54,-10.2 -10.54,-8.54 C-10.54,-6.88 -11.88,-5.54 -13.54,-5.54 C-15.2,-5.54 -16.54,-6.88 -16.54,-8.54 C-16.54,-10.2 -15.2,-11.54 -13.54,-11.54c " android:valueTo="M-13.54 -12.54 C-11.33,-12.54 -9.54,-10.75 -9.54,-8.54 C-9.54,-6.33 -11.33,-4.54 -13.54,-4.54 C-15.75,-4.54 -17.54,-6.33 -17.54,-8.54 C-17.54,-10.75 -15.75,-12.54 -13.54,-12.54c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="time_group"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="translateX" android:duration="500" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target></animated-vector>
\ No newline at end of file
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0.43"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0.43"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="fillAlpha"
+ android:duration="200"
+ android:startOffset="150"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="0.65"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="0.65"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="500"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="30dp"
+ android:height="30dp"
+ android:viewportHeight="30"
+ android:viewportWidth="30">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="-13.54"
+ android:pivotY="-8.54"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="28.54"
+ android:translateY="23.54">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-13.54 -16.54 C-9.12,-16.54 -5.54,-12.96 -5.54,-8.54 C-5.54,-4.12 -9.12,-0.54 -13.54,-0.54 C-17.96,-0.54 -21.54,-4.12 -21.54,-8.54 C-21.54,-12.96 -17.96,-16.54 -13.54,-16.54c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="317.509"
+ android:pivotY="-826.986"
+ android:scaleX="0.65"
+ android:scaleY="0.65"
+ android:translateX="-302.509"
+ android:translateY="841.986">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M317.51 -821.99 C314.75,-821.99 312.51,-824.23 312.51,-826.99 C312.51,-829.74 314.75,-831.99 317.51,-831.99 C320.27,-831.99 322.51,-829.74 322.51,-826.99 C322.51,-824.23 320.27,-821.99 317.51,-821.99z M317.51 -829.99 C315.86,-829.99 314.51,-828.64 314.51,-826.99 C314.51,-825.33 315.86,-823.99 317.51,-823.99 C319.16,-823.99 320.51,-825.33 320.51,-826.99 C320.51,-828.64 319.16,-829.99 317.51,-829.99z " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pin_dot_shape_1_avd.xml b/packages/SystemUI/res/drawable/pin_dot_shape_1_avd.xml
index f1fb2aa..02abb99 100644
--- a/packages/SystemUI/res/drawable/pin_dot_shape_1_avd.xml
+++ b/packages/SystemUI/res/drawable/pin_dot_shape_1_avd.xml
@@ -1 +1,141 @@
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"><aapt:attr name="android:drawable"><vector android:height="30dp" android:width="30dp" android:viewportHeight="30" android:viewportWidth="30"><group android:name="_R_G"><group android:name="_R_G_L_1_G" android:translateX="15.441" android:translateY="15.691" android:scaleY="0"><path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-0.44 -12.06 C13.5,-14.63 13.5,-14.63 10.9,-0.69 C13.5,13.25 13.5,13.25 -0.44,10.53 C-14.38,13.25 -14.38,13.25 -11.86,-0.69 C-14.38,-14.63 -14.38,-14.63 -0.44,-12.06c "/></group><group android:name="_R_G_L_0_G" android:translateX="15" android:translateY="15" android:scaleX="0" android:scaleY="0"><path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-13.65 -3.95 C-16.31,-10.09 -10.09,-16.31 -3.95,-13.65 C-3.95,-13.65 -2.94,-13.21 -2.94,-13.21 C-1.06,-12.39 1.06,-12.39 2.94,-13.21 C2.94,-13.21 3.95,-13.65 3.95,-13.65 C10.09,-16.31 16.31,-10.09 13.65,-3.95 C13.65,-3.95 13.21,-2.94 13.21,-2.94 C12.39,-1.06 12.39,1.06 13.21,2.94 C13.21,2.94 13.65,3.95 13.65,3.95 C16.31,10.09 10.09,16.31 3.95,13.65 C3.95,13.65 2.94,13.21 2.94,13.21 C1.06,12.39 -1.06,12.39 -2.94,13.21 C-2.94,13.21 -3.95,13.65 -3.95,13.65 C-10.09,16.31 -16.31,10.09 -13.65,3.95 C-13.65,3.95 -13.21,2.94 -13.21,2.94 C-12.39,1.06 -12.39,-1.06 -13.21,-2.94 C-13.21,-2.94 -13.65,-3.95 -13.65,-3.95c "/></group></group><group android:name="time_group"/></vector></aapt:attr><target android:name="_R_G_L_1_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="pathData" android:duration="67" android:startOffset="0" android:valueFrom="M-0.44 -12.06 C13.5,-14.63 13.5,-14.63 10.9,-0.69 C13.5,13.25 13.5,13.25 -0.44,10.53 C-14.38,13.25 -14.38,13.25 -11.86,-0.69 C-14.38,-14.63 -14.38,-14.63 -0.44,-12.06c " android:valueTo="M-0.44 -12.06 C13.5,-14.63 13.5,-14.63 10.9,-0.69 C13.5,13.25 13.5,13.25 -0.44,10.53 C-14.38,13.25 -14.38,13.25 -11.86,-0.69 C-14.38,-14.63 -14.38,-14.63 -0.44,-12.06c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="pathData" android:duration="283" android:startOffset="67" android:valueFrom="M-0.44 -12.06 C13.5,-14.63 13.5,-14.63 10.9,-0.69 C13.5,13.25 13.5,13.25 -0.44,10.53 C-14.38,13.25 -14.38,13.25 -11.86,-0.69 C-14.38,-14.63 -14.38,-14.63 -0.44,-12.06c " android:valueTo="M-0.44 -8.69 C3.98,-8.69 7.56,-5.11 7.56,-0.69 C7.56,3.73 3.98,7.31 -0.44,7.31 C-4.86,7.31 -8.44,3.73 -8.44,-0.69 C-8.44,-5.11 -4.86,-8.69 -0.44,-8.69c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_1_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="67" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleX" android:duration="67" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="67" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleX" android:duration="283" android:startOffset="67" android:valueFrom="1" android:valueTo="0.3" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.6,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="283" android:startOffset="67" android:valueFrom="1" android:valueTo="0.3" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.6,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="367" android:valueFrom="1" android:valueTo="0" android:valueType="floatType"/></set></aapt:attr></target><target android:name="time_group"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="translateX" android:duration="500" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target></animated-vector>
\ No newline at end of file
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M-0.44 -12.06 C13.5,-14.63 13.5,-14.63 10.9,-0.69 C13.5,13.25 13.5,13.25 -0.44,10.53 C-14.38,13.25 -14.38,13.25 -11.86,-0.69 C-14.38,-14.63 -14.38,-14.63 -0.44,-12.06c "
+ android:valueTo="M-0.44 -12.06 C13.5,-14.63 13.5,-14.63 10.9,-0.69 C13.5,13.25 13.5,13.25 -0.44,10.53 C-14.38,13.25 -14.38,13.25 -11.86,-0.69 C-14.38,-14.63 -14.38,-14.63 -0.44,-12.06c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="283"
+ android:propertyName="pathData"
+ android:startOffset="67"
+ android:valueFrom="M-0.44 -12.06 C13.5,-14.63 13.5,-14.63 10.9,-0.69 C13.5,13.25 13.5,13.25 -0.44,10.53 C-14.38,13.25 -14.38,13.25 -11.86,-0.69 C-14.38,-14.63 -14.38,-14.63 -0.44,-12.06c "
+ android:valueTo="M-0.44 -8.69 C3.98,-8.69 7.56,-5.11 7.56,-0.69 C7.56,3.73 3.98,7.31 -0.44,7.31 C-4.86,7.31 -8.44,3.73 -8.44,-0.69 C-8.44,-5.11 -4.86,-8.69 -0.44,-8.69c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="0"
+ android:propertyName="scaleY"
+ android:startOffset="67"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="283"
+ android:propertyName="scaleX"
+ android:startOffset="67"
+ android:valueFrom="1"
+ android:valueTo="0.3"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.6,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="283"
+ android:propertyName="scaleY"
+ android:startOffset="67"
+ android:valueFrom="1"
+ android:valueTo="0.3"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.6,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="500"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="30dp"
+ android:height="30dp"
+ android:viewportHeight="30"
+ android:viewportWidth="30">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:scaleY="0"
+ android:translateX="15.441"
+ android:translateY="15.691">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-0.44 -12.06 C13.5,-14.63 13.5,-14.63 10.9,-0.69 C13.5,13.25 13.5,13.25 -0.44,10.53 C-14.38,13.25 -14.38,13.25 -11.86,-0.69 C-14.38,-14.63 -14.38,-14.63 -0.44,-12.06c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="15"
+ android:translateY="15">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-13.65 -3.95 C-16.31,-10.09 -10.09,-16.31 -3.95,-13.65 C-3.95,-13.65 -2.94,-13.21 -2.94,-13.21 C-1.06,-12.39 1.06,-12.39 2.94,-13.21 C2.94,-13.21 3.95,-13.65 3.95,-13.65 C10.09,-16.31 16.31,-10.09 13.65,-3.95 C13.65,-3.95 13.21,-2.94 13.21,-2.94 C12.39,-1.06 12.39,1.06 13.21,2.94 C13.21,2.94 13.65,3.95 13.65,3.95 C16.31,10.09 10.09,16.31 3.95,13.65 C3.95,13.65 2.94,13.21 2.94,13.21 C1.06,12.39 -1.06,12.39 -2.94,13.21 C-2.94,13.21 -3.95,13.65 -3.95,13.65 C-10.09,16.31 -16.31,10.09 -13.65,3.95 C-13.65,3.95 -13.21,2.94 -13.21,2.94 C-12.39,1.06 -12.39,-1.06 -13.21,-2.94 C-13.21,-2.94 -13.65,-3.95 -13.65,-3.95c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pin_dot_shape_2_avd.xml b/packages/SystemUI/res/drawable/pin_dot_shape_2_avd.xml
index 3717db8..1607327 100644
--- a/packages/SystemUI/res/drawable/pin_dot_shape_2_avd.xml
+++ b/packages/SystemUI/res/drawable/pin_dot_shape_2_avd.xml
@@ -1 +1,148 @@
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"><aapt:attr name="android:drawable"><vector android:height="30dp" android:width="30dp" android:viewportHeight="30" android:viewportWidth="30"><group android:name="_R_G"><group android:name="_R_G_L_1_G" android:translateX="15.397" android:translateY="15.691" android:scaleY="0"><path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-0.56 -14.03 C3.65,-13.99 14.58,7.64 11.51,10.42 C8.45,13.2 5.92,9.56 -0.46,9.61 C-6.85,9.65 -9.27,12.76 -12.33,10.46 C-15.39,8.15 -4.77,-14.07 -0.56,-14.03c "/></group><group android:name="_R_G_L_0_G" android:translateX="15" android:translateY="13.205" android:pivotY="1.795" android:scaleX="0" android:scaleY="0"><path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M12.78 7.57 C12.78,7.57 4.72,-8.55 4.72,-8.55 C2.77,-12.44 -2.77,-12.44 -4.72,-8.55 C-4.72,-8.55 -12.78,7.57 -12.78,7.57 C-15,12.01 -10.42,16.78 -5.89,14.74 C-5.89,14.74 -2.17,13.07 -2.17,13.07 C-0.79,12.45 0.79,12.45 2.17,13.07 C2.17,13.07 5.9,14.74 5.9,14.74 C10.42,16.78 15,12.01 12.78,7.57c "/></group></group><group android:name="time_group"/></vector></aapt:attr><target android:name="_R_G_L_1_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="pathData" android:duration="67" android:startOffset="0" android:valueFrom="M-0.56 -14.03 C3.65,-13.99 14.58,7.64 11.51,10.42 C8.45,13.2 5.92,9.56 -0.46,9.61 C-6.85,9.65 -9.27,12.76 -12.33,10.46 C-15.39,8.15 -4.77,-14.07 -0.56,-14.03c " android:valueTo="M-0.56 -14.03 C3.65,-13.99 14.58,7.64 11.51,10.42 C8.45,13.2 5.92,9.56 -0.46,9.61 C-6.85,9.65 -9.27,12.76 -12.33,10.46 C-15.39,8.15 -4.77,-14.07 -0.56,-14.03c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="pathData" android:duration="283" android:startOffset="67" android:valueFrom="M-0.56 -14.03 C3.65,-13.99 14.58,7.64 11.51,10.42 C8.45,13.2 5.92,9.56 -0.46,9.61 C-6.85,9.65 -9.27,12.76 -12.33,10.46 C-15.39,8.15 -4.77,-14.07 -0.56,-14.03c " android:valueTo="M-0.44 -8.69 C3.98,-8.69 7.56,-5.11 7.56,-0.69 C7.56,3.73 3.98,7.31 -0.44,7.31 C-4.86,7.31 -8.44,3.73 -8.44,-0.69 C-8.44,-5.11 -4.86,-8.69 -0.44,-8.69c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_1_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="67" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target><target android:name="_R_G_L_0_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="pathData" android:duration="67" android:startOffset="0" android:valueFrom="M12.78 7.57 C12.78,7.57 4.72,-8.55 4.72,-8.55 C2.77,-12.44 -2.77,-12.44 -4.72,-8.55 C-4.72,-8.55 -12.78,7.57 -12.78,7.57 C-15,12.01 -10.42,16.78 -5.89,14.74 C-5.89,14.74 -2.17,13.07 -2.17,13.07 C-0.79,12.45 0.79,12.45 2.17,13.07 C2.17,13.07 5.9,14.74 5.9,14.74 C10.42,16.78 15,12.01 12.78,7.57c " android:valueTo="M12.78 7.57 C12.78,7.57 4.72,-8.55 4.72,-8.55 C2.77,-12.44 -2.77,-12.44 -4.72,-8.55 C-4.72,-8.55 -12.78,7.57 -12.78,7.57 C-15,12.01 -10.42,16.78 -5.89,14.74 C-5.89,14.74 -2.17,13.07 -2.17,13.07 C-0.79,12.45 0.79,12.45 2.17,13.07 C2.17,13.07 5.9,14.74 5.9,14.74 C10.42,16.78 15,12.01 12.78,7.57c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.833,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="pathData" android:duration="283" android:startOffset="67" android:valueFrom="M12.78 7.57 C12.78,7.57 4.72,-8.55 4.72,-8.55 C2.77,-12.44 -2.77,-12.44 -4.72,-8.55 C-4.72,-8.55 -12.78,7.57 -12.78,7.57 C-15,12.01 -10.42,16.78 -5.89,14.74 C-5.89,14.74 -2.17,13.07 -2.17,13.07 C-0.79,12.45 0.79,12.45 2.17,13.07 C2.17,13.07 5.9,14.74 5.9,14.74 C10.42,16.78 15,12.01 12.78,7.57c " android:valueTo="M6.12 0.21 C6.12,0.21 2.27,-4.35 2.27,-4.35 C1.34,-6.2 -1.3,-6.2 -2.23,-4.35 C-2.23,-4.35 -6.06,0.21 -6.06,0.21 C-7.12,2.33 -5.46,5.79 -4.03,6.54 C-2.28,7.45 -1.01,7.48 -1.01,7.48 C-1.01,7.48 1.05,7.48 1.05,7.48 C1.05,7.48 3.28,7.36 4.23,6.66 C4.92,6.15 7.18,2.33 6.12,0.21c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.833,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleX" android:duration="67" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="67" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="367" android:valueFrom="1" android:valueTo="0" android:valueType="floatType"/></set></aapt:attr></target><target android:name="time_group"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="translateX" android:duration="500" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target></animated-vector>
\ No newline at end of file
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="30dp"
+ android:width="30dp"
+ android:viewportHeight="30"
+ android:viewportWidth="30">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="15.397"
+ android:translateY="15.691"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M-0.56 -14.03 C3.65,-13.99 14.58,7.64 11.51,10.42 C8.45,13.2 5.92,9.56 -0.46,9.61 C-6.85,9.65 -9.27,12.76 -12.33,10.46 C-15.39,8.15 -4.77,-14.07 -0.56,-14.03c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="15"
+ android:translateY="13.205"
+ android:pivotY="1.795">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M12.78 7.57 C12.78,7.57 4.72,-8.55 4.72,-8.55 C2.77,-12.44 -2.77,-12.44 -4.72,-8.55 C-4.72,-8.55 -12.78,7.57 -12.78,7.57 C-15,12.01 -10.42,16.78 -5.89,14.74 C-5.89,14.74 -2.17,13.07 -2.17,13.07 C-0.79,12.45 0.79,12.45 2.17,13.07 C2.17,13.07 5.9,14.74 5.9,14.74 C10.42,16.78 15,12.01 12.78,7.57c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="67"
+ android:startOffset="0"
+ android:valueFrom="M-0.56 -14.03 C3.65,-13.99 14.58,7.64 11.51,10.42 C8.45,13.2 5.92,9.56 -0.46,9.61 C-6.85,9.65 -9.27,12.76 -12.33,10.46 C-15.39,8.15 -4.77,-14.07 -0.56,-14.03c "
+ android:valueTo="M-0.56 -14.03 C3.65,-13.99 14.58,7.64 11.51,10.42 C8.45,13.2 5.92,9.56 -0.46,9.61 C-6.85,9.65 -9.27,12.76 -12.33,10.46 C-15.39,8.15 -4.77,-14.07 -0.56,-14.03c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="283"
+ android:startOffset="67"
+ android:valueFrom="M-0.56 -14.03 C3.65,-13.99 14.58,7.64 11.51,10.42 C8.45,13.2 5.92,9.56 -0.46,9.61 C-6.85,9.65 -9.27,12.76 -12.33,10.46 C-15.39,8.15 -4.77,-14.07 -0.56,-14.03c "
+ android:valueTo="M-0.44 -8.69 C3.98,-8.69 7.56,-5.11 7.56,-0.69 C7.56,3.73 3.98,7.31 -0.44,7.31 C-4.86,7.31 -8.44,3.73 -8.44,-0.69 C-8.44,-5.11 -4.86,-8.69 -0.44,-8.69c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="0"
+ android:startOffset="67"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="67"
+ android:startOffset="0"
+ android:valueFrom="M12.78 7.57 C12.78,7.57 4.72,-8.55 4.72,-8.55 C2.77,-12.44 -2.77,-12.44 -4.72,-8.55 C-4.72,-8.55 -12.78,7.57 -12.78,7.57 C-15,12.01 -10.42,16.78 -5.89,14.74 C-5.89,14.74 -2.17,13.07 -2.17,13.07 C-0.79,12.45 0.79,12.45 2.17,13.07 C2.17,13.07 5.9,14.74 5.9,14.74 C10.42,16.78 15,12.01 12.78,7.57c "
+ android:valueTo="M12.78 7.57 C12.78,7.57 4.72,-8.55 4.72,-8.55 C2.77,-12.44 -2.77,-12.44 -4.72,-8.55 C-4.72,-8.55 -12.78,7.57 -12.78,7.57 C-15,12.01 -10.42,16.78 -5.89,14.74 C-5.89,14.74 -2.17,13.07 -2.17,13.07 C-0.79,12.45 0.79,12.45 2.17,13.07 C2.17,13.07 5.9,14.74 5.9,14.74 C10.42,16.78 15,12.01 12.78,7.57c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="283"
+ android:startOffset="67"
+ android:valueFrom="M12.78 7.57 C12.78,7.57 4.72,-8.55 4.72,-8.55 C2.77,-12.44 -2.77,-12.44 -4.72,-8.55 C-4.72,-8.55 -12.78,7.57 -12.78,7.57 C-15,12.01 -10.42,16.78 -5.89,14.74 C-5.89,14.74 -2.17,13.07 -2.17,13.07 C-0.79,12.45 0.79,12.45 2.17,13.07 C2.17,13.07 5.9,14.74 5.9,14.74 C10.42,16.78 15,12.01 12.78,7.57c "
+ android:valueTo="M6.12 0.21 C6.12,0.21 2.27,-4.35 2.27,-4.35 C1.34,-6.2 -1.3,-6.2 -2.23,-4.35 C-2.23,-4.35 -6.06,0.21 -6.06,0.21 C-7.12,2.33 -5.46,5.79 -4.03,6.54 C-2.28,7.45 -1.01,7.48 -1.01,7.48 C-1.01,7.48 1.05,7.48 1.05,7.48 C1.05,7.48 3.28,7.36 4.23,6.66 C4.92,6.15 7.18,2.33 6.12,0.21c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="67"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="67"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="500"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pin_dot_shape_3_avd.xml b/packages/SystemUI/res/drawable/pin_dot_shape_3_avd.xml
index 95b8044..78e2249 100644
--- a/packages/SystemUI/res/drawable/pin_dot_shape_3_avd.xml
+++ b/packages/SystemUI/res/drawable/pin_dot_shape_3_avd.xml
@@ -1 +1,141 @@
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"><aapt:attr name="android:drawable"><vector android:height="30dp" android:width="30dp" android:viewportHeight="30" android:viewportWidth="30"><group android:name="_R_G"><group android:name="_R_G_L_1_G" android:translateX="15.441" android:translateY="15.691" android:scaleY="0"><path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-10.2 -11.16 C-1.58,-18.94 4.25,-12.72 8.06,-8.64 C11.88,-4.57 17.93,1.89 9.39,9.74 C0.85,17.6 -5.06,11.3 -8.87,7.22 C-12.69,3.14 -18.81,-3.39 -10.2,-11.16c "/></group><group android:name="_R_G_L_0_G" android:translateX="15" android:translateY="15" android:scaleX="0" android:scaleY="0"><path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M10.71 10.71 C5.92,15.5 -1.85,15.5 -6.64,10.71 C-6.64,10.71 -10.71,6.64 -10.71,6.64 C-15.5,1.85 -15.5,-5.92 -10.71,-10.71 C-5.92,-15.5 1.85,-15.5 6.64,-10.71 C6.64,-10.71 10.71,-6.64 10.71,-6.64 C15.5,-1.85 15.5,5.92 10.71,10.71c "/></group></group><group android:name="time_group"/></vector></aapt:attr><target android:name="_R_G_L_1_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="pathData" android:duration="67" android:startOffset="0" android:valueFrom="M-10.2 -11.16 C-1.58,-18.94 4.25,-12.72 8.06,-8.64 C11.88,-4.57 17.93,1.89 9.39,9.74 C0.85,17.6 -5.06,11.3 -8.87,7.22 C-12.69,3.14 -18.81,-3.39 -10.2,-11.16c " android:valueTo="M-10.2 -11.16 C-1.58,-18.94 4.25,-12.72 8.06,-8.64 C11.88,-4.57 17.93,1.89 9.39,9.74 C0.85,17.6 -5.06,11.3 -8.87,7.22 C-12.69,3.14 -18.81,-3.39 -10.2,-11.16c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="pathData" android:duration="283" android:startOffset="67" android:valueFrom="M-10.2 -11.16 C-1.58,-18.94 4.25,-12.72 8.06,-8.64 C11.88,-4.57 17.93,1.89 9.39,9.74 C0.85,17.6 -5.06,11.3 -8.87,7.22 C-12.69,3.14 -18.81,-3.39 -10.2,-11.16c " android:valueTo="M-0.44 -8.69 C3.98,-8.69 7.56,-5.11 7.56,-0.69 C7.56,3.73 3.98,7.31 -0.44,7.31 C-4.86,7.31 -8.44,3.73 -8.44,-0.69 C-8.44,-5.11 -4.86,-8.69 -0.44,-8.69c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_1_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="67" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleX" android:duration="67" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="67" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleX" android:duration="283" android:startOffset="67" android:valueFrom="1" android:valueTo="0.4" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.6,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="283" android:startOffset="67" android:valueFrom="1" android:valueTo="0.4" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.6,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="367" android:valueFrom="1" android:valueTo="0" android:valueType="floatType"/></set></aapt:attr></target><target android:name="time_group"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="translateX" android:duration="500" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target></animated-vector>
\ No newline at end of file
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="30dp"
+ android:width="30dp"
+ android:viewportHeight="30"
+ android:viewportWidth="30">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="15.441"
+ android:translateY="15.691"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M-10.2 -11.16 C-1.58,-18.94 4.25,-12.72 8.06,-8.64 C11.88,-4.57 17.93,1.89 9.39,9.74 C0.85,17.6 -5.06,11.3 -8.87,7.22 C-12.69,3.14 -18.81,-3.39 -10.2,-11.16c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="15"
+ android:translateY="15">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M10.71 10.71 C5.92,15.5 -1.85,15.5 -6.64,10.71 C-6.64,10.71 -10.71,6.64 -10.71,6.64 C-15.5,1.85 -15.5,-5.92 -10.71,-10.71 C-5.92,-15.5 1.85,-15.5 6.64,-10.71 C6.64,-10.71 10.71,-6.64 10.71,-6.64 C15.5,-1.85 15.5,5.92 10.71,10.71c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="67"
+ android:startOffset="0"
+ android:valueFrom="M-10.2 -11.16 C-1.58,-18.94 4.25,-12.72 8.06,-8.64 C11.88,-4.57 17.93,1.89 9.39,9.74 C0.85,17.6 -5.06,11.3 -8.87,7.22 C-12.69,3.14 -18.81,-3.39 -10.2,-11.16c "
+ android:valueTo="M-10.2 -11.16 C-1.58,-18.94 4.25,-12.72 8.06,-8.64 C11.88,-4.57 17.93,1.89 9.39,9.74 C0.85,17.6 -5.06,11.3 -8.87,7.22 C-12.69,3.14 -18.81,-3.39 -10.2,-11.16c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="283"
+ android:startOffset="67"
+ android:valueFrom="M-10.2 -11.16 C-1.58,-18.94 4.25,-12.72 8.06,-8.64 C11.88,-4.57 17.93,1.89 9.39,9.74 C0.85,17.6 -5.06,11.3 -8.87,7.22 C-12.69,3.14 -18.81,-3.39 -10.2,-11.16c "
+ android:valueTo="M-0.44 -8.69 C3.98,-8.69 7.56,-5.11 7.56,-0.69 C7.56,3.73 3.98,7.31 -0.44,7.31 C-4.86,7.31 -8.44,3.73 -8.44,-0.69 C-8.44,-5.11 -4.86,-8.69 -0.44,-8.69c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="0"
+ android:startOffset="67"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="67"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="67"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="283"
+ android:startOffset="67"
+ android:valueFrom="1"
+ android:valueTo="0.4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.6,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="283"
+ android:startOffset="67"
+ android:valueFrom="1"
+ android:valueTo="0.4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.6,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="500"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pin_dot_shape_4_avd.xml b/packages/SystemUI/res/drawable/pin_dot_shape_4_avd.xml
index 8ea8f85..35c7210 100644
--- a/packages/SystemUI/res/drawable/pin_dot_shape_4_avd.xml
+++ b/packages/SystemUI/res/drawable/pin_dot_shape_4_avd.xml
@@ -1 +1,119 @@
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"><aapt:attr name="android:drawable"><vector android:height="30dp" android:width="30dp" android:viewportHeight="30" android:viewportWidth="30"><group android:name="_R_G"><group android:name="_R_G_L_1_G" android:translateX="15.441" android:translateY="15.691" android:scaleY="0"><path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-0.44 -8.69 C3.97,-8.69 7.56,-5.11 7.56,-0.69 C7.56,3.72 3.97,7.31 -0.44,7.31 C-4.86,7.31 -8.44,3.72 -8.44,-0.69 C-8.44,-5.11 -4.86,-8.69 -0.44,-8.69c "/></group><group android:name="_R_G_L_0_G" android:translateX="15" android:translateY="15" android:scaleX="0" android:scaleY="0"><path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M8 0 C8,-1.35 7.97,-1.94 7.41,-3.02 C6.85,-4.09 6.61,-4.79 5.66,-5.66 C4.7,-6.52 4.2,-6.97 3.15,-7.36 C2.09,-7.74 1.39,-8 0,-8 C-1.39,-8 -2.18,-7.78 -3.12,-7.37 C-4.07,-6.96 -4.67,-6.63 -5.66,-5.66 C-6.64,-4.68 -6.98,-4.1 -7.37,-3.13 C-7.78,-2.08 -8,-1.39 -8,0 C-8,1.4 -7.86,1.98 -7.47,2.87 C-7.08,3.76 -6.68,4.66 -5.66,5.66 C-4.63,6.65 -4,6.96 -3.12,7.37 C-2.25,7.78 -1.32,8 0,8 C1.32,8 1.86,7.88 2.9,7.46 C3.95,7.03 4.85,6.63 5.66,5.66 C6.46,4.69 6.78,4.45 7.29,3.29 C7.81,2.14 8,1.35 8,0c "/></group></group><group android:name="time_group"/></vector></aapt:attr><target android:name="_R_G_L_1_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="67" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target><target android:name="_R_G_L_0_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="pathData" android:duration="67" android:startOffset="0" android:valueFrom="M8 0 C8,-1.35 7.97,-1.94 7.41,-3.02 C6.85,-4.09 6.61,-4.79 5.66,-5.66 C4.7,-6.52 4.2,-6.97 3.15,-7.36 C2.09,-7.74 1.39,-8 0,-8 C-1.39,-8 -2.18,-7.78 -3.12,-7.37 C-4.07,-6.96 -4.67,-6.63 -5.66,-5.66 C-6.64,-4.68 -6.98,-4.1 -7.37,-3.13 C-7.78,-2.08 -8,-1.39 -8,0 C-8,1.4 -7.86,1.98 -7.47,2.87 C-7.08,3.76 -6.68,4.66 -5.66,5.66 C-4.63,6.65 -4,6.96 -3.12,7.37 C-2.25,7.78 -1.32,8 0,8 C1.32,8 1.86,7.88 2.9,7.46 C3.95,7.03 4.85,6.63 5.66,5.66 C6.46,4.69 6.78,4.45 7.29,3.29 C7.81,2.14 8,1.35 8,0c " android:valueTo="M15 0 C15,-2.52 11.99,-2.3 10.94,-4.32 C9.89,-6.33 12.4,-8.98 10.61,-10.61 C8.82,-12.23 6.44,-10.15 4.46,-10.86 C2.48,-11.58 2.61,-15 0,-15 C-2.61,-15 -2.68,-11.61 -4.46,-10.84 C-6.23,-10.08 -8.76,-12.44 -10.61,-10.61 C-12.45,-8.78 -10.31,-6.69 -10.87,-4.64 C-11.43,-2.61 -15,-2.61 -15,0 C-15,2.62 -11.67,2.75 -10.94,4.42 C-10.21,6.08 -12.53,8.74 -10.61,10.61 C-8.68,12.47 -6.18,10.19 -4.54,10.96 C-2.89,11.72 -2.48,15 0,15 C2.48,15 2.49,11.78 4.45,10.99 C6.4,10.19 9.09,12.43 10.61,10.61 C12.12,8.79 10,6.52 10.97,4.36 C11.94,2.2 15,2.52 15,0c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="pathData" android:duration="283" android:startOffset="67" android:valueFrom="M15 0 C15,-2.52 11.99,-2.3 10.94,-4.32 C9.89,-6.33 12.4,-8.98 10.61,-10.61 C8.82,-12.23 6.44,-10.15 4.46,-10.86 C2.48,-11.58 2.61,-15 0,-15 C-2.61,-15 -2.68,-11.61 -4.46,-10.84 C-6.23,-10.08 -8.76,-12.44 -10.61,-10.61 C-12.45,-8.78 -10.31,-6.69 -10.87,-4.64 C-11.43,-2.61 -15,-2.61 -15,0 C-15,2.62 -11.67,2.75 -10.94,4.42 C-10.21,6.08 -12.53,8.74 -10.61,10.61 C-8.68,12.47 -6.18,10.19 -4.54,10.96 C-2.89,11.72 -2.48,15 0,15 C2.48,15 2.49,11.78 4.45,10.99 C6.4,10.19 9.09,12.43 10.61,10.61 C12.12,8.79 10,6.52 10.97,4.36 C11.94,2.2 15,2.52 15,0c " android:valueTo="M7.73 0 C7.73,-1.3 7.71,-1.88 7.16,-2.92 C6.62,-3.95 6.39,-4.63 5.47,-5.47 C4.55,-6.31 4.06,-6.74 3.04,-7.11 C2.02,-7.48 1.35,-7.73 0,-7.73 C-1.34,-7.73 -2.1,-7.52 -3.02,-7.12 C-3.93,-6.73 -4.52,-6.41 -5.47,-5.47 C-6.42,-4.53 -6.75,-3.96 -7.12,-3.02 C-7.52,-2.01 -7.73,-1.35 -7.73,0 C-7.73,1.35 -7.6,1.91 -7.22,2.77 C-6.85,3.63 -6.46,4.51 -5.47,5.47 C-4.48,6.43 -3.87,6.73 -3.02,7.12 C-2.17,7.52 -1.28,7.73 0,7.73 C1.28,7.73 1.8,7.62 2.81,7.21 C3.81,6.8 4.69,6.41 5.47,5.47 C6.25,4.53 6.55,4.3 7.05,3.19 C7.55,2.07 7.73,1.3 7.73,0c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.7,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleX" android:duration="67" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="67" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="367" android:valueFrom="1" android:valueTo="0" android:valueType="floatType"/></set></aapt:attr></target><target android:name="time_group"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="translateX" android:duration="500" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target></animated-vector>
\ No newline at end of file
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="0"
+ android:propertyName="scaleY"
+ android:startOffset="67"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M8 0 C8,-1.35 7.97,-1.94 7.41,-3.02 C6.85,-4.09 6.61,-4.79 5.66,-5.66 C4.7,-6.52 4.2,-6.97 3.15,-7.36 C2.09,-7.74 1.39,-8 0,-8 C-1.39,-8 -2.18,-7.78 -3.12,-7.37 C-4.07,-6.96 -4.67,-6.63 -5.66,-5.66 C-6.64,-4.68 -6.98,-4.1 -7.37,-3.13 C-7.78,-2.08 -8,-1.39 -8,0 C-8,1.4 -7.86,1.98 -7.47,2.87 C-7.08,3.76 -6.68,4.66 -5.66,5.66 C-4.63,6.65 -4,6.96 -3.12,7.37 C-2.25,7.78 -1.32,8 0,8 C1.32,8 1.86,7.88 2.9,7.46 C3.95,7.03 4.85,6.63 5.66,5.66 C6.46,4.69 6.78,4.45 7.29,3.29 C7.81,2.14 8,1.35 8,0c "
+ android:valueTo="M15 0 C15,-2.52 11.99,-2.3 10.94,-4.32 C9.89,-6.33 12.4,-8.98 10.61,-10.61 C8.82,-12.23 6.44,-10.15 4.46,-10.86 C2.48,-11.58 2.61,-15 0,-15 C-2.61,-15 -2.68,-11.61 -4.46,-10.84 C-6.23,-10.08 -8.76,-12.44 -10.61,-10.61 C-12.45,-8.78 -10.31,-6.69 -10.87,-4.64 C-11.43,-2.61 -15,-2.61 -15,0 C-15,2.62 -11.67,2.75 -10.94,4.42 C-10.21,6.08 -12.53,8.74 -10.61,10.61 C-8.68,12.47 -6.18,10.19 -4.54,10.96 C-2.89,11.72 -2.48,15 0,15 C2.48,15 2.49,11.78 4.45,10.99 C6.4,10.19 9.09,12.43 10.61,10.61 C12.12,8.79 10,6.52 10.97,4.36 C11.94,2.2 15,2.52 15,0c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="283"
+ android:propertyName="pathData"
+ android:startOffset="67"
+ android:valueFrom="M15 0 C15,-2.52 11.99,-2.3 10.94,-4.32 C9.89,-6.33 12.4,-8.98 10.61,-10.61 C8.82,-12.23 6.44,-10.15 4.46,-10.86 C2.48,-11.58 2.61,-15 0,-15 C-2.61,-15 -2.68,-11.61 -4.46,-10.84 C-6.23,-10.08 -8.76,-12.44 -10.61,-10.61 C-12.45,-8.78 -10.31,-6.69 -10.87,-4.64 C-11.43,-2.61 -15,-2.61 -15,0 C-15,2.62 -11.67,2.75 -10.94,4.42 C-10.21,6.08 -12.53,8.74 -10.61,10.61 C-8.68,12.47 -6.18,10.19 -4.54,10.96 C-2.89,11.72 -2.48,15 0,15 C2.48,15 2.49,11.78 4.45,10.99 C6.4,10.19 9.09,12.43 10.61,10.61 C12.12,8.79 10,6.52 10.97,4.36 C11.94,2.2 15,2.52 15,0c "
+ android:valueTo="M7.73 0 C7.73,-1.3 7.71,-1.88 7.16,-2.92 C6.62,-3.95 6.39,-4.63 5.47,-5.47 C4.55,-6.31 4.06,-6.74 3.04,-7.11 C2.02,-7.48 1.35,-7.73 0,-7.73 C-1.34,-7.73 -2.1,-7.52 -3.02,-7.12 C-3.93,-6.73 -4.52,-6.41 -5.47,-5.47 C-6.42,-4.53 -6.75,-3.96 -7.12,-3.02 C-7.52,-2.01 -7.73,-1.35 -7.73,0 C-7.73,1.35 -7.6,1.91 -7.22,2.77 C-6.85,3.63 -6.46,4.51 -5.47,5.47 C-4.48,6.43 -3.87,6.73 -3.02,7.12 C-2.17,7.52 -1.28,7.73 0,7.73 C1.28,7.73 1.8,7.62 2.81,7.21 C3.81,6.8 4.69,6.41 5.47,5.47 C6.25,4.53 6.55,4.3 7.05,3.19 C7.55,2.07 7.73,1.3 7.73,0c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.7,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="500"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="30dp"
+ android:height="30dp"
+ android:viewportHeight="30"
+ android:viewportWidth="30">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:scaleY="0"
+ android:translateX="15.441"
+ android:translateY="15.691">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-0.44 -8.69 C3.97,-8.69 7.56,-5.11 7.56,-0.69 C7.56,3.72 3.97,7.31 -0.44,7.31 C-4.86,7.31 -8.44,3.72 -8.44,-0.69 C-8.44,-5.11 -4.86,-8.69 -0.44,-8.69c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="15"
+ android:translateY="15">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C8,-1.35 7.97,-1.94 7.41,-3.02 C6.85,-4.09 6.61,-4.79 5.66,-5.66 C4.7,-6.52 4.2,-6.97 3.15,-7.36 C2.09,-7.74 1.39,-8 0,-8 C-1.39,-8 -2.18,-7.78 -3.12,-7.37 C-4.07,-6.96 -4.67,-6.63 -5.66,-5.66 C-6.64,-4.68 -6.98,-4.1 -7.37,-3.13 C-7.78,-2.08 -8,-1.39 -8,0 C-8,1.4 -7.86,1.98 -7.47,2.87 C-7.08,3.76 -6.68,4.66 -5.66,5.66 C-4.63,6.65 -4,6.96 -3.12,7.37 C-2.25,7.78 -1.32,8 0,8 C1.32,8 1.86,7.88 2.9,7.46 C3.95,7.03 4.85,6.63 5.66,5.66 C6.46,4.69 6.78,4.45 7.29,3.29 C7.81,2.14 8,1.35 8,0c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pin_dot_shape_5_avd.xml b/packages/SystemUI/res/drawable/pin_dot_shape_5_avd.xml
index 3779c80..9458b2e 100644
--- a/packages/SystemUI/res/drawable/pin_dot_shape_5_avd.xml
+++ b/packages/SystemUI/res/drawable/pin_dot_shape_5_avd.xml
@@ -1 +1,148 @@
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"><aapt:attr name="android:drawable"><vector android:height="30dp" android:width="30dp" android:viewportHeight="30" android:viewportWidth="30"><group android:name="_R_G"><group android:name="_R_G_L_1_G" android:translateX="15.397" android:translateY="15.691" android:scaleY="0"><path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-0.48 -12.86 C2.96,-12.87 14.59,5.93 11.98,9.12 C9.42,12.26 5.76,11.36 -0.48,11.41 C-6.72,11.45 -10.24,11.91 -12.78,9.16 C-15.4,6.32 -3.91,-12.85 -0.48,-12.86c "/></group><group android:name="_R_G_L_0_G" android:translateX="15" android:translateY="17.64" android:pivotY="-2.64" android:scaleX="0" android:scaleY="0"><path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-4.68 -13.34 C-2.59,-17.01 2.64,-17 4.72,-13.33 C4.72,-13.33 13.65,2.45 13.65,2.45 C15.72,6.11 13.11,10.66 8.94,10.65 C8.94,10.65 -8.98,10.62 -8.98,10.62 C-13.15,10.61 -15.75,6.05 -13.67,2.4 C-13.67,2.4 -4.68,-13.34 -4.68,-13.34c "/></group></group><group android:name="time_group"/></vector></aapt:attr><target android:name="_R_G_L_1_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="pathData" android:duration="67" android:startOffset="0" android:valueFrom="M-0.48 -12.86 C2.96,-12.87 14.59,5.93 11.98,9.12 C9.42,12.26 5.76,11.36 -0.48,11.41 C-6.72,11.45 -10.24,11.91 -12.78,9.16 C-15.4,6.32 -3.91,-12.85 -0.48,-12.86c " android:valueTo="M-0.48 -12.86 C2.96,-12.87 14.59,5.93 11.98,9.12 C9.42,12.26 5.76,11.36 -0.48,11.41 C-6.72,11.45 -10.24,11.91 -12.78,9.16 C-15.4,6.32 -3.91,-12.85 -0.48,-12.86c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.7,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="pathData" android:duration="283" android:startOffset="67" android:valueFrom="M-0.48 -12.86 C2.96,-12.87 14.59,5.93 11.98,9.12 C9.42,12.26 5.76,11.36 -0.48,11.41 C-6.72,11.45 -10.24,11.91 -12.78,9.16 C-15.4,6.32 -3.91,-12.85 -0.48,-12.86c " android:valueTo="M-0.44 -8.69 C3.98,-8.69 7.56,-5.11 7.56,-0.69 C7.56,3.73 3.98,7.31 -0.44,7.31 C-4.86,7.31 -8.44,3.73 -8.44,-0.69 C-8.44,-5.11 -4.86,-8.69 -0.44,-8.69c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.7,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_1_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="67" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target><target android:name="_R_G_L_0_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="pathData" android:duration="67" android:startOffset="0" android:valueFrom="M-4.68 -13.34 C-2.59,-17.01 2.64,-17 4.72,-13.33 C4.72,-13.33 13.65,2.45 13.65,2.45 C15.72,6.11 13.11,10.66 8.94,10.65 C8.94,10.65 -8.98,10.62 -8.98,10.62 C-13.15,10.61 -15.75,6.05 -13.67,2.4 C-13.67,2.4 -4.68,-13.34 -4.68,-13.34c " android:valueTo="M-4.68 -13.34 C-2.59,-17.01 2.64,-17 4.72,-13.33 C4.72,-13.33 13.65,2.45 13.65,2.45 C15.72,6.11 13.11,10.66 8.94,10.65 C8.94,10.65 -8.98,10.62 -8.98,10.62 C-13.15,10.61 -15.75,6.05 -13.67,2.4 C-13.67,2.4 -4.68,-13.34 -4.68,-13.34c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.7,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="pathData" android:duration="283" android:startOffset="67" android:valueFrom="M-4.68 -13.34 C-2.59,-17.01 2.64,-17 4.72,-13.33 C4.72,-13.33 13.65,2.45 13.65,2.45 C15.72,6.11 13.11,10.66 8.94,10.65 C8.94,10.65 -8.98,10.62 -8.98,10.62 C-13.15,10.61 -15.75,6.05 -13.67,2.4 C-13.67,2.4 -4.68,-13.34 -4.68,-13.34c " android:valueTo="M-2.99 -8.52 C-1.33,-9.83 1.52,-9.34 3.25,-8.28 C4.98,-7.22 6.77,-5.88 6.7,-2.4 C6.64,1.08 4.48,2.26 3.2,3.05 C1.92,3.83 -1.1,3.72 -3.03,2.76 C-4.97,1.79 -6.38,0.3 -6.37,-2.59 C-6.36,-5.49 -4.65,-7.2 -2.99,-8.52c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.7,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleX" android:duration="67" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="67" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="367" android:valueFrom="1" android:valueTo="0" android:valueType="floatType"/></set></aapt:attr></target><target android:name="time_group"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="translateX" android:duration="500" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target></animated-vector>
\ No newline at end of file
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="30dp"
+ android:width="30dp"
+ android:viewportHeight="30"
+ android:viewportWidth="30">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="15.397"
+ android:translateY="15.691"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M-0.48 -12.86 C2.96,-12.87 14.59,5.93 11.98,9.12 C9.42,12.26 5.76,11.36 -0.48,11.41 C-6.72,11.45 -10.24,11.91 -12.78,9.16 C-15.4,6.32 -3.91,-12.85 -0.48,-12.86c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="15"
+ android:translateY="17.64"
+ android:pivotY="-2.64">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M-4.68 -13.34 C-2.59,-17.01 2.64,-17 4.72,-13.33 C4.72,-13.33 13.65,2.45 13.65,2.45 C15.72,6.11 13.11,10.66 8.94,10.65 C8.94,10.65 -8.98,10.62 -8.98,10.62 C-13.15,10.61 -15.75,6.05 -13.67,2.4 C-13.67,2.4 -4.68,-13.34 -4.68,-13.34c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="67"
+ android:startOffset="0"
+ android:valueFrom="M-0.48 -12.86 C2.96,-12.87 14.59,5.93 11.98,9.12 C9.42,12.26 5.76,11.36 -0.48,11.41 C-6.72,11.45 -10.24,11.91 -12.78,9.16 C-15.4,6.32 -3.91,-12.85 -0.48,-12.86c "
+ android:valueTo="M-0.48 -12.86 C2.96,-12.87 14.59,5.93 11.98,9.12 C9.42,12.26 5.76,11.36 -0.48,11.41 C-6.72,11.45 -10.24,11.91 -12.78,9.16 C-15.4,6.32 -3.91,-12.85 -0.48,-12.86c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.7,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="283"
+ android:startOffset="67"
+ android:valueFrom="M-0.48 -12.86 C2.96,-12.87 14.59,5.93 11.98,9.12 C9.42,12.26 5.76,11.36 -0.48,11.41 C-6.72,11.45 -10.24,11.91 -12.78,9.16 C-15.4,6.32 -3.91,-12.85 -0.48,-12.86c "
+ android:valueTo="M-0.44 -8.69 C3.98,-8.69 7.56,-5.11 7.56,-0.69 C7.56,3.73 3.98,7.31 -0.44,7.31 C-4.86,7.31 -8.44,3.73 -8.44,-0.69 C-8.44,-5.11 -4.86,-8.69 -0.44,-8.69c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.7,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="0"
+ android:startOffset="67"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="67"
+ android:startOffset="0"
+ android:valueFrom="M-4.68 -13.34 C-2.59,-17.01 2.64,-17 4.72,-13.33 C4.72,-13.33 13.65,2.45 13.65,2.45 C15.72,6.11 13.11,10.66 8.94,10.65 C8.94,10.65 -8.98,10.62 -8.98,10.62 C-13.15,10.61 -15.75,6.05 -13.67,2.4 C-13.67,2.4 -4.68,-13.34 -4.68,-13.34c "
+ android:valueTo="M-4.68 -13.34 C-2.59,-17.01 2.64,-17 4.72,-13.33 C4.72,-13.33 13.65,2.45 13.65,2.45 C15.72,6.11 13.11,10.66 8.94,10.65 C8.94,10.65 -8.98,10.62 -8.98,10.62 C-13.15,10.61 -15.75,6.05 -13.67,2.4 C-13.67,2.4 -4.68,-13.34 -4.68,-13.34c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.7,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="283"
+ android:startOffset="67"
+ android:valueFrom="M-4.68 -13.34 C-2.59,-17.01 2.64,-17 4.72,-13.33 C4.72,-13.33 13.65,2.45 13.65,2.45 C15.72,6.11 13.11,10.66 8.94,10.65 C8.94,10.65 -8.98,10.62 -8.98,10.62 C-13.15,10.61 -15.75,6.05 -13.67,2.4 C-13.67,2.4 -4.68,-13.34 -4.68,-13.34c "
+ android:valueTo="M-2.99 -8.52 C-1.33,-9.83 1.52,-9.34 3.25,-8.28 C4.98,-7.22 6.77,-5.88 6.7,-2.4 C6.64,1.08 4.48,2.26 3.2,3.05 C1.92,3.83 -1.1,3.72 -3.03,2.76 C-4.97,1.79 -6.38,0.3 -6.37,-2.59 C-6.36,-5.49 -4.65,-7.2 -2.99,-8.52c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.7,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="67"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="67"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="500"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pin_dot_shape_6_avd.xml b/packages/SystemUI/res/drawable/pin_dot_shape_6_avd.xml
index ddda94a..06e27df 100644
--- a/packages/SystemUI/res/drawable/pin_dot_shape_6_avd.xml
+++ b/packages/SystemUI/res/drawable/pin_dot_shape_6_avd.xml
@@ -1 +1,142 @@
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"><aapt:attr name="android:drawable"><vector android:height="30dp" android:width="30dp" android:viewportHeight="30" android:viewportWidth="30"><group android:name="_R_G"><group android:name="_R_G_L_1_G" android:translateX="15.397" android:translateY="15.691" android:scaleY="0"><path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-0.46 -13.65 C3.05,-13.65 12.63,-6.57 12.9,-3.63 C12.98,-2.7 12.65,12.85 -0.46,12.85 C-13.57,12.85 -13.77,-2.84 -13.76,-3.63 C-13.72,-6.87 -3.96,-13.65 -0.46,-13.65c "/></group><group android:name="_R_G_L_0_G" android:translateX="15" android:translateY="15.859" android:pivotY="-0.859" android:scaleX="0" android:scaleY="0"><path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-2.82 -14.07 C-1.14,-15.29 1.14,-15.29 2.82,-14.07 C2.82,-14.07 7.73,-10.53 7.73,-10.53 C7.73,-10.53 12.58,-7 12.58,-7 C14.29,-5.76 15,-3.55 14.35,-1.54 C14.35,-1.54 12.51,4.14 12.51,4.14 C12.51,4.14 10.64,9.85 10.64,9.85 C9.99,11.84 8.14,13.19 6.05,13.19 C6.05,13.19 0,13.2 0,13.2 C0,13.2 -6.05,13.19 -6.05,13.19 C-8.14,13.19 -9.98,11.84 -10.64,9.85 C-10.64,9.85 -12.51,4.14 -12.51,4.14 C-12.51,4.14 -14.35,-1.54 -14.35,-1.54 C-15,-3.55 -14.29,-5.76 -12.58,-7 C-12.58,-7 -7.73,-10.53 -7.73,-10.53 C-7.73,-10.53 -2.82,-14.07 -2.82,-14.07c "/></group></group><group android:name="time_group"/></vector></aapt:attr><target android:name="_R_G_L_1_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="pathData" android:duration="67" android:startOffset="0" android:valueFrom="M-0.46 -13.65 C3.05,-13.65 12.63,-6.57 12.9,-3.63 C12.98,-2.7 12.65,12.85 -0.46,12.85 C-13.57,12.85 -13.77,-2.84 -13.76,-3.63 C-13.72,-6.87 -3.96,-13.65 -0.46,-13.65c " android:valueTo="M-0.46 -13.65 C3.05,-13.65 12.63,-6.57 12.9,-3.63 C12.98,-2.7 12.65,12.85 -0.46,12.85 C-13.57,12.85 -13.77,-2.84 -13.76,-3.63 C-13.72,-6.87 -3.96,-13.65 -0.46,-13.65c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.8,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="pathData" android:duration="283" android:startOffset="67" android:valueFrom="M-0.46 -13.65 C3.05,-13.65 12.63,-6.57 12.9,-3.63 C12.98,-2.7 12.65,12.85 -0.46,12.85 C-13.57,12.85 -13.77,-2.84 -13.76,-3.63 C-13.72,-6.87 -3.96,-13.65 -0.46,-13.65c " android:valueTo="M-0.44 -8.69 C3.98,-8.69 7.56,-5.11 7.56,-0.69 C7.56,3.73 3.98,7.31 -0.44,7.31 C-4.86,7.31 -8.44,3.73 -8.44,-0.69 C-8.44,-5.11 -4.86,-8.69 -0.44,-8.69c " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.8,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_1_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="67" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleX" android:duration="67" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="67" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleX" android:duration="283" android:startOffset="67" android:valueFrom="1" android:valueTo="0.35000000000000003" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.6,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="283" android:startOffset="67" android:valueFrom="1" android:valueTo="0.35000000000000003" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.6,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="367" android:valueFrom="1" android:valueTo="0" android:valueType="floatType"/></set></aapt:attr></target><target android:name="time_group"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="translateX" android:duration="500" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target></animated-vector>
\ No newline at end of file
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="30dp"
+ android:width="30dp"
+ android:viewportHeight="30"
+ android:viewportWidth="30">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="15.397"
+ android:translateY="15.691"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M-0.46 -13.65 C3.05,-13.65 12.63,-6.57 12.9,-3.63 C12.98,-2.7 12.65,12.85 -0.46,12.85 C-13.57,12.85 -13.77,-2.84 -13.76,-3.63 C-13.72,-6.87 -3.96,-13.65 -0.46,-13.65c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="15"
+ android:translateY="15.859"
+ android:pivotY="-0.859">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M-2.82 -14.07 C-1.14,-15.29 1.14,-15.29 2.82,-14.07 C2.82,-14.07 7.73,-10.53 7.73,-10.53 C7.73,-10.53 12.58,-7 12.58,-7 C14.29,-5.76 15,-3.55 14.35,-1.54 C14.35,-1.54 12.51,4.14 12.51,4.14 C12.51,4.14 10.64,9.85 10.64,9.85 C9.99,11.84 8.14,13.19 6.05,13.19 C6.05,13.19 0,13.2 0,13.2 C0,13.2 -6.05,13.19 -6.05,13.19 C-8.14,13.19 -9.98,11.84 -10.64,9.85 C-10.64,9.85 -12.51,4.14 -12.51,4.14 C-12.51,4.14 -14.35,-1.54 -14.35,-1.54 C-15,-3.55 -14.29,-5.76 -12.58,-7 C-12.58,-7 -7.73,-10.53 -7.73,-10.53 C-7.73,-10.53 -2.82,-14.07 -2.82,-14.07c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="67"
+ android:startOffset="0"
+ android:valueFrom="M-0.46 -13.65 C3.05,-13.65 12.63,-6.57 12.9,-3.63 C12.98,-2.7 12.65,12.85 -0.46,12.85 C-13.57,12.85 -13.77,-2.84 -13.76,-3.63 C-13.72,-6.87 -3.96,-13.65 -0.46,-13.65c "
+ android:valueTo="M-0.46 -13.65 C3.05,-13.65 12.63,-6.57 12.9,-3.63 C12.98,-2.7 12.65,12.85 -0.46,12.85 C-13.57,12.85 -13.77,-2.84 -13.76,-3.63 C-13.72,-6.87 -3.96,-13.65 -0.46,-13.65c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.8,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="283"
+ android:startOffset="67"
+ android:valueFrom="M-0.46 -13.65 C3.05,-13.65 12.63,-6.57 12.9,-3.63 C12.98,-2.7 12.65,12.85 -0.46,12.85 C-13.57,12.85 -13.77,-2.84 -13.76,-3.63 C-13.72,-6.87 -3.96,-13.65 -0.46,-13.65c "
+ android:valueTo="M-0.44 -8.69 C3.98,-8.69 7.56,-5.11 7.56,-0.69 C7.56,3.73 3.98,7.31 -0.44,7.31 C-4.86,7.31 -8.44,3.73 -8.44,-0.69 C-8.44,-5.11 -4.86,-8.69 -0.44,-8.69c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.8,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="0"
+ android:startOffset="67"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="67"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="67"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="283"
+ android:startOffset="67"
+ android:valueFrom="1"
+ android:valueTo="0.35000000000000003"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.6,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="283"
+ android:startOffset="67"
+ android:valueFrom="1"
+ android:valueTo="0.35000000000000003"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.6,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="500"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/screen_record_options.xml b/packages/SystemUI/res/layout/screen_record_options.xml
index 6cc72dd..d9f4b79 100644
--- a/packages/SystemUI/res/layout/screen_record_options.xml
+++ b/packages/SystemUI/res/layout/screen_record_options.xml
@@ -55,14 +55,13 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
+ android:gravity="center_vertical"
android:layout_marginTop="@dimen/screenrecord_option_padding">
<ImageView
android:layout_width="@dimen/screenrecord_option_icon_size"
android:layout_height="@dimen/screenrecord_option_icon_size"
- android:layout_weight="0"
android:src="@drawable/ic_touch"
android:tint="?android:attr/textColorSecondary"
- android:layout_gravity="center_vertical"
android:layout_marginRight="@dimen/screenrecord_option_padding"
android:importantForAccessibility="no"/>
<TextView
@@ -70,7 +69,6 @@
android:layout_height="wrap_content"
android:minHeight="48dp"
android:layout_weight="1"
- android:gravity="center_vertical"
android:text="@string/screenrecord_taps_label"
android:textAppearance="?android:attr/textAppearanceMedium"
android:fontFamily="@*android:string/config_bodyFontFamily"
@@ -80,7 +78,6 @@
android:layout_width="wrap_content"
android:minWidth="48dp"
android:layout_height="48dp"
- android:layout_weight="0"
android:id="@+id/screenrecord_taps_switch"
style="@style/ScreenRecord.Switch"
android:importantForAccessibility="yes"/>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 59becc6..9a2db6bfd 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -20,6 +20,13 @@
On large screens should be the same as the regular status bar. -->
<dimen name="status_bar_header_height_keyguard">@dimen/status_bar_height</dimen>
+ <!-- padding for container with status icons and battery -->
+ <dimen name="status_bar_icons_padding_end">12dp</dimen>
+ <!-- start padding is smaller to account for status icon margins coming from drawable itself -->
+ <dimen name="status_bar_icons_padding_start">11dp</dimen>
+
+ <dimen name="status_bar_padding_end">0dp</dimen>
+
<!-- Size of user icon + frame in the qs user picker (incl. frame) -->
<dimen name="qs_framed_avatar_size">60dp</dimen>
<!-- Size of user icon + frame in the keyguard user picker (incl. frame) -->
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index d277dae..d053a7a 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -16,13 +16,9 @@
*/
-->
<resources>
- <!-- padding for container with status icons and battery -->
- <dimen name="status_bar_icons_padding_end">12dp</dimen>
- <!-- it's a bit smaller on large screen to account for status_bar_icon_horizontal_margin -->
+ <!-- it's a bit smaller on 720dp to account for status_bar_icon_horizontal_margin -->
<dimen name="status_bar_icons_padding_start">10dp</dimen>
- <dimen name="status_bar_padding_end">0dp</dimen>
-
<!-- gap on either side of status bar notification icons -->
<dimen name="status_bar_icon_horizontal_margin">1dp</dimen>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/util/TraceUtils.kt b/packages/SystemUI/shared/src/com/android/systemui/util/TraceUtils.kt
index 64234c2..e02e592 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/util/TraceUtils.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/util/TraceUtils.kt
@@ -18,22 +18,23 @@
import android.os.Trace
import android.os.TraceNameSupplier
+import java.util.concurrent.atomic.AtomicInteger
/**
- * Run a block within a [Trace] section.
- * Calls [Trace.beginSection] before and [Trace.endSection] after the passed block.
+ * Run a block within a [Trace] section. Calls [Trace.beginSection] before and [Trace.endSection]
+ * after the passed block.
*/
inline fun <T> traceSection(tag: String, block: () -> T): T =
- if (Trace.isTagEnabled(Trace.TRACE_TAG_APP)) {
- Trace.traceBegin(Trace.TRACE_TAG_APP, tag)
- try {
- block()
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_APP)
- }
- } else {
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_APP)) {
+ Trace.traceBegin(Trace.TRACE_TAG_APP, tag)
+ try {
block()
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_APP)
}
+ } else {
+ block()
+ }
class TraceUtils {
companion object {
@@ -43,6 +44,7 @@
/**
* Helper function for creating a Runnable object that implements TraceNameSupplier.
+ *
* This is useful for posting Runnables to Handlers with meaningful names.
*/
inline fun namedRunnable(tag: String, crossinline block: () -> Unit): Runnable {
@@ -51,5 +53,37 @@
override fun run() = block()
}
}
+
+ /**
+ * Cookie used for async traces. Shouldn't be public, but to use it inside inline methods
+ * there is no other way around.
+ */
+ val lastCookie = AtomicInteger(0)
+
+ /**
+ * Creates an async slice in a track called "AsyncTraces".
+ *
+ * This can be used to trace coroutine code. Note that all usages of this method will appear
+ * under a single track.
+ */
+ inline fun <T> traceAsync(method: String, block: () -> T): T =
+ traceAsync(method, "AsyncTraces", block)
+
+ /**
+ * Creates an async slice in a track with [trackName] while [block] runs.
+ *
+ * This can be used to trace coroutine code. [method] will be the name of the slice,
+ * [trackName] of the track. The track is one of the rows visible in a perfetto trace inside
+ * SystemUI process.
+ */
+ inline fun <T> traceAsync(method: String, trackName: String, block: () -> T): T {
+ val cookie = lastCookie.incrementAndGet()
+ Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_APP, trackName, method, cookie)
+ try {
+ return block()
+ } finally {
+ Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_APP, trackName, cookie)
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index e255f5c..8ef6c2e 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -56,6 +56,7 @@
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.AuthRippleController;
import com.android.systemui.biometrics.UdfpsController;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
@@ -113,6 +114,7 @@
@NonNull private final VibratorHelper mVibrator;
@Nullable private final AuthRippleController mAuthRippleController;
@NonNull private final FeatureFlags mFeatureFlags;
+ @NonNull private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
@NonNull private final KeyguardTransitionInteractor mTransitionInteractor;
@NonNull private final KeyguardInteractor mKeyguardInteractor;
@@ -181,7 +183,8 @@
@NonNull @Main Resources resources,
@NonNull KeyguardTransitionInteractor transitionInteractor,
@NonNull KeyguardInteractor keyguardInteractor,
- @NonNull FeatureFlags featureFlags
+ @NonNull FeatureFlags featureFlags,
+ PrimaryBouncerInteractor primaryBouncerInteractor
) {
super(view);
mStatusBarStateController = statusBarStateController;
@@ -198,6 +201,7 @@
mTransitionInteractor = transitionInteractor;
mKeyguardInteractor = keyguardInteractor;
mFeatureFlags = featureFlags;
+ mPrimaryBouncerInteractor = primaryBouncerInteractor;
mMaxBurnInOffsetX = resources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x);
mMaxBurnInOffsetY = resources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
@@ -326,8 +330,14 @@
mView.setContentDescription(null);
}
+ boolean accessibilityEnabled =
+ !mPrimaryBouncerInteractor.isAnimatingAway() && mView.isVisibleToUser();
+ mView.setImportantForAccessibility(
+ accessibilityEnabled ? View.IMPORTANT_FOR_ACCESSIBILITY_YES
+ : View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+
if (!Objects.equals(prevContentDescription, mView.getContentDescription())
- && mView.getContentDescription() != null && mView.isVisibleToUser()) {
+ && mView.getContentDescription() != null && accessibilityEnabled) {
mView.announceForAccessibility(mView.getContentDescription());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index de7a669..ff395da 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -36,6 +36,7 @@
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.hardware.graphics.common.AlphaInterpretation;
@@ -171,7 +172,7 @@
private int mTintColor = Color.BLACK;
@VisibleForTesting
protected DisplayDecorationSupport mHwcScreenDecorationSupport;
- private Display.Mode mDisplayMode;
+ private final Point mDisplaySize = new Point();
@VisibleForTesting
protected DisplayInfo mDisplayInfo = new DisplayInfo();
private DisplayCutout mDisplayCutout;
@@ -484,7 +485,8 @@
mWindowManager = mContext.getSystemService(WindowManager.class);
mContext.getDisplay().getDisplayInfo(mDisplayInfo);
mRotation = mDisplayInfo.rotation;
- mDisplayMode = mDisplayInfo.getMode();
+ mDisplaySize.x = mDisplayInfo.getNaturalWidth();
+ mDisplaySize.y = mDisplayInfo.getNaturalHeight();
mDisplayUniqueId = mDisplayInfo.uniqueId;
mDisplayCutout = mDisplayInfo.displayCutout;
mRoundedCornerResDelegate =
@@ -505,10 +507,12 @@
public void onDisplayChanged(int displayId) {
mContext.getDisplay().getDisplayInfo(mDisplayInfo);
final int newRotation = mDisplayInfo.rotation;
- final Display.Mode newDisplayMode = mDisplayInfo.getMode();
if ((mOverlays != null || mScreenDecorHwcWindow != null)
&& (mRotation != newRotation
- || displayModeChanged(mDisplayMode, newDisplayMode))) {
+ || displaySizeChanged(mDisplaySize, mDisplayInfo))) {
+ final Point newSize = new Point();
+ newSize.x = mDisplayInfo.getNaturalWidth();
+ newSize.y = mDisplayInfo.getNaturalHeight();
// We cannot immediately update the orientation. Otherwise
// WindowManager is still deferring layout until it has finished dispatching
// the config changes, which may cause divergence between what we draw
@@ -520,9 +524,8 @@
if (mRotation != newRotation) {
mLogger.logRotationChangeDeferred(mRotation, newRotation);
}
- if (displayModeChanged(mDisplayMode, newDisplayMode)) {
- mLogger.logDisplayModeChanged(
- newDisplayMode.getModeId(), mDisplayMode.getModeId());
+ if (!mDisplaySize.equals(newSize)) {
+ mLogger.logDisplaySizeChanged(mDisplaySize, newSize);
}
if (mOverlays != null) {
@@ -531,7 +534,7 @@
final ViewGroup overlayView = mOverlays[i].getRootView();
overlayView.getViewTreeObserver().addOnPreDrawListener(
new RestartingPreDrawListener(
- overlayView, i, newRotation, newDisplayMode));
+ overlayView, i, newRotation, newSize));
}
}
}
@@ -541,7 +544,7 @@
new RestartingPreDrawListener(
mScreenDecorHwcWindow,
-1, // Pass -1 for views with no specific position.
- newRotation, newDisplayMode));
+ newRotation, newSize));
}
if (mScreenDecorHwcLayer != null) {
mScreenDecorHwcLayer.pendingConfigChange = true;
@@ -943,15 +946,8 @@
}
}
- private static boolean displayModeChanged(Display.Mode oldMode, Display.Mode newMode) {
- if (oldMode == null) {
- return true;
- }
-
- // We purposely ignore refresh rate and id changes here, because we don't need to
- // invalidate for those, and they can trigger the refresh rate to increase
- return oldMode.getPhysicalWidth() != newMode.getPhysicalWidth()
- || oldMode.getPhysicalHeight() != newMode.getPhysicalHeight();
+ private static boolean displaySizeChanged(Point size, DisplayInfo info) {
+ return size.x != info.getNaturalWidth() || size.y != info.getNaturalHeight();
}
private int getOverlayWindowGravity(@BoundsPosition int pos) {
@@ -1170,14 +1166,14 @@
if (mRotation != newRotation) {
mDotViewController.setNewRotation(newRotation);
}
- final Display.Mode newMod = mDisplayInfo.getMode();
final DisplayCutout newCutout = mDisplayInfo.displayCutout;
if (!mPendingConfigChange
- && (newRotation != mRotation || displayModeChanged(mDisplayMode, newMod)
+ && (newRotation != mRotation || displaySizeChanged(mDisplaySize, mDisplayInfo)
|| !Objects.equals(newCutout, mDisplayCutout))) {
mRotation = newRotation;
- mDisplayMode = newMod;
+ mDisplaySize.x = mDisplayInfo.getNaturalWidth();
+ mDisplaySize.y = mDisplayInfo.getNaturalHeight();
mDisplayCutout = newCutout;
float ratio = getPhysicalPixelDisplaySizeRatio();
mRoundedCornerResDelegate.setPhysicalPixelDisplaySizeRatio(ratio);
@@ -1494,31 +1490,29 @@
private final View mView;
private final int mTargetRotation;
- private final Display.Mode mTargetDisplayMode;
+ private final Point mTargetDisplaySize;
// Pass -1 for ScreenDecorHwcLayer since it's a fullscreen window and has no specific
// position.
private final int mPosition;
private RestartingPreDrawListener(View view, @BoundsPosition int position,
- int targetRotation, Display.Mode targetDisplayMode) {
+ int targetRotation, Point targetDisplaySize) {
mView = view;
mTargetRotation = targetRotation;
- mTargetDisplayMode = targetDisplayMode;
+ mTargetDisplaySize = targetDisplaySize;
mPosition = position;
}
@Override
public boolean onPreDraw() {
mView.getViewTreeObserver().removeOnPreDrawListener(this);
- if (mTargetRotation == mRotation
- && !displayModeChanged(mDisplayMode, mTargetDisplayMode)) {
+ if (mTargetRotation == mRotation && mDisplaySize.equals(mTargetDisplaySize)) {
if (DEBUG_LOGGING) {
final String title = mPosition < 0 ? "ScreenDecorHwcLayer"
: getWindowTitleByPos(mPosition);
Log.i(TAG, title + " already in target rot "
+ mTargetRotation + " and in target resolution "
- + mTargetDisplayMode.getPhysicalWidth() + "x"
- + mTargetDisplayMode.getPhysicalHeight()
+ + mTargetDisplaySize.x + "x" + mTargetDisplaySize.y
+ ", allow draw without restarting it");
}
return true;
@@ -1533,8 +1527,7 @@
: getWindowTitleByPos(mPosition);
Log.i(TAG, title
+ " restarting listener fired, restarting draw for rot " + mRotation
- + ", resolution " + mDisplayMode.getPhysicalWidth() + "x"
- + mDisplayMode.getPhysicalHeight());
+ + ", resolution " + mDisplaySize.x + "x" + mDisplaySize.y);
}
mView.invalidate();
return false;
@@ -1560,19 +1553,18 @@
public boolean onPreDraw() {
mContext.getDisplay().getDisplayInfo(mDisplayInfo);
final int displayRotation = mDisplayInfo.rotation;
- final Display.Mode displayMode = mDisplayInfo.getMode();
- if ((displayRotation != mRotation || displayModeChanged(mDisplayMode, displayMode))
+ if ((displayRotation != mRotation || displaySizeChanged(mDisplaySize, mDisplayInfo))
&& !mPendingConfigChange) {
if (DEBUG_LOGGING) {
if (displayRotation != mRotation) {
Log.i(TAG, "Drawing rot " + mRotation + ", but display is at rot "
+ displayRotation + ". Restarting draw");
}
- if (displayModeChanged(mDisplayMode, displayMode)) {
- Log.i(TAG, "Drawing at " + mDisplayMode.getPhysicalWidth()
- + "x" + mDisplayMode.getPhysicalHeight() + ", but display is at "
- + displayMode.getPhysicalWidth() + "x"
- + displayMode.getPhysicalHeight() + ". Restarting draw");
+ if (displaySizeChanged(mDisplaySize, mDisplayInfo)) {
+ Log.i(TAG, "Drawing at " + mDisplaySize.x + "x" + mDisplaySize.y
+ + ", but display is at "
+ + mDisplayInfo.getNaturalWidth() + "x"
+ + mDisplayInfo.getNaturalHeight() + ". Restarting draw");
}
}
mView.invalidate();
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index 2a14dc8..1739ba4 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -28,6 +28,7 @@
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.Handler;
+import android.util.SparseArray;
import android.view.Display;
import android.view.SurfaceControl;
import android.view.WindowManagerGlobal;
@@ -72,6 +73,9 @@
private WindowMagnificationConnectionImpl mWindowMagnificationConnectionImpl;
private SysUiState mSysUiState;
+ @VisibleForTesting
+ SparseArray<SparseArray<Float>> mUsersScales = new SparseArray();
+
private static class ControllerSupplier extends
DisplayIdIndexSupplier<WindowMagnificationController> {
@@ -295,6 +299,19 @@
mModeSwitchesController.removeButton(displayId);
}
+ @MainThread
+ void setUserMagnificationScale(int userId, int displayId, float scale) {
+ SparseArray<Float> scales = mUsersScales.get(userId);
+ if (scales == null) {
+ scales = new SparseArray<>();
+ mUsersScales.put(userId, scales);
+ }
+ if (scales.contains(displayId) && scales.get(displayId) == scale) {
+ return;
+ }
+ scales.put(displayId, scale);
+ }
+
@VisibleForTesting
final WindowMagnifierCallback mWindowMagnifierCallback = new WindowMagnifierCallback() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.java
index c081893..f1d00ce2 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.java
@@ -99,6 +99,12 @@
}
@Override
+ public void onUserMagnificationScaleChanged(int userId, int displayId, float scale) {
+ mHandler.post(() -> mWindowMagnification.setUserMagnificationScale(
+ userId, displayId, scale));
+ }
+
+ @Override
public void setConnectionCallback(IWindowMagnificationConnectionCallback callback) {
mConnectionCallback = callback;
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
index 31b0f056..1e1d4b7 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
@@ -172,7 +172,8 @@
};
}
- private class ZoomSeekbarChangeListener implements SeekBar.OnSeekBarChangeListener {
+ private class ZoomSeekbarChangeListener implements
+ SeekBarWithIconButtonsView.OnSeekBarWithIconButtonsChangeListener {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
float scale = (progress / (float) mSeekBarMagnitude) + SCALE_MIN_VALUE;
@@ -197,6 +198,11 @@
public void onStopTrackingTouch(SeekBar seekBar) {
// Do nothing
}
+
+ @Override
+ public void onUserInteractionFinalized(SeekBar seekBar, @ControlUnitType int control) {
+ // Do nothing
+ }
}
private final AccessibilityDelegate mPanelDelegate = new AccessibilityDelegate() {
@@ -521,7 +527,7 @@
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, 0,
UserHandle.USER_CURRENT);
setScaleSeekbar(scale);
- mZoomSeekbar.setOnSeekBarChangeListener(new ZoomSeekbarChangeListener());
+ mZoomSeekbar.setOnSeekBarWithIconButtonsChangeListener(new ZoomSeekbarChangeListener());
mAllowDiagonalScrollingView =
(LinearLayout) mSettingView.findViewById(R.id.magnifier_horizontal_lock_view);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt
index a910ab5..783460c 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt
@@ -26,12 +26,13 @@
import android.view.LayoutInflater
import android.widget.Button
import android.widget.SeekBar
-import android.widget.SeekBar.OnSeekBarChangeListener
import android.widget.TextView
import androidx.annotation.MainThread
import androidx.annotation.WorkerThread
import com.android.systemui.R
import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView
+import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView.OnSeekBarWithIconButtonsChangeListener
+import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView.OnSeekBarWithIconButtonsChangeListener.ControlUnitType
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.settings.UserTracker
@@ -105,28 +106,32 @@
lastProgress.set(fontSizeValueToIndex(currentScale))
seekBarWithIconButtonsView.setProgress(lastProgress.get())
- seekBarWithIconButtonsView.setOnSeekBarChangeListener(
- object : OnSeekBarChangeListener {
- var isTrackingTouch = false
-
+ seekBarWithIconButtonsView.setOnSeekBarWithIconButtonsChangeListener(
+ object : OnSeekBarWithIconButtonsChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
// Always provide preview configuration for text first when there is a change
// in the seekbar progress.
createTextPreview(progress)
-
- if (!isTrackingTouch) {
- // The seekbar progress is changed by icon buttons
- changeFontSize(progress, CHANGE_BY_BUTTON_DELAY_MS)
- }
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
- isTrackingTouch = true
+ // Do nothing
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
- isTrackingTouch = false
- changeFontSize(seekBar.progress, CHANGE_BY_SEEKBAR_DELAY_MS)
+ // Do nothing
+ }
+
+ override fun onUserInteractionFinalized(
+ seekBar: SeekBar,
+ @ControlUnitType control: Int
+ ) {
+ if (control == ControlUnitType.BUTTON) {
+ // The seekbar progress is changed by icon buttons
+ changeFontSize(seekBar.progress, CHANGE_BY_BUTTON_DELAY_MS)
+ } else {
+ changeFontSize(seekBar.progress, CHANGE_BY_SEEKBAR_DELAY_MS)
+ }
}
}
)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt
index e6aeb43..802eea3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt
@@ -37,4 +37,8 @@
dumpManager
) {
override val tag = "UdfpsBpViewController"
+
+ override fun shouldPauseAuth(): Boolean {
+ return false
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
index b293ea6..db6ca0b 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
@@ -61,6 +61,7 @@
private val pin: PinBouncerViewModel by lazy {
PinBouncerViewModel(
+ applicationContext = applicationContext,
applicationScope = applicationScope,
interactor = interactor,
isInputEnabled = isInputEnabled,
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
index 014ebc3..641e863 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
@@ -16,6 +16,8 @@
package com.android.systemui.bouncer.ui.viewmodel
+import android.content.Context
+import com.android.keyguard.PinShapeAdapter
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import kotlinx.coroutines.CoroutineScope
@@ -29,6 +31,7 @@
/** Holds UI state and handles user input for the PIN code bouncer UI. */
class PinBouncerViewModel(
+ applicationContext: Context,
private val applicationScope: CoroutineScope,
private val interactor: BouncerInteractor,
isInputEnabled: StateFlow<Boolean>,
@@ -37,6 +40,8 @@
isInputEnabled = isInputEnabled,
) {
+ val pinShapes = PinShapeAdapter(applicationContext)
+
private val mutablePinEntries = MutableStateFlow<List<EnteredKey>>(emptyList())
val pinEntries: StateFlow<List<EnteredKey>> = mutablePinEntries
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java b/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
index 4538a6c..277b427 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
@@ -16,6 +16,7 @@
package com.android.systemui.common.ui.view;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.TypedArray;
@@ -30,6 +31,9 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* The layout contains a seekbar whose progress could be modified
* through the icons on two ends of the seekbar.
@@ -47,6 +51,8 @@
private SeekBar mSeekbar;
private int mSeekBarChangeMagnitude = 1;
+ private boolean mSetProgressFromButtonFlag = false;
+
private SeekBarChangeListener mSeekBarListener = new SeekBarChangeListener();
private String[] mStateLabels = null;
@@ -121,21 +127,8 @@
mSeekbar.setOnSeekBarChangeListener(mSeekBarListener);
- mIconStartFrame.setOnClickListener((view) -> {
- final int progress = mSeekbar.getProgress();
- if (progress > 0) {
- mSeekbar.setProgress(progress - mSeekBarChangeMagnitude);
- setIconViewAndFrameEnabled(mIconStart, mSeekbar.getProgress() > 0);
- }
- });
-
- mIconEndFrame.setOnClickListener((view) -> {
- final int progress = mSeekbar.getProgress();
- if (progress < mSeekbar.getMax()) {
- mSeekbar.setProgress(progress + mSeekBarChangeMagnitude);
- setIconViewAndFrameEnabled(mIconEnd, mSeekbar.getProgress() < mSeekbar.getMax());
- }
- });
+ mIconStartFrame.setOnClickListener((view) -> onIconStartClicked());
+ mIconEndFrame.setOnClickListener((view) -> onIconEndClicked());
}
private static void setIconViewAndFrameEnabled(View iconView, boolean enabled) {
@@ -172,9 +165,9 @@
* Sets a onSeekbarChangeListener to the seekbar in the layout.
* We update the Start Icon and End Icon if needed when the seekbar progress is changed.
*/
- public void setOnSeekBarChangeListener(
- @Nullable SeekBar.OnSeekBarChangeListener onSeekBarChangeListener) {
- mSeekBarListener.setOnSeekBarChangeListener(onSeekBarChangeListener);
+ public void setOnSeekBarWithIconButtonsChangeListener(
+ @Nullable OnSeekBarWithIconButtonsChangeListener onSeekBarChangeListener) {
+ mSeekBarListener.setOnSeekBarWithIconButtonsChangeListener(onSeekBarChangeListener);
}
/**
@@ -216,16 +209,72 @@
*/
public void setProgress(int progress) {
mSeekbar.setProgress(progress);
- updateIconViewIfNeeded(progress);
+ updateIconViewIfNeeded(mSeekbar.getProgress());
}
+ private void setProgressFromButton(int progress) {
+ mSetProgressFromButtonFlag = true;
+ mSeekbar.setProgress(progress);
+ updateIconViewIfNeeded(mSeekbar.getProgress());
+ }
+
+ private void onIconStartClicked() {
+ final int progress = mSeekbar.getProgress();
+ if (progress > 0) {
+ setProgressFromButton(progress - mSeekBarChangeMagnitude);
+ }
+ }
+
+ private void onIconEndClicked() {
+ final int progress = mSeekbar.getProgress();
+ if (progress < mSeekbar.getMax()) {
+ setProgressFromButton(progress + mSeekBarChangeMagnitude);
+ }
+ }
+
+ /**
+ * Get current seekbar progress
+ *
+ * @return
+ */
@VisibleForTesting
public int getProgress() {
return mSeekbar.getProgress();
}
+ /**
+ * Extended from {@link SeekBar.OnSeekBarChangeListener} to add callback to notify the listeners
+ * the user interaction with the SeekBarWithIconButtonsView is finalized.
+ */
+ public interface OnSeekBarWithIconButtonsChangeListener
+ extends SeekBar.OnSeekBarChangeListener {
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ ControlUnitType.SLIDER,
+ ControlUnitType.BUTTON
+ })
+ /** Denotes the Last user interacted control unit type. */
+ @interface ControlUnitType {
+ int SLIDER = 0;
+ int BUTTON = 1;
+ }
+
+ /**
+ * Notification that the user interaction with SeekBarWithIconButtonsView is finalized. This
+ * would be triggered after user ends dragging on the slider or clicks icon buttons.
+ *
+ * @param seekBar The SeekBar in which the user ends interaction with
+ * @param control The last user interacted control unit. It would be
+ * {@link ControlUnitType#SLIDER} if the user was changing the seekbar
+ * progress through dragging the slider, or {@link ControlUnitType#BUTTON}
+ * is the user was clicking button to change the progress.
+ */
+ void onUserInteractionFinalized(SeekBar seekBar, @ControlUnitType int control);
+ }
+
private class SeekBarChangeListener implements SeekBar.OnSeekBarChangeListener {
- private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener = null;
+ private OnSeekBarWithIconButtonsChangeListener mOnSeekBarChangeListener = null;
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
@@ -233,7 +282,17 @@
setSeekbarStateDescription();
}
if (mOnSeekBarChangeListener != null) {
- mOnSeekBarChangeListener.onProgressChanged(seekBar, progress, fromUser);
+ if (mSetProgressFromButtonFlag) {
+ mSetProgressFromButtonFlag = false;
+ mOnSeekBarChangeListener.onProgressChanged(
+ seekBar, progress, /* fromUser= */ true);
+ // Directly trigger onUserInteractionFinalized since the interaction
+ // (click button) is ended.
+ mOnSeekBarChangeListener.onUserInteractionFinalized(
+ seekBar, OnSeekBarWithIconButtonsChangeListener.ControlUnitType.BUTTON);
+ } else {
+ mOnSeekBarChangeListener.onProgressChanged(seekBar, progress, fromUser);
+ }
}
updateIconViewIfNeeded(progress);
}
@@ -249,10 +308,13 @@
public void onStopTrackingTouch(SeekBar seekBar) {
if (mOnSeekBarChangeListener != null) {
mOnSeekBarChangeListener.onStopTrackingTouch(seekBar);
+ mOnSeekBarChangeListener.onUserInteractionFinalized(
+ seekBar, OnSeekBarWithIconButtonsChangeListener.ControlUnitType.SLIDER);
}
}
- void setOnSeekBarChangeListener(SeekBar.OnSeekBarChangeListener listener) {
+ void setOnSeekBarWithIconButtonsChangeListener(
+ OnSeekBarWithIconButtonsChangeListener listener) {
mOnSeekBarChangeListener = listener;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index 40db63d..b1f513d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -42,6 +42,7 @@
import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper
import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver
import com.android.systemui.media.taptotransfer.sender.MediaTttSenderCoordinator
+import com.android.systemui.mediaprojection.taskswitcher.MediaProjectionTaskSwitcherCoreStartable
import com.android.systemui.power.PowerUI
import com.android.systemui.reardisplay.RearDisplayDialogController
import com.android.systemui.recents.Recents
@@ -111,6 +112,14 @@
@ClassKey(KeyboardUI::class)
abstract fun bindKeyboardUI(sysui: KeyboardUI): CoreStartable
+ /** Inject into MediaProjectionTaskSwitcherCoreStartable. */
+ @Binds
+ @IntoMap
+ @ClassKey(MediaProjectionTaskSwitcherCoreStartable::class)
+ abstract fun bindProjectedTaskListener(
+ sysui: MediaProjectionTaskSwitcherCoreStartable
+ ): CoreStartable
+
/** Inject into KeyguardBiometricLockoutLogger */
@Binds
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index ead24ae..3b89739 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -59,6 +59,7 @@
import com.android.systemui.log.dagger.MonitorLog;
import com.android.systemui.log.table.TableLogBuffer;
import com.android.systemui.mediaprojection.appselector.MediaProjectionModule;
+import com.android.systemui.mediaprojection.taskswitcher.MediaProjectionTaskSwitcherModule;
import com.android.systemui.model.SysUiState;
import com.android.systemui.motiontool.MotionToolModule;
import com.android.systemui.navigationbar.NavigationBarComponent;
@@ -182,6 +183,7 @@
LockscreenLayoutModule.class,
LogModule.class,
MediaProjectionModule.class,
+ MediaProjectionTaskSwitcherModule.class,
MotionToolModule.class,
PeopleHubModule.class,
PeopleModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index d1ac49b..f692a39 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -49,6 +49,7 @@
import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.TraceUtils.Companion.traceAsync
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -442,8 +443,10 @@
}
private suspend fun isFeatureDisabledByDevicePolicy(): Boolean =
- withContext(backgroundDispatcher) {
- devicePolicyManager.areKeyguardShortcutsDisabled(userId = userTracker.userId)
+ traceAsync("isFeatureDisabledByDevicePolicy", TAG) {
+ withContext(backgroundDispatcher) {
+ devicePolicyManager.areKeyguardShortcutsDisabled(userId = userTracker.userId)
+ }
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt b/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
index 150de26..702a23e 100644
--- a/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
@@ -189,15 +189,15 @@
)
}
- fun logDisplayModeChanged(currentMode: Int, newMode: Int) {
+ fun logDisplaySizeChanged(currentSize: Point, newSize: Point) {
logBuffer.log(
TAG,
INFO,
{
- int1 = currentMode
- int2 = newMode
+ str1 = currentSize.flattenToString()
+ str2 = newSize.flattenToString()
},
- { "Resolution changed, deferring mode change to $int2, staying at $int1" },
+ { "Resolution changed, deferring size change to $str2, staying at $str1" },
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/MediaProjectionTaskSwitcherCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/MediaProjectionTaskSwitcherCoreStartable.kt
new file mode 100644
index 0000000..3c50127
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/MediaProjectionTaskSwitcherCoreStartable.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.mediaprojection.taskswitcher.ui.TaskSwitcherNotificationCoordinator
+import javax.inject.Inject
+
+@SysUISingleton
+class MediaProjectionTaskSwitcherCoreStartable
+@Inject
+constructor(
+ private val notificationCoordinator: TaskSwitcherNotificationCoordinator,
+ private val featureFlags: FeatureFlags,
+) : CoreStartable {
+
+ override fun start() {
+ if (featureFlags.isEnabled(Flags.PARTIAL_SCREEN_SHARING_TASK_SWITCHER)) {
+ notificationCoordinator.start()
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/MediaProjectionTaskSwitcherModule.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/MediaProjectionTaskSwitcherModule.kt
new file mode 100644
index 0000000..22ad07e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/MediaProjectionTaskSwitcherModule.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher
+
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.ActivityTaskManagerTasksRepository
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.MediaProjectionManagerRepository
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.MediaProjectionRepository
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.TasksRepository
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface MediaProjectionTaskSwitcherModule {
+
+ @Binds fun mediaRepository(impl: MediaProjectionManagerRepository): MediaProjectionRepository
+
+ @Binds fun tasksRepository(impl: ActivityTaskManagerTasksRepository): TasksRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/model/MediaProjectionState.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/model/MediaProjectionState.kt
new file mode 100644
index 0000000..9938f11
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/model/MediaProjectionState.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.data.model
+
+import android.app.TaskInfo
+
+/** Represents the state of media projection. */
+sealed interface MediaProjectionState {
+ object NotProjecting : MediaProjectionState
+ object EntireScreen : MediaProjectionState
+ data class SingleTask(val task: TaskInfo) : MediaProjectionState
+}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepository.kt
new file mode 100644
index 0000000..492d482
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepository.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.data.repository
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.ActivityTaskManager
+import android.app.TaskStackListener
+import android.os.IBinder
+import android.util.Log
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.withContext
+
+/** Implementation of [TasksRepository] that uses [ActivityTaskManager] as the data source. */
+@SysUISingleton
+class ActivityTaskManagerTasksRepository
+@Inject
+constructor(
+ private val activityTaskManager: ActivityTaskManager,
+ @Application private val applicationScope: CoroutineScope,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+) : TasksRepository {
+
+ override suspend fun findRunningTaskFromWindowContainerToken(
+ windowContainerToken: IBinder
+ ): RunningTaskInfo? =
+ getRunningTasks().firstOrNull { taskInfo ->
+ taskInfo.token.asBinder() == windowContainerToken
+ }
+
+ private suspend fun getRunningTasks(): List<RunningTaskInfo> =
+ withContext(backgroundDispatcher) { activityTaskManager.getTasks(Integer.MAX_VALUE) }
+
+ override val foregroundTask: Flow<RunningTaskInfo> =
+ conflatedCallbackFlow {
+ val listener =
+ object : TaskStackListener() {
+ override fun onTaskMovedToFront(taskInfo: RunningTaskInfo) {
+ Log.d(TAG, "onTaskMovedToFront: $taskInfo")
+ trySendWithFailureLogging(taskInfo, TAG)
+ }
+ }
+ activityTaskManager.registerTaskStackListener(listener)
+ awaitClose { activityTaskManager.unregisterTaskStackListener(listener) }
+ }
+ .shareIn(applicationScope, SharingStarted.Lazily, replay = 1)
+
+ companion object {
+ private const val TAG = "TasksRepository"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepository.kt
new file mode 100644
index 0000000..38d4e69
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepository.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.data.repository
+
+import android.media.projection.MediaProjectionInfo
+import android.media.projection.MediaProjectionManager
+import android.os.Handler
+import android.util.Log
+import android.view.ContentRecordingSession
+import android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.mediaprojection.taskswitcher.data.model.MediaProjectionState
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.launch
+
+@SysUISingleton
+class MediaProjectionManagerRepository
+@Inject
+constructor(
+ private val mediaProjectionManager: MediaProjectionManager,
+ @Main private val handler: Handler,
+ @Application private val applicationScope: CoroutineScope,
+ private val tasksRepository: TasksRepository,
+) : MediaProjectionRepository {
+
+ override val mediaProjectionState: Flow<MediaProjectionState> =
+ conflatedCallbackFlow {
+ val callback =
+ object : MediaProjectionManager.Callback() {
+ override fun onStart(info: MediaProjectionInfo?) {
+ Log.d(TAG, "MediaProjectionManager.Callback#onStart")
+ trySendWithFailureLogging(MediaProjectionState.NotProjecting, TAG)
+ }
+
+ override fun onStop(info: MediaProjectionInfo?) {
+ Log.d(TAG, "MediaProjectionManager.Callback#onStop")
+ trySendWithFailureLogging(MediaProjectionState.NotProjecting, TAG)
+ }
+
+ override fun onRecordingSessionSet(
+ info: MediaProjectionInfo,
+ session: ContentRecordingSession?
+ ) {
+ Log.d(TAG, "MediaProjectionManager.Callback#onSessionStarted: $session")
+ launch { trySendWithFailureLogging(stateForSession(session), TAG) }
+ }
+ }
+ mediaProjectionManager.addCallback(callback, handler)
+ awaitClose { mediaProjectionManager.removeCallback(callback) }
+ }
+ .shareIn(scope = applicationScope, started = SharingStarted.Lazily, replay = 1)
+
+ private suspend fun stateForSession(session: ContentRecordingSession?): MediaProjectionState {
+ if (session == null) {
+ return MediaProjectionState.NotProjecting
+ }
+ if (session.contentToRecord == RECORD_CONTENT_DISPLAY || session.tokenToRecord == null) {
+ return MediaProjectionState.EntireScreen
+ }
+ val matchingTask =
+ tasksRepository.findRunningTaskFromWindowContainerToken(session.tokenToRecord)
+ ?: return MediaProjectionState.EntireScreen
+ return MediaProjectionState.SingleTask(matchingTask)
+ }
+
+ companion object {
+ private const val TAG = "MediaProjectionMngrRepo"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionRepository.kt
new file mode 100644
index 0000000..5bec692
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionRepository.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.data.repository
+
+import com.android.systemui.mediaprojection.taskswitcher.data.model.MediaProjectionState
+import kotlinx.coroutines.flow.Flow
+
+/** Represents a repository to retrieve and change data related to media projection. */
+interface MediaProjectionRepository {
+
+ /** Represents the current [MediaProjectionState]. */
+ val mediaProjectionState: Flow<MediaProjectionState>
+}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/NoOpMediaProjectionRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/NoOpMediaProjectionRepository.kt
new file mode 100644
index 0000000..544eb6b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/NoOpMediaProjectionRepository.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.mediaprojection.taskswitcher.data.model.MediaProjectionState
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emptyFlow
+
+/**
+ * No-op implementation of [MediaProjectionRepository] that does nothing. Currently used as a
+ * placeholder, while the real implementation is not completed.
+ */
+@SysUISingleton
+class NoOpMediaProjectionRepository @Inject constructor() : MediaProjectionRepository {
+
+ override val mediaProjectionState: Flow<MediaProjectionState> = emptyFlow()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/TasksRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/TasksRepository.kt
new file mode 100644
index 0000000..6a535e4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/TasksRepository.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.data.repository
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.os.IBinder
+import kotlinx.coroutines.flow.Flow
+
+/** Repository responsible for retrieving data related to running tasks. */
+interface TasksRepository {
+
+ /**
+ * Tries to find a [RunningTaskInfo] with a matching window container token. Returns `null` when
+ * no matching task was found.
+ */
+ suspend fun findRunningTaskFromWindowContainerToken(
+ windowContainerToken: IBinder
+ ): RunningTaskInfo?
+
+ /**
+ * Emits a stream of [RunningTaskInfo] that have been moved to the foreground.
+ *
+ * Note: when subscribing for the first time, it will not immediately emit the current
+ * foreground task. Only after a change in foreground task has occurred.
+ */
+ val foregroundTask: Flow<RunningTaskInfo>
+}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractor.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractor.kt
new file mode 100644
index 0000000..fc5cf7d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractor.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.domain.interactor
+
+import android.app.TaskInfo
+import android.content.Intent
+import android.util.Log
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.mediaprojection.taskswitcher.data.model.MediaProjectionState
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.MediaProjectionRepository
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.TasksRepository
+import com.android.systemui.mediaprojection.taskswitcher.domain.model.TaskSwitchState
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+
+/** Interactor with logic related to task switching in the context of media projection. */
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class TaskSwitchInteractor
+@Inject
+constructor(
+ mediaProjectionRepository: MediaProjectionRepository,
+ private val tasksRepository: TasksRepository,
+) {
+
+ /**
+ * Emits a stream of changes to the state of task switching, in the context of media projection.
+ */
+ val taskSwitchChanges: Flow<TaskSwitchState> =
+ mediaProjectionRepository.mediaProjectionState.flatMapLatest { projectionState ->
+ Log.d(TAG, "MediaProjectionState -> $projectionState")
+ when (projectionState) {
+ is MediaProjectionState.SingleTask -> {
+ val projectedTask = projectionState.task
+ tasksRepository.foregroundTask.map { foregroundTask ->
+ if (hasForegroundTaskSwitched(projectedTask, foregroundTask)) {
+ TaskSwitchState.TaskSwitched(projectedTask, foregroundTask)
+ } else {
+ TaskSwitchState.TaskUnchanged
+ }
+ }
+ }
+ is MediaProjectionState.EntireScreen,
+ is MediaProjectionState.NotProjecting -> {
+ flowOf(TaskSwitchState.NotProjectingTask)
+ }
+ }
+ }
+
+ /**
+ * Returns whether tasks have been switched.
+ *
+ * Always returns `false` when launcher is in the foreground. The reason is that when going to
+ * recents to switch apps, launcher becomes the new foreground task, and we don't want to show
+ * the notification then.
+ */
+ private fun hasForegroundTaskSwitched(projectedTask: TaskInfo, foregroundTask: TaskInfo) =
+ projectedTask.taskId != foregroundTask.taskId && !foregroundTask.isLauncher
+
+ private val TaskInfo.isLauncher
+ get() =
+ baseIntent.hasCategory(Intent.CATEGORY_HOME) && baseIntent.action == Intent.ACTION_MAIN
+
+ companion object {
+ private const val TAG = "TaskSwitchInteractor"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/model/TaskSwitchState.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/model/TaskSwitchState.kt
new file mode 100644
index 0000000..cd1258e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/model/TaskSwitchState.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.domain.model
+
+import android.app.TaskInfo
+
+/** Represents tha state of task switching in the context of single task media projection. */
+sealed interface TaskSwitchState {
+ /** Currently no task is being projected. */
+ object NotProjectingTask : TaskSwitchState
+ /** The foreground task is the same as the task that is currently being projected. */
+ object TaskUnchanged : TaskSwitchState
+ /** The foreground task is a different one to the task it currently being projected. */
+ data class TaskSwitched(val projectedTask: TaskInfo, val foregroundTask: TaskInfo) :
+ TaskSwitchState
+}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinator.kt
new file mode 100644
index 0000000..a4f4076
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinator.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.ui
+
+import android.content.Context
+import android.util.Log
+import android.widget.Toast
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.mediaprojection.taskswitcher.ui.model.TaskSwitcherNotificationUiState.NotShowing
+import com.android.systemui.mediaprojection.taskswitcher.ui.model.TaskSwitcherNotificationUiState.Showing
+import com.android.systemui.mediaprojection.taskswitcher.ui.viewmodel.TaskSwitcherNotificationViewModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.launch
+
+/** Coordinator responsible for showing/hiding the task switcher notification. */
+@SysUISingleton
+class TaskSwitcherNotificationCoordinator
+@Inject
+constructor(
+ private val context: Context,
+ @Application private val applicationScope: CoroutineScope,
+ @Main private val mainDispatcher: CoroutineDispatcher,
+ private val viewModel: TaskSwitcherNotificationViewModel,
+) {
+
+ fun start() {
+ applicationScope.launch {
+ viewModel.uiState.flowOn(mainDispatcher).collect { uiState ->
+ Log.d(TAG, "uiState -> $uiState")
+ when (uiState) {
+ is Showing -> showNotification(uiState)
+ is NotShowing -> hideNotification()
+ }
+ }
+ }
+ }
+
+ private fun showNotification(uiState: Showing) {
+ val text =
+ """
+ Sharing pauses when you switch apps.
+ Share this app instead.
+ Switch back.
+ """
+ .trimIndent()
+ // TODO(b/286201515): Create actual notification.
+ Toast.makeText(context, text, Toast.LENGTH_SHORT).show()
+ }
+
+ private fun hideNotification() {}
+
+ companion object {
+ private const val TAG = "TaskSwitchNotifCoord"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/model/TaskSwitcherNotificationUiState.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/model/TaskSwitcherNotificationUiState.kt
new file mode 100644
index 0000000..21aee72
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/model/TaskSwitcherNotificationUiState.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.ui.model
+
+import android.app.TaskInfo
+
+/** Represents the UI state for the task switcher notification. */
+sealed interface TaskSwitcherNotificationUiState {
+ /** The notification should not be shown. */
+ object NotShowing : TaskSwitcherNotificationUiState
+ /** The notification should be shown. */
+ data class Showing(
+ val projectedTask: TaskInfo,
+ val foregroundTask: TaskInfo,
+ ) : TaskSwitcherNotificationUiState
+}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModel.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModel.kt
new file mode 100644
index 0000000..d9754d4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModel.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.ui.viewmodel
+
+import android.util.Log
+import com.android.systemui.mediaprojection.taskswitcher.domain.interactor.TaskSwitchInteractor
+import com.android.systemui.mediaprojection.taskswitcher.domain.model.TaskSwitchState
+import com.android.systemui.mediaprojection.taskswitcher.ui.model.TaskSwitcherNotificationUiState
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+class TaskSwitcherNotificationViewModel @Inject constructor(interactor: TaskSwitchInteractor) {
+
+ val uiState: Flow<TaskSwitcherNotificationUiState> =
+ interactor.taskSwitchChanges.map { taskSwitchChange ->
+ Log.d(TAG, "taskSwitchChange: $taskSwitchChange")
+ when (taskSwitchChange) {
+ is TaskSwitchState.TaskSwitched -> {
+ TaskSwitcherNotificationUiState.Showing(
+ projectedTask = taskSwitchChange.projectedTask,
+ foregroundTask = taskSwitchChange.foregroundTask,
+ )
+ }
+ is TaskSwitchState.NotProjectingTask,
+ is TaskSwitchState.TaskUnchanged -> {
+ TaskSwitcherNotificationUiState.NotShowing
+ }
+ }
+ }
+
+ companion object {
+ private const val TAG = "TaskSwitchNotifVM"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
index 63276fe..99daf36 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
@@ -28,18 +28,21 @@
import android.os.PatternMatcher;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.util.Log;
+import androidx.annotation.NonNull;
+
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -64,22 +67,21 @@
private Context mCurrentUserContext;
private final IOverlayManager mOverlayManager;
private final Executor mUiBgExecutor;
+ private final UserTracker mUserTracker;
private ArrayList<ModeChangedListener> mListeners = new ArrayList<>();
- private final DeviceProvisionedController.DeviceProvisionedListener mDeviceProvisionedCallback =
- new DeviceProvisionedController.DeviceProvisionedListener() {
- @Override
- public void onUserSwitched() {
- if (DEBUG) {
- Log.d(TAG, "onUserSwitched: "
- + ActivityManagerWrapper.getInstance().getCurrentUserId());
- }
+ private final UserTracker.Callback mUserTrackerCallback = new UserTracker.Callback() {
+ @Override
+ public void onUserChanged(int newUser, @NonNull Context userContext) {
+ if (DEBUG) {
+ Log.d(TAG, "onUserChanged: "
+ + newUser);
+ }
- // Update the nav mode for the current user
- updateCurrentInteractionMode(true /* notify */);
- }
- };
+ updateCurrentInteractionMode(true /* notify */);
+ }
+ };
// The primary user SysUI process doesn't get AppInfo changes from overlay package changes for
// the secondary user (b/158613864), so we need to update the interaction mode here as well
@@ -97,19 +99,20 @@
@Inject
public NavigationModeController(Context context,
- DeviceProvisionedController deviceProvisionedController,
ConfigurationController configurationController,
+ UserTracker userTracker,
+ @Main Executor mainExecutor,
@UiBackground Executor uiBgExecutor,
DumpManager dumpManager) {
mContext = context;
mCurrentUserContext = context;
+ mUserTracker = userTracker;
+ mUserTracker.addCallback(mUserTrackerCallback, mainExecutor);
mOverlayManager = IOverlayManager.Stub.asInterface(
ServiceManager.getService(Context.OVERLAY_SERVICE));
mUiBgExecutor = uiBgExecutor;
dumpManager.registerDumpable(getClass().getSimpleName(), this);
- deviceProvisionedController.addCallback(mDeviceProvisionedCallback);
-
IntentFilter overlayFilter = new IntentFilter(ACTION_OVERLAY_CHANGED);
overlayFilter.addDataScheme("package");
overlayFilter.addDataSchemeSpecificPart("android", PatternMatcher.PATTERN_LITERAL);
@@ -129,6 +132,7 @@
}
public void updateCurrentInteractionMode(boolean notify) {
+ Trace.beginSection("NMC#updateCurrentInteractionMode");
mCurrentUserContext = getCurrentUserContext();
int mode = getCurrentInteractionMode(mCurrentUserContext);
mUiBgExecutor.execute(() ->
@@ -144,6 +148,7 @@
mListeners.get(i).onNavigationModeChanged(mode);
}
}
+ Trace.endSection();
}
public int addListener(ModeChangedListener listener) {
@@ -171,7 +176,7 @@
}
public Context getCurrentUserContext() {
- int userId = ActivityManagerWrapper.getInstance().getCurrentUserId();
+ int userId = mUserTracker.getUserId();
if (DEBUG) {
Log.d(TAG, "getCurrentUserContext: contextUser=" + mContext.getUserId()
+ " currentUser=" + userId);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
index e7e1cc9..75106e7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
@@ -42,6 +42,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.AuthRippleController;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.doze.util.BurnInHelperKt;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
@@ -93,6 +94,7 @@
protected @Mock KeyguardTransitionRepository mTransitionRepository;
protected FakeExecutor mDelayableExecutor = new FakeExecutor(new FakeSystemClock());
protected FakeFeatureFlags mFeatureFlags;
+ protected @Mock PrimaryBouncerInteractor mPrimaryBouncerInteractor;
protected LockIconViewController mUnderTest;
@@ -163,7 +165,8 @@
new KeyguardTransitionInteractor(mTransitionRepository,
TestScopeProvider.getTestScope().getBackgroundScope()),
KeyguardInteractorFactory.create(mFeatureFlags).getKeyguardInteractor(),
- mFeatureFlags
+ mFeatureFlags,
+ mPrimaryBouncerInteractor
);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
index b6287598..ed6a891 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
@@ -33,6 +33,7 @@
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.Pair;
+import android.view.View;
import androidx.test.filters.SmallTest;
@@ -267,4 +268,75 @@
// THEN the lock icon is shown
verify(mLockIconView).setContentDescription(LOCKED_LABEL);
}
+
+ @Test
+ public void lockIconAccessibility_notVisibleToUser() {
+ // GIVEN lock icon controller is initialized and view is attached
+ init(/* useMigrationFlag= */false);
+ captureKeyguardStateCallback();
+ captureKeyguardUpdateMonitorCallback();
+
+ // GIVEN user has unlocked with a biometric auth (ie: face auth)
+ // and biometric running state changes
+ when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(true);
+ mKeyguardUpdateMonitorCallback.onBiometricRunningStateChanged(false,
+ BiometricSourceType.FACE);
+ reset(mLockIconView);
+ when(mLockIconView.isVisibleToUser()).thenReturn(false);
+
+ // WHEN the unlocked state changes
+ when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(false);
+ mKeyguardStateCallback.onUnlockedChanged();
+
+ // THEN the lock icon is shown
+ verify(mLockIconView).setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ }
+
+ @Test
+ public void lockIconAccessibility_bouncerAnimatingAway() {
+ // GIVEN lock icon controller is initialized and view is attached
+ init(/* useMigrationFlag= */false);
+ captureKeyguardStateCallback();
+ captureKeyguardUpdateMonitorCallback();
+
+ // GIVEN user has unlocked with a biometric auth (ie: face auth)
+ // and biometric running state changes
+ when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(true);
+ mKeyguardUpdateMonitorCallback.onBiometricRunningStateChanged(false,
+ BiometricSourceType.FACE);
+ reset(mLockIconView);
+ when(mLockIconView.isVisibleToUser()).thenReturn(true);
+ when(mPrimaryBouncerInteractor.isAnimatingAway()).thenReturn(true);
+
+ // WHEN the unlocked state changes
+ when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(false);
+ mKeyguardStateCallback.onUnlockedChanged();
+
+ // THEN the lock icon is shown
+ verify(mLockIconView).setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ }
+
+ @Test
+ public void lockIconAccessibility_bouncerNotAnimatingAway_viewVisible() {
+ // GIVEN lock icon controller is initialized and view is attached
+ init(/* useMigrationFlag= */false);
+ captureKeyguardStateCallback();
+ captureKeyguardUpdateMonitorCallback();
+
+ // GIVEN user has unlocked with a biometric auth (ie: face auth)
+ // and biometric running state changes
+ when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(true);
+ mKeyguardUpdateMonitorCallback.onBiometricRunningStateChanged(false,
+ BiometricSourceType.FACE);
+ reset(mLockIconView);
+ when(mLockIconView.isVisibleToUser()).thenReturn(true);
+ when(mPrimaryBouncerInteractor.isAnimatingAway()).thenReturn(false);
+
+ // WHEN the unlocked state changes
+ when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(false);
+ mKeyguardStateCallback.onUnlockedChanged();
+
+ // THEN the lock icon is shown
+ verify(mLockIconView).setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
index f64db78f..caf230d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
@@ -16,8 +16,10 @@
package com.android.systemui.accessibility;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
@@ -185,6 +187,19 @@
verify(mMagnificationSettingsController).closeMagnificationSettings();
}
+ @Test
+ public void onUserMagnificationScaleChanged() throws RemoteException {
+ final int testUserId = 1;
+ final float testScale = 3.0f;
+ mIWindowMagnificationConnection.onUserMagnificationScaleChanged(
+ testUserId, TEST_DISPLAY, testScale);
+ waitForIdleSync();
+
+ assertTrue(mWindowMagnification.mUsersScales.contains(testUserId));
+ assertEquals(mWindowMagnification.mUsersScales.get(testUserId).get(TEST_DISPLAY),
+ (Float) testScale);
+ }
+
private class FakeControllerSupplier extends
DisplayIdIndexSupplier<WindowMagnificationController> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt
index a10f5dd..d5e6881 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt
@@ -25,6 +25,7 @@
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView
+import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView.OnSeekBarWithIconButtonsChangeListener
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.capture
@@ -67,7 +68,7 @@
@Mock private lateinit var userTracker: UserTracker
@Captor
- private lateinit var seekBarChangeCaptor: ArgumentCaptor<SeekBar.OnSeekBarChangeListener>
+ private lateinit var seekBarChangeCaptor: ArgumentCaptor<OnSeekBarWithIconButtonsChangeListener>
@Before
fun setUp() {
@@ -176,16 +177,17 @@
fun progressChanged_keyWasNotSetBefore_fontScalingHasBeenChangedIsOn() {
fontScalingDialog.show()
- val seekBarWithIconButtonsView: SeekBarWithIconButtonsView =
- fontScalingDialog.findViewById(R.id.font_scaling_slider)!!
+ val iconStartFrame: ViewGroup = fontScalingDialog.findViewById(R.id.icon_start_frame)!!
secureSettings.putIntForUser(
Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
OFF,
userTracker.userId
)
- // Default seekbar progress for font size is 1, set it to another progress 0
- seekBarWithIconButtonsView.setProgress(0)
+ // Default seekbar progress for font size is 1, click start icon to decrease the progress
+ iconStartFrame.performClick()
+ backgroundDelayableExecutor.runAllReady()
+ backgroundDelayableExecutor.advanceClockToNext()
backgroundDelayableExecutor.runAllReady()
val currentSettings =
@@ -208,7 +210,7 @@
)
.thenReturn(slider)
fontScalingDialog.show()
- verify(slider).setOnSeekBarChangeListener(capture(seekBarChangeCaptor))
+ verify(slider).setOnSeekBarWithIconButtonsChangeListener(capture(seekBarChangeCaptor))
val seekBar: SeekBar = slider.findViewById(R.id.seekbar)!!
// Default seekbar progress for font size is 1, simulate dragging to 0 without
@@ -237,6 +239,15 @@
backgroundDelayableExecutor.advanceClockToNext()
backgroundDelayableExecutor.runAllReady()
+ // SeekBar interaction is finalized.
+ seekBarChangeCaptor.value.onUserInteractionFinalized(
+ seekBar,
+ OnSeekBarWithIconButtonsChangeListener.ControlUnitType.SLIDER
+ )
+ backgroundDelayableExecutor.runAllReady()
+ backgroundDelayableExecutor.advanceClockToNext()
+ backgroundDelayableExecutor.runAllReady()
+
// Verify that the scale of font size has been updated.
systemScale =
systemSettings.getFloatForUser(
@@ -258,7 +269,7 @@
)
.thenReturn(slider)
fontScalingDialog.show()
- verify(slider).setOnSeekBarChangeListener(capture(seekBarChangeCaptor))
+ verify(slider).setOnSeekBarWithIconButtonsChangeListener(capture(seekBarChangeCaptor))
val seekBar: SeekBar = slider.findViewById(R.id.seekbar)!!
// Default seekbar progress for font size is 1, simulate dragging to 0 without
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt
new file mode 100644
index 0000000..7de78a6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics
+
+import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.RoboPilotTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.shade.ShadeExpansionStateManager
+import com.android.systemui.statusbar.phone.SystemUIDialogManager
+import org.junit.Assert.assertFalse
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.junit.MockitoJUnit
+
+@SmallTest
+@RoboPilotTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper
+class UdfpsBpViewControllerTest : SysuiTestCase() {
+
+ @JvmField @Rule var rule = MockitoJUnit.rule()
+
+ @Mock lateinit var udfpsBpView: UdfpsBpView
+ @Mock lateinit var statusBarStateController: StatusBarStateController
+ @Mock lateinit var shadeExpansionStateManager: ShadeExpansionStateManager
+ @Mock lateinit var systemUIDialogManager: SystemUIDialogManager
+ @Mock lateinit var dumpManager: DumpManager
+
+ private lateinit var udfpsBpViewController: UdfpsBpViewController
+
+ @Before
+ fun setup() {
+ udfpsBpViewController =
+ UdfpsBpViewController(
+ udfpsBpView,
+ statusBarStateController,
+ shadeExpansionStateManager,
+ systemUIDialogManager,
+ dumpManager
+ )
+ }
+
+ @Test
+ fun testShouldNeverPauseAuth() {
+ assertFalse(udfpsBpViewController.shouldPauseAuth())
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
index 22ac1b6..f811ce0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
@@ -42,6 +42,7 @@
)
private val underTest =
PinBouncerViewModel(
+ applicationContext = context,
applicationScope = testScope.backgroundScope,
interactor =
utils.bouncerInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
index 61432e2..608a187 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
@@ -67,6 +67,7 @@
)
private val underTest =
PinBouncerViewModel(
+ applicationContext = context,
applicationScope = testScope.backgroundScope,
interactor = bouncerInteractor,
isInputEnabled = MutableStateFlow(true).asStateFlow(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java
index afd9be5..f0006e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java
@@ -18,6 +18,13 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.ViewGroup;
@@ -28,10 +35,15 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView.OnSeekBarWithIconButtonsChangeListener;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
/**
* Tests for {@link SeekBarWithIconButtonsView}
@@ -48,14 +60,22 @@
private SeekBar mSeekbar;
private SeekBarWithIconButtonsView mIconDiscreteSliderLinearLayout;
+ @Mock
+ private OnSeekBarWithIconButtonsChangeListener mOnSeekBarChangeListener;
+
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
mIconDiscreteSliderLinearLayout = new SeekBarWithIconButtonsView(mContext);
mIconStart = mIconDiscreteSliderLinearLayout.findViewById(R.id.icon_start);
mIconEnd = mIconDiscreteSliderLinearLayout.findViewById(R.id.icon_end);
mIconStartFrame = mIconDiscreteSliderLinearLayout.findViewById(R.id.icon_start_frame);
mIconEndFrame = mIconDiscreteSliderLinearLayout.findViewById(R.id.icon_end_frame);
mSeekbar = mIconDiscreteSliderLinearLayout.findViewById(R.id.seekbar);
+
+ mIconDiscreteSliderLinearLayout.setOnSeekBarWithIconButtonsChangeListener(
+ mOnSeekBarChangeListener);
}
@Test
@@ -109,6 +129,49 @@
}
@Test
+ public void setProgress_onlyOnProgressChangedTriggeredWithFromUserFalse() {
+ reset(mOnSeekBarChangeListener);
+ mIconDiscreteSliderLinearLayout.setProgress(1);
+
+ verify(mOnSeekBarChangeListener).onProgressChanged(
+ eq(mSeekbar), /* progress= */ eq(1), /* fromUser= */ eq(false));
+ verify(mOnSeekBarChangeListener, never()).onStartTrackingTouch(/* seekBar= */ any());
+ verify(mOnSeekBarChangeListener, never()).onStopTrackingTouch(/* seekBar= */ any());
+ verify(mOnSeekBarChangeListener, never()).onUserInteractionFinalized(
+ /* seekBar= */any(), /* control= */ anyInt());
+ }
+
+ @Test
+ public void clickIconEnd_triggerCallbacksInSequence() {
+ final int magnitude = mIconDiscreteSliderLinearLayout.getChangeMagnitude();
+ mIconDiscreteSliderLinearLayout.setProgress(0);
+ reset(mOnSeekBarChangeListener);
+
+ mIconEndFrame.performClick();
+
+ InOrder inOrder = Mockito.inOrder(mOnSeekBarChangeListener);
+ inOrder.verify(mOnSeekBarChangeListener).onProgressChanged(
+ eq(mSeekbar), /* progress= */ eq(magnitude), /* fromUser= */ eq(true));
+ inOrder.verify(mOnSeekBarChangeListener).onUserInteractionFinalized(
+ eq(mSeekbar), eq(OnSeekBarWithIconButtonsChangeListener.ControlUnitType.BUTTON));
+ }
+
+ @Test
+ public void clickIconStart_triggerCallbacksInSequence() {
+ final int magnitude = mIconDiscreteSliderLinearLayout.getChangeMagnitude();
+ mIconDiscreteSliderLinearLayout.setProgress(magnitude);
+ reset(mOnSeekBarChangeListener);
+
+ mIconStartFrame.performClick();
+
+ InOrder inOrder = Mockito.inOrder(mOnSeekBarChangeListener);
+ inOrder.verify(mOnSeekBarChangeListener).onProgressChanged(
+ eq(mSeekbar), /* progress= */ eq(0), /* fromUser= */ eq(true));
+ inOrder.verify(mOnSeekBarChangeListener).onUserInteractionFinalized(
+ eq(mSeekbar), eq(OnSeekBarWithIconButtonsChangeListener.ControlUnitType.BUTTON));
+ }
+
+ @Test
public void setProgressStateLabels_getExpectedStateDescriptionOnInitialization() {
String[] stateLabels = new String[]{"1", "2", "3", "4", "5"};
mIconDiscreteSliderLinearLayout.setMax(stateLabels.length);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/MediaProjectionTaskSwitcherCoreStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/MediaProjectionTaskSwitcherCoreStartableTest.kt
new file mode 100644
index 0000000..bcbf666
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/MediaProjectionTaskSwitcherCoreStartableTest.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.mediaprojection.taskswitcher.ui.TaskSwitcherNotificationCoordinator
+import com.android.systemui.util.mockito.whenever
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class MediaProjectionTaskSwitcherCoreStartableTest : SysuiTestCase() {
+
+ @Mock private lateinit var flags: FeatureFlags
+ @Mock private lateinit var coordinator: TaskSwitcherNotificationCoordinator
+
+ private lateinit var coreStartable: MediaProjectionTaskSwitcherCoreStartable
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ coreStartable = MediaProjectionTaskSwitcherCoreStartable(coordinator, flags)
+ }
+
+ @Test
+ fun start_flagEnabled_startsCoordinator() {
+ whenever(flags.isEnabled(Flags.PARTIAL_SCREEN_SHARING_TASK_SWITCHER)).thenReturn(true)
+
+ coreStartable.start()
+
+ verify(coordinator).start()
+ }
+
+ @Test
+ fun start_flagDisabled_doesNotStartCoordinator() {
+ whenever(flags.isEnabled(Flags.PARTIAL_SCREEN_SHARING_TASK_SWITCHER)).thenReturn(false)
+
+ coreStartable.start()
+
+ verifyZeroInteractions(coordinator)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepositoryTest.kt
new file mode 100644
index 0000000..83932b0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepositoryTest.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.data.repository
+
+import android.os.Binder
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeActivityTaskManager.Companion.createTask
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeActivityTaskManager.Companion.createToken
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class ActivityTaskManagerTasksRepositoryTest : SysuiTestCase() {
+
+ private val fakeActivityTaskManager = FakeActivityTaskManager()
+
+ private val dispatcher = UnconfinedTestDispatcher()
+ private val testScope = TestScope(dispatcher)
+
+ private val repo =
+ ActivityTaskManagerTasksRepository(
+ activityTaskManager = fakeActivityTaskManager.activityTaskManager,
+ applicationScope = testScope.backgroundScope,
+ backgroundDispatcher = dispatcher
+ )
+
+ @Test
+ fun findRunningTaskFromWindowContainerToken_noMatch_returnsNull() {
+ fakeActivityTaskManager.addRunningTasks(createTask(taskId = 1), createTask(taskId = 2))
+
+ testScope.runTest {
+ val matchingTask =
+ repo.findRunningTaskFromWindowContainerToken(windowContainerToken = Binder())
+
+ assertThat(matchingTask).isNull()
+ }
+ }
+
+ @Test
+ fun findRunningTaskFromWindowContainerToken_matchingToken_returnsTaskInfo() {
+ val expectedToken = createToken()
+ val expectedTask = createTask(taskId = 1, token = expectedToken)
+
+ fakeActivityTaskManager.addRunningTasks(
+ createTask(taskId = 2),
+ expectedTask,
+ )
+
+ testScope.runTest {
+ val actualTask =
+ repo.findRunningTaskFromWindowContainerToken(
+ windowContainerToken = expectedToken.asBinder()
+ )
+
+ assertThat(actualTask).isEqualTo(expectedTask)
+ }
+ }
+
+ @Test
+ fun foregroundTask_returnsStreamOfTasksMovedToFront() =
+ testScope.runTest {
+ val foregroundTask by collectLastValue(repo.foregroundTask)
+
+ fakeActivityTaskManager.moveTaskToForeground(createTask(taskId = 1))
+ assertThat(foregroundTask?.taskId).isEqualTo(1)
+
+ fakeActivityTaskManager.moveTaskToForeground(createTask(taskId = 2))
+ assertThat(foregroundTask?.taskId).isEqualTo(2)
+
+ fakeActivityTaskManager.moveTaskToForeground(createTask(taskId = 3))
+ assertThat(foregroundTask?.taskId).isEqualTo(3)
+ }
+
+ @Test
+ fun foregroundTask_lastValueIsCached() =
+ testScope.runTest {
+ val foregroundTaskA by collectLastValue(repo.foregroundTask)
+ fakeActivityTaskManager.moveTaskToForeground(createTask(taskId = 1))
+ assertThat(foregroundTaskA?.taskId).isEqualTo(1)
+
+ val foregroundTaskB by collectLastValue(repo.foregroundTask)
+ assertThat(foregroundTaskB?.taskId).isEqualTo(1)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeActivityTaskManager.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeActivityTaskManager.kt
new file mode 100644
index 0000000..1c4870b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeActivityTaskManager.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.data.repository
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.ActivityTaskManager
+import android.app.TaskStackListener
+import android.content.Intent
+import android.window.IWindowContainerToken
+import android.window.WindowContainerToken
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+
+class FakeActivityTaskManager {
+
+ private val runningTasks = mutableListOf<RunningTaskInfo>()
+ private val taskTaskListeners = mutableListOf<TaskStackListener>()
+
+ val activityTaskManager = mock<ActivityTaskManager>()
+
+ init {
+ whenever(activityTaskManager.registerTaskStackListener(any())).thenAnswer {
+ taskTaskListeners += it.arguments[0] as TaskStackListener
+ return@thenAnswer Unit
+ }
+ whenever(activityTaskManager.unregisterTaskStackListener(any())).thenAnswer {
+ taskTaskListeners -= it.arguments[0] as TaskStackListener
+ return@thenAnswer Unit
+ }
+ whenever(activityTaskManager.getTasks(any())).thenAnswer {
+ val maxNumTasks = it.arguments[0] as Int
+ return@thenAnswer runningTasks.take(maxNumTasks)
+ }
+ }
+
+ fun moveTaskToForeground(task: RunningTaskInfo) {
+ taskTaskListeners.forEach { it.onTaskMovedToFront(task) }
+ }
+
+ fun addRunningTasks(vararg tasks: RunningTaskInfo) {
+ runningTasks += tasks
+ }
+
+ companion object {
+
+ fun createTask(
+ taskId: Int,
+ token: WindowContainerToken = createToken(),
+ baseIntent: Intent = Intent()
+ ) =
+ RunningTaskInfo().apply {
+ this.taskId = taskId
+ this.token = token
+ this.baseIntent = baseIntent
+ }
+
+ fun createToken(): WindowContainerToken {
+ val realToken = object : IWindowContainerToken.Stub() {}
+ return WindowContainerToken(realToken)
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeMediaProjectionRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeMediaProjectionRepository.kt
new file mode 100644
index 0000000..c59fd60
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeMediaProjectionRepository.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.data.repository
+
+import android.app.TaskInfo
+import com.android.systemui.mediaprojection.taskswitcher.data.model.MediaProjectionState
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeMediaProjectionRepository : MediaProjectionRepository {
+
+ private val state = MutableStateFlow<MediaProjectionState>(MediaProjectionState.NotProjecting)
+
+ fun switchProjectedTask(newTask: TaskInfo) {
+ state.value = MediaProjectionState.SingleTask(newTask)
+ }
+
+ override val mediaProjectionState: Flow<MediaProjectionState> = state.asStateFlow()
+
+ fun projectEntireScreen() {
+ state.value = MediaProjectionState.EntireScreen
+ }
+
+ fun stopProjecting() {
+ state.value = MediaProjectionState.NotProjecting
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeTasksRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeTasksRepository.kt
new file mode 100644
index 0000000..593e389
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeTasksRepository.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.data.repository
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.content.Intent
+import android.os.IBinder
+import android.window.IWindowContainerToken
+import android.window.WindowContainerToken
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeTasksRepository : TasksRepository {
+
+ private val _foregroundTask = MutableStateFlow(DEFAULT_TASK)
+
+ override val foregroundTask: Flow<RunningTaskInfo> = _foregroundTask.asStateFlow()
+
+ private val runningTasks = mutableListOf(DEFAULT_TASK)
+
+ override suspend fun findRunningTaskFromWindowContainerToken(
+ windowContainerToken: IBinder
+ ): RunningTaskInfo? = runningTasks.firstOrNull { it.token.asBinder() == windowContainerToken }
+
+ fun addRunningTask(task: RunningTaskInfo) {
+ runningTasks.add(task)
+ }
+
+ fun moveTaskToForeground(task: RunningTaskInfo) {
+ _foregroundTask.value = task
+ }
+
+ companion object {
+ val DEFAULT_TASK = createTask(taskId = -1)
+ val LAUNCHER_INTENT: Intent = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
+
+ fun createTask(
+ taskId: Int,
+ token: WindowContainerToken = createToken(),
+ baseIntent: Intent = Intent()
+ ) =
+ RunningTaskInfo().apply {
+ this.taskId = taskId
+ this.token = token
+ this.baseIntent = baseIntent
+ }
+
+ fun createToken(): WindowContainerToken {
+ val realToken = object : IWindowContainerToken.Stub() {}
+ return WindowContainerToken(realToken)
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepositoryTest.kt
new file mode 100644
index 0000000..2b07465
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepositoryTest.kt
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.data.repository
+
+import android.media.projection.MediaProjectionInfo
+import android.media.projection.MediaProjectionManager
+import android.os.Binder
+import android.os.Handler
+import android.os.UserHandle
+import android.testing.AndroidTestingRunner
+import android.view.ContentRecordingSession
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.mediaprojection.taskswitcher.data.model.MediaProjectionState
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class MediaProjectionManagerRepositoryTest : SysuiTestCase() {
+
+ private val mediaProjectionManager = mock<MediaProjectionManager>()
+
+ private val dispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(dispatcher)
+ private val tasksRepo = FakeTasksRepository()
+
+ private lateinit var callback: MediaProjectionManager.Callback
+ private lateinit var repo: MediaProjectionManagerRepository
+
+ @Before
+ fun setUp() {
+ whenever(mediaProjectionManager.addCallback(any(), any())).thenAnswer {
+ callback = it.arguments[0] as MediaProjectionManager.Callback
+ return@thenAnswer Unit
+ }
+ repo =
+ MediaProjectionManagerRepository(
+ mediaProjectionManager = mediaProjectionManager,
+ handler = Handler.getMain(),
+ applicationScope = testScope.backgroundScope,
+ tasksRepository = tasksRepo
+ )
+ }
+
+ @Test
+ fun mediaProjectionState_onStart_emitsNotProjecting() =
+ testScope.runTest {
+ val state by collectLastValue(repo.mediaProjectionState)
+ runCurrent()
+
+ callback.onStart(TEST_MEDIA_INFO)
+
+ assertThat(state).isEqualTo(MediaProjectionState.NotProjecting)
+ }
+
+ @Test
+ fun mediaProjectionState_onStop_emitsNotProjecting() =
+ testScope.runTest {
+ val state by collectLastValue(repo.mediaProjectionState)
+ runCurrent()
+
+ callback.onStop(TEST_MEDIA_INFO)
+
+ assertThat(state).isEqualTo(MediaProjectionState.NotProjecting)
+ }
+
+ @Test
+ fun mediaProjectionState_onSessionSet_sessionNull_emitsNotProjecting() =
+ testScope.runTest {
+ val state by collectLastValue(repo.mediaProjectionState)
+ runCurrent()
+
+ callback.onRecordingSessionSet(TEST_MEDIA_INFO, /* session= */ null)
+
+ assertThat(state).isEqualTo(MediaProjectionState.NotProjecting)
+ }
+
+ @Test
+ fun mediaProjectionState_onSessionSet_contentToRecordDisplay_emitsEntireScreen() =
+ testScope.runTest {
+ val state by collectLastValue(repo.mediaProjectionState)
+ runCurrent()
+
+ val session = ContentRecordingSession.createDisplaySession(/* displayToMirror= */ 123)
+ callback.onRecordingSessionSet(TEST_MEDIA_INFO, session)
+
+ assertThat(state).isEqualTo(MediaProjectionState.EntireScreen)
+ }
+
+ @Test
+ fun mediaProjectionState_onSessionSet_tokenNull_emitsEntireScreen() =
+ testScope.runTest {
+ val state by collectLastValue(repo.mediaProjectionState)
+ runCurrent()
+
+ val session =
+ ContentRecordingSession.createTaskSession(/* taskWindowContainerToken= */ null)
+ callback.onRecordingSessionSet(TEST_MEDIA_INFO, session)
+
+ assertThat(state).isEqualTo(MediaProjectionState.EntireScreen)
+ }
+
+ @Test
+ fun mediaProjectionState_sessionSet_taskWithToken_noMatchingRunningTask_emitsEntireScreen() =
+ testScope.runTest {
+ val state by collectLastValue(repo.mediaProjectionState)
+ runCurrent()
+
+ val taskWindowContainerToken = Binder()
+ val session = ContentRecordingSession.createTaskSession(taskWindowContainerToken)
+ callback.onRecordingSessionSet(TEST_MEDIA_INFO, session)
+
+ assertThat(state).isEqualTo(MediaProjectionState.EntireScreen)
+ }
+
+ @Test
+ fun mediaProjectionState_sessionSet_taskWithToken_matchingRunningTask_emitsSingleTask() =
+ testScope.runTest {
+ val token = FakeTasksRepository.createToken()
+ val task = FakeTasksRepository.createTask(taskId = 1, token = token)
+ tasksRepo.addRunningTask(task)
+ val state by collectLastValue(repo.mediaProjectionState)
+ runCurrent()
+
+ val session = ContentRecordingSession.createTaskSession(token.asBinder())
+ callback.onRecordingSessionSet(TEST_MEDIA_INFO, session)
+
+ assertThat(state).isEqualTo(MediaProjectionState.SingleTask(task))
+ }
+
+ companion object {
+ val TEST_MEDIA_INFO =
+ MediaProjectionInfo(/* packageName= */ "com.test.package", UserHandle.CURRENT)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt
new file mode 100644
index 0000000..112950b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.domain.interactor
+
+import android.content.Intent
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.ActivityTaskManagerTasksRepository
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeActivityTaskManager
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeActivityTaskManager.Companion.createTask
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeMediaProjectionRepository
+import com.android.systemui.mediaprojection.taskswitcher.domain.model.TaskSwitchState
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class TaskSwitchInteractorTest : SysuiTestCase() {
+
+ private val dispatcher = UnconfinedTestDispatcher()
+ private val testScope = TestScope(dispatcher)
+
+ private val fakeActivityTaskManager = FakeActivityTaskManager()
+ private val mediaRepo = FakeMediaProjectionRepository()
+ private val tasksRepo =
+ ActivityTaskManagerTasksRepository(
+ activityTaskManager = fakeActivityTaskManager.activityTaskManager,
+ applicationScope = testScope.backgroundScope,
+ backgroundDispatcher = dispatcher
+ )
+
+ private val interactor = TaskSwitchInteractor(mediaRepo, tasksRepo)
+
+ @Test
+ fun taskSwitchChanges_notProjecting_foregroundTaskChange_emitsNotProjectingTask() =
+ testScope.runTest {
+ mediaRepo.stopProjecting()
+ val taskSwitchState by collectLastValue(interactor.taskSwitchChanges)
+
+ fakeActivityTaskManager.moveTaskToForeground(createTask(taskId = 1))
+
+ assertThat(taskSwitchState).isEqualTo(TaskSwitchState.NotProjectingTask)
+ }
+
+ @Test
+ fun taskSwitchChanges_projectingScreen_foregroundTaskChange_emitsNotProjectingTask() =
+ testScope.runTest {
+ mediaRepo.projectEntireScreen()
+ val taskSwitchState by collectLastValue(interactor.taskSwitchChanges)
+
+ fakeActivityTaskManager.moveTaskToForeground(createTask(taskId = 1))
+
+ assertThat(taskSwitchState).isEqualTo(TaskSwitchState.NotProjectingTask)
+ }
+
+ @Test
+ fun taskSwitchChanges_projectingTask_foregroundTaskDifferent_emitsTaskChanged() =
+ testScope.runTest {
+ val projectedTask = createTask(taskId = 0)
+ val foregroundTask = createTask(taskId = 1)
+ mediaRepo.switchProjectedTask(projectedTask)
+ val taskSwitchState by collectLastValue(interactor.taskSwitchChanges)
+
+ fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
+
+ assertThat(taskSwitchState)
+ .isEqualTo(
+ TaskSwitchState.TaskSwitched(
+ projectedTask = projectedTask,
+ foregroundTask = foregroundTask
+ )
+ )
+ }
+
+ @Test
+ fun taskSwitchChanges_projectingTask_foregroundTaskLauncher_emitsTaskUnchanged() =
+ testScope.runTest {
+ val projectedTask = createTask(taskId = 0)
+ val foregroundTask = createTask(taskId = 1, baseIntent = LAUNCHER_INTENT)
+ mediaRepo.switchProjectedTask(projectedTask)
+ val taskSwitchState by collectLastValue(interactor.taskSwitchChanges)
+
+ fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
+
+ assertThat(taskSwitchState).isEqualTo(TaskSwitchState.TaskUnchanged)
+ }
+
+ @Test
+ fun taskSwitchChanges_projectingTask_foregroundTaskSame_emitsTaskUnchanged() =
+ testScope.runTest {
+ val projectedTask = createTask(taskId = 0)
+ val foregroundTask = createTask(taskId = 0)
+ mediaRepo.switchProjectedTask(projectedTask)
+ val taskSwitchState by collectLastValue(interactor.taskSwitchChanges)
+
+ fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
+
+ assertThat(taskSwitchState).isEqualTo(TaskSwitchState.TaskUnchanged)
+ }
+
+ companion object {
+ private val LAUNCHER_INTENT: Intent =
+ Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModelTest.kt
new file mode 100644
index 0000000..ea44fb3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModelTest.kt
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.ui.viewmodel
+
+import android.content.Intent
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.ActivityTaskManagerTasksRepository
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeActivityTaskManager
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeActivityTaskManager.Companion.createTask
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeMediaProjectionRepository
+import com.android.systemui.mediaprojection.taskswitcher.domain.interactor.TaskSwitchInteractor
+import com.android.systemui.mediaprojection.taskswitcher.ui.model.TaskSwitcherNotificationUiState
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class TaskSwitcherNotificationViewModelTest : SysuiTestCase() {
+
+ private val dispatcher = UnconfinedTestDispatcher()
+ private val testScope = TestScope(dispatcher)
+
+ private val fakeActivityTaskManager = FakeActivityTaskManager()
+ private val mediaRepo = FakeMediaProjectionRepository()
+ private val tasksRepo =
+ ActivityTaskManagerTasksRepository(
+ activityTaskManager = fakeActivityTaskManager.activityTaskManager,
+ applicationScope = testScope.backgroundScope,
+ backgroundDispatcher = dispatcher
+ )
+ private val interactor = TaskSwitchInteractor(mediaRepo, tasksRepo)
+
+ private val viewModel = TaskSwitcherNotificationViewModel(interactor)
+
+ @Test
+ fun uiState_notProjecting_emitsNotShowing() =
+ testScope.runTest {
+ mediaRepo.stopProjecting()
+ val uiState by collectLastValue(viewModel.uiState)
+
+ assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing)
+ }
+
+ @Test
+ fun uiState_notProjecting_foregroundTaskChanged_emitsNotShowing() =
+ testScope.runTest {
+ mediaRepo.stopProjecting()
+ val uiState by collectLastValue(viewModel.uiState)
+
+ mediaRepo.switchProjectedTask(createTask(taskId = 1))
+
+ assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing)
+ }
+
+ @Test
+ fun uiState_projectingEntireScreen_emitsNotShowing() =
+ testScope.runTest {
+ mediaRepo.projectEntireScreen()
+ val uiState by collectLastValue(viewModel.uiState)
+
+ assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing)
+ }
+
+ @Test
+ fun uiState_projectingEntireScreen_foregroundTaskChanged_emitsNotShowing() =
+ testScope.runTest {
+ mediaRepo.projectEntireScreen()
+ val uiState by collectLastValue(viewModel.uiState)
+
+ mediaRepo.switchProjectedTask(createTask(taskId = 1))
+
+ assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing)
+ }
+
+ @Test
+ fun uiState_projectingTask_foregroundTaskChanged_different_emitsShowing() =
+ testScope.runTest {
+ val projectedTask = createTask(taskId = 1)
+ val foregroundTask = createTask(taskId = 2)
+ mediaRepo.switchProjectedTask(projectedTask)
+ val uiState by collectLastValue(viewModel.uiState)
+
+ fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
+
+ assertThat(uiState)
+ .isEqualTo(TaskSwitcherNotificationUiState.Showing(projectedTask, foregroundTask))
+ }
+
+ @Test
+ fun uiState_projectingTask_foregroundTaskChanged_same_emitsNotShowing() =
+ testScope.runTest {
+ val projectedTask = createTask(taskId = 1)
+ mediaRepo.switchProjectedTask(projectedTask)
+ val uiState by collectLastValue(viewModel.uiState)
+
+ fakeActivityTaskManager.moveTaskToForeground(projectedTask)
+
+ assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing)
+ }
+
+ @Test
+ fun uiState_projectingTask_foregroundTaskChanged_different_taskIsLauncher_emitsNotShowing() =
+ testScope.runTest {
+ val projectedTask = createTask(taskId = 1)
+ val foregroundTask = createTask(taskId = 2, baseIntent = LAUNCHER_INTENT)
+ mediaRepo.switchProjectedTask(projectedTask)
+ val uiState by collectLastValue(viewModel.uiState)
+
+ fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
+
+ assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing)
+ }
+
+ companion object {
+ private val LAUNCHER_INTENT: Intent =
+ Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
+ }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 87fbee7..f6948e9 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -502,6 +502,10 @@
@Override
public void onSourceBoundsChanged(int displayId, Rect bounds) {
if (shouldNotifyMagnificationChange(displayId, MAGNIFICATION_MODE_WINDOW)) {
+ // notify sysui the magnification scale changed on window magnifier
+ mWindowMagnificationMgr.onUserMagnificationScaleChanged(
+ mUserId, displayId, getWindowMagnificationMgr().getScale(displayId));
+
final MagnificationConfig config = new MagnificationConfig.Builder()
.setMode(MAGNIFICATION_MODE_WINDOW)
.setActivated(getWindowMagnificationMgr().isWindowMagnifierEnabled(displayId))
@@ -516,6 +520,10 @@
public void onFullScreenMagnificationChanged(int displayId, @NonNull Region region,
@NonNull MagnificationConfig config) {
if (shouldNotifyMagnificationChange(displayId, MAGNIFICATION_MODE_FULLSCREEN)) {
+ // notify sysui the magnification scale changed on fullscreen magnifier
+ mWindowMagnificationMgr.onUserMagnificationScaleChanged(
+ mUserId, displayId, config.getScale());
+
mAms.notifyMagnificationChanged(displayId, region, config);
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java
index 1202cfa..6c6394f 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java
@@ -201,6 +201,22 @@
return true;
}
+ boolean onUserMagnificationScaleChanged(int userId, int displayId, float scale) {
+ if (mTrace.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MAGNIFICATION_CONNECTION)) {
+ mTrace.logTrace(TAG + ".onMagnificationScaleUpdated",
+ FLAGS_WINDOW_MAGNIFICATION_CONNECTION, "displayId=" + displayId);
+ }
+ try {
+ mConnection.onUserMagnificationScaleChanged(userId, displayId, scale);
+ } catch (RemoteException e) {
+ if (DBG) {
+ Slog.e(TAG, "Error calling onMagnificationScaleUpdated()", e);
+ }
+ return false;
+ }
+ return true;
+ }
+
boolean setConnectionCallback(IWindowMagnificationConnectionCallback connectionCallback) {
if (mTrace.isA11yTracingEnabledForTypes(
FLAGS_WINDOW_MAGNIFICATION_CONNECTION
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index d07db3f..d96682c 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -827,6 +827,20 @@
}
/**
+ * Notify System UI the magnification scale on the specified display for userId is changed.
+ *
+ * @param userId the user id.
+ * @param displayId the logical display id.
+ * @param scale magnification scale.
+ */
+ public boolean onUserMagnificationScaleChanged(int userId, int displayId, float scale) {
+ synchronized (mLock) {
+ return mConnectionWrapper != null
+ && mConnectionWrapper.onUserMagnificationScaleChanged(userId, displayId, scale);
+ }
+ }
+
+ /**
* Returns the screen-relative X coordinate of the center of the magnified bounds.
*
* @param displayId The logical display id
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index e85eee81..e3262cf 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -22,7 +22,6 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.RouteInfo.RTN_THROW;
import static android.net.RouteInfo.RTN_UNREACHABLE;
import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
@@ -280,15 +279,22 @@
private static final int VPN_DEFAULT_SCORE = 101;
/**
- * The reset session timer for data stall. If a session has not successfully revalidated after
- * the delay, the session will be torn down and restarted in an attempt to recover. Delay
+ * The recovery timer for data stall. If a session has not successfully revalidated after
+ * the delay, the session will perform MOBIKE or be restarted in an attempt to recover. Delay
* counter is reset on successful validation only.
*
+ * <p>The first {@code MOBIKE_RECOVERY_ATTEMPT} timers are used for performing MOBIKE.
+ * System will perform session reset for the remaining timers.
* <p>If retries have exceeded the length of this array, the last entry in the array will be
* used as a repeating interval.
*/
- private static final long[] DATA_STALL_RESET_DELAYS_SEC = {30L, 60L, 120L, 240L, 480L, 960L};
-
+ // TODO: use ms instead to speed up the test.
+ private static final long[] DATA_STALL_RECOVERY_DELAYS_SEC =
+ {1L, 5L, 30L, 60L, 120L, 240L, 480L, 960L};
+ /**
+ * Maximum attempts to perform MOBIKE when the network is bad.
+ */
+ private static final int MAX_MOBIKE_RECOVERY_ATTEMPT = 2;
/**
* The initial token value of IKE session.
*/
@@ -380,6 +386,7 @@
private final INetworkManagementService mNms;
private final INetd mNetd;
@VisibleForTesting
+ @GuardedBy("this")
protected VpnConfig mConfig;
private final NetworkProvider mNetworkProvider;
@VisibleForTesting
@@ -392,7 +399,6 @@
private final UserManager mUserManager;
private final VpnProfileStore mVpnProfileStore;
- protected boolean mDataStallSuspected = false;
@VisibleForTesting
VpnProfileStore getVpnProfileStore() {
@@ -685,14 +691,14 @@
}
/**
- * Get the length of time to wait before resetting the ike session when a data stall is
- * suspected.
+ * Get the length of time to wait before perform data stall recovery when the validation
+ * result is bad.
*/
- public long getDataStallResetSessionSeconds(int count) {
- if (count >= DATA_STALL_RESET_DELAYS_SEC.length) {
- return DATA_STALL_RESET_DELAYS_SEC[DATA_STALL_RESET_DELAYS_SEC.length - 1];
+ public long getValidationFailRecoverySeconds(int count) {
+ if (count >= DATA_STALL_RECOVERY_DELAYS_SEC.length) {
+ return DATA_STALL_RECOVERY_DELAYS_SEC[DATA_STALL_RECOVERY_DELAYS_SEC.length - 1];
} else {
- return DATA_STALL_RESET_DELAYS_SEC[count];
+ return DATA_STALL_RECOVERY_DELAYS_SEC[count];
}
}
@@ -1598,6 +1604,8 @@
return network;
}
+ // TODO : this is not synchronized(this) but reads from mConfig, which is dangerous
+ // This file makes an effort to avoid partly initializing mConfig, but this is still not great
private LinkProperties makeLinkProperties() {
// The design of disabling IPv6 is only enabled for IKEv2 VPN because it needs additional
// logic to handle IPv6 only VPN, and the IPv6 only VPN may be restarted when its MTU
@@ -1679,6 +1687,7 @@
* registering a new NetworkAgent. This is not always possible if the new VPN configuration
* has certain changes, in which case this method would just return {@code false}.
*/
+ // TODO : this method is not synchronized(this) but reads from mConfig
private boolean updateLinkPropertiesInPlaceIfPossible(NetworkAgent agent, VpnConfig oldConfig) {
// NetworkAgentConfig cannot be updated without registering a new NetworkAgent.
// Strictly speaking, bypassability is affected by lockdown and therefore it's possible
@@ -2269,7 +2278,12 @@
*/
public synchronized VpnConfig getVpnConfig() {
enforceControlPermission();
- return mConfig;
+ // Constructor of VpnConfig cannot take a null parameter. Return null directly if mConfig is
+ // null
+ if (mConfig == null) return null;
+ // mConfig is guarded by "this" and can be modified by another thread as soon as
+ // this method returns, so this method must return a copy.
+ return new VpnConfig(mConfig);
}
@Deprecated
@@ -2315,6 +2329,7 @@
}
};
+ @GuardedBy("this")
private void cleanupVpnStateLocked() {
mStatusIntent = null;
resetNetworkCapabilities();
@@ -2837,9 +2852,7 @@
}
final boolean isLegacyVpn = mVpnRunner instanceof LegacyVpnRunner;
-
mVpnRunner.exit();
- mVpnRunner = null;
// LegacyVpn uses daemons that must be shut down before new ones are brought up.
// The same limitation does not apply to Platform VPNs.
@@ -3044,7 +3057,6 @@
@Nullable private IkeSessionWrapper mSession;
@Nullable private IkeSessionConnectionInfo mIkeConnectionInfo;
- @Nullable private VpnConnectivityDiagnosticsCallback mDiagnosticsCallback;
// mMobikeEnabled can only be updated after IKE AUTH is finished.
private boolean mMobikeEnabled = false;
@@ -3055,7 +3067,7 @@
* <p>This variable controls the retry delay, and is reset when the VPN pass network
* validation.
*/
- private int mDataStallRetryCount = 0;
+ private int mValidationFailRetryCount = 0;
/**
* The number of attempts since the last successful connection.
@@ -3084,6 +3096,7 @@
}
};
+ // GuardedBy("Vpn.this") (annotation can't be applied to constructor)
IkeV2VpnRunner(
@NonNull Ikev2VpnProfile profile, @NonNull ScheduledThreadPoolExecutor executor) {
super(TAG);
@@ -3136,15 +3149,6 @@
mConnectivityManager.registerSystemDefaultNetworkCallback(mNetworkCallback,
new Handler(mLooper));
}
-
- // DiagnosticsCallback may return more than one alive VPNs, but VPN will filter based on
- // Network object.
- final NetworkRequest diagRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_VPN)
- .removeCapability(NET_CAPABILITY_NOT_VPN).build();
- mDiagnosticsCallback = new VpnConnectivityDiagnosticsCallback();
- mConnectivityDiagnosticsManager.registerConnectivityDiagnosticsCallback(
- diagRequest, mExecutor, mDiagnosticsCallback);
}
private boolean isActiveNetwork(@Nullable Network network) {
@@ -3710,11 +3714,14 @@
}
public void updateVpnTransportInfoAndNetCap(int keepaliveDelaySec) {
- final VpnTransportInfo info = new VpnTransportInfo(
- getActiveVpnType(),
- mConfig.session,
- mConfig.allowBypass && !mLockdown,
- areLongLivedTcpConnectionsExpensive(keepaliveDelaySec));
+ final VpnTransportInfo info;
+ synchronized (Vpn.this) {
+ info = new VpnTransportInfo(
+ getActiveVpnType(),
+ mConfig.session,
+ mConfig.allowBypass && !mLockdown,
+ areLongLivedTcpConnectionsExpensive(keepaliveDelaySec));
+ }
final boolean ncUpdateRequired = !info.equals(mNetworkCapabilities.getTransportInfo());
if (ncUpdateRequired) {
mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
@@ -3875,39 +3882,12 @@
}
}
- class VpnConnectivityDiagnosticsCallback
- extends ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback {
- // The callback runs in the executor thread.
- @Override
- public void onDataStallSuspected(
- ConnectivityDiagnosticsManager.DataStallReport report) {
- synchronized (Vpn.this) {
- // Ignore stale runner.
- if (mVpnRunner != Vpn.IkeV2VpnRunner.this) return;
-
- // Handle the report only for current VPN network. If data stall is already
- // reported, ignoring the other reports. It means that the stall is not
- // recovered by MOBIKE and should be on the way to reset the ike session.
- if (mNetworkAgent != null
- && mNetworkAgent.getNetwork().equals(report.getNetwork())
- && !mDataStallSuspected) {
- Log.d(TAG, "Data stall suspected");
-
- // Trigger MOBIKE.
- maybeMigrateIkeSessionAndUpdateVpnTransportInfo(mActiveNetwork);
- mDataStallSuspected = true;
- }
- }
- }
- }
-
public void onValidationStatus(int status) {
mEventChanges.log("[Validation] validation status " + status);
if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
// No data stall now. Reset it.
mExecutor.execute(() -> {
- mDataStallSuspected = false;
- mDataStallRetryCount = 0;
+ mValidationFailRetryCount = 0;
if (mScheduledHandleDataStallFuture != null) {
Log.d(TAG, "Recovered from stall. Cancel pending reset action.");
mScheduledHandleDataStallFuture.cancel(false /* mayInterruptIfRunning */);
@@ -3918,8 +3898,21 @@
// Skip other invalid status if the scheduled recovery exists.
if (mScheduledHandleDataStallFuture != null) return;
+ if (mValidationFailRetryCount < MAX_MOBIKE_RECOVERY_ATTEMPT) {
+ Log.d(TAG, "Validation failed");
+
+ // Trigger MOBIKE to recover first.
+ mExecutor.schedule(() -> {
+ maybeMigrateIkeSessionAndUpdateVpnTransportInfo(mActiveNetwork);
+ }, mDeps.getValidationFailRecoverySeconds(mValidationFailRetryCount++),
+ TimeUnit.SECONDS);
+ return;
+ }
+
+ // Data stall is not recovered by MOBIKE. Try to reset session to recover it.
mScheduledHandleDataStallFuture = mExecutor.schedule(() -> {
- if (mDataStallSuspected) {
+ // Only perform the recovery when the network is still bad.
+ if (mValidationFailRetryCount > 0) {
Log.d(TAG, "Reset session to recover stalled network");
// This will reset old state if it exists.
startIkeSession(mActiveNetwork);
@@ -3928,7 +3921,9 @@
// Reset mScheduledHandleDataStallFuture since it's already run on executor
// thread.
mScheduledHandleDataStallFuture = null;
- }, mDeps.getDataStallResetSessionSeconds(mDataStallRetryCount++), TimeUnit.SECONDS);
+ // TODO: compute the delay based on the last recovery timestamp
+ }, mDeps.getValidationFailRecoverySeconds(mValidationFailRetryCount++),
+ TimeUnit.SECONDS);
}
}
@@ -4220,7 +4215,7 @@
* consistency of the Ikev2VpnRunner fields.
*/
private void disconnectVpnRunner() {
- mEventChanges.log("[VPNRunner] Disconnect runner, underlying network" + mActiveNetwork);
+ mEventChanges.log("[VPNRunner] Disconnect runner, underlying net " + mActiveNetwork);
mActiveNetwork = null;
mUnderlyingNetworkCapabilities = null;
mUnderlyingLinkProperties = null;
@@ -4231,8 +4226,6 @@
mCarrierConfigManager.unregisterCarrierConfigChangeListener(
mCarrierConfigChangeListener);
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
- mConnectivityDiagnosticsManager.unregisterConnectivityDiagnosticsCallback(
- mDiagnosticsCallback);
clearVpnNetworkPreference(mSessionKey);
mExecutor.shutdown();
@@ -4293,6 +4286,7 @@
}
};
+ // GuardedBy("Vpn.this") (annotation can't be applied to constructor)
LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd, VpnProfile profile) {
super(TAG);
if (racoon == null && mtpd == null) {
@@ -4500,46 +4494,46 @@
}
// Set the interface and the addresses in the config.
- mConfig.interfaze = parameters[0].trim();
-
- mConfig.addLegacyAddresses(parameters[1]);
- // Set the routes if they are not set in the config.
- if (mConfig.routes == null || mConfig.routes.isEmpty()) {
- mConfig.addLegacyRoutes(parameters[2]);
- }
-
- // Set the DNS servers if they are not set in the config.
- if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) {
- String dnsServers = parameters[3].trim();
- if (!dnsServers.isEmpty()) {
- mConfig.dnsServers = Arrays.asList(dnsServers.split(" "));
- }
- }
-
- // Set the search domains if they are not set in the config.
- if (mConfig.searchDomains == null || mConfig.searchDomains.size() == 0) {
- String searchDomains = parameters[4].trim();
- if (!searchDomains.isEmpty()) {
- mConfig.searchDomains = Arrays.asList(searchDomains.split(" "));
- }
- }
-
- // Add a throw route for the VPN server endpoint, if one was specified.
- if (endpointAddress instanceof Inet4Address) {
- mConfig.routes.add(new RouteInfo(
- new IpPrefix(endpointAddress, 32), null /*gateway*/,
- null /*iface*/, RTN_THROW));
- } else if (endpointAddress instanceof Inet6Address) {
- mConfig.routes.add(new RouteInfo(
- new IpPrefix(endpointAddress, 128), null /*gateway*/,
- null /*iface*/, RTN_THROW));
- } else {
- Log.e(TAG, "Unknown IP address family for VPN endpoint: "
- + endpointAddress);
- }
-
- // Here is the last step and it must be done synchronously.
synchronized (Vpn.this) {
+ mConfig.interfaze = parameters[0].trim();
+
+ mConfig.addLegacyAddresses(parameters[1]);
+ // Set the routes if they are not set in the config.
+ if (mConfig.routes == null || mConfig.routes.isEmpty()) {
+ mConfig.addLegacyRoutes(parameters[2]);
+ }
+
+ // Set the DNS servers if they are not set in the config.
+ if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) {
+ String dnsServers = parameters[3].trim();
+ if (!dnsServers.isEmpty()) {
+ mConfig.dnsServers = Arrays.asList(dnsServers.split(" "));
+ }
+ }
+
+ // Set the search domains if they are not set in the config.
+ if (mConfig.searchDomains == null || mConfig.searchDomains.size() == 0) {
+ String searchDomains = parameters[4].trim();
+ if (!searchDomains.isEmpty()) {
+ mConfig.searchDomains = Arrays.asList(searchDomains.split(" "));
+ }
+ }
+
+ // Add a throw route for the VPN server endpoint, if one was specified.
+ if (endpointAddress instanceof Inet4Address) {
+ mConfig.routes.add(new RouteInfo(
+ new IpPrefix(endpointAddress, 32), null /*gateway*/,
+ null /*iface*/, RTN_THROW));
+ } else if (endpointAddress instanceof Inet6Address) {
+ mConfig.routes.add(new RouteInfo(
+ new IpPrefix(endpointAddress, 128), null /*gateway*/,
+ null /*iface*/, RTN_THROW));
+ } else {
+ Log.e(TAG, "Unknown IP address family for VPN endpoint: "
+ + endpointAddress);
+ }
+
+ // Here is the last step and it must be done synchronously.
// Set the start time
mConfig.startTime = SystemClock.elapsedRealtime();
@@ -4773,25 +4767,26 @@
try {
// Build basic config
- mConfig = new VpnConfig();
+ final VpnConfig config = new VpnConfig();
if (VpnConfig.LEGACY_VPN.equals(packageName)) {
- mConfig.legacy = true;
- mConfig.session = profile.name;
- mConfig.user = profile.key;
+ config.legacy = true;
+ config.session = profile.name;
+ config.user = profile.key;
// TODO: Add support for configuring meteredness via Settings. Until then, use a
// safe default.
- mConfig.isMetered = true;
+ config.isMetered = true;
} else {
- mConfig.user = packageName;
- mConfig.isMetered = profile.isMetered;
+ config.user = packageName;
+ config.isMetered = profile.isMetered;
}
- mConfig.startTime = SystemClock.elapsedRealtime();
- mConfig.proxyInfo = profile.proxy;
- mConfig.requiresInternetValidation = profile.requiresInternetValidation;
- mConfig.excludeLocalRoutes = profile.excludeLocalRoutes;
- mConfig.allowBypass = profile.isBypassable;
- mConfig.disallowedApplications = getAppExclusionList(mPackage);
+ config.startTime = SystemClock.elapsedRealtime();
+ config.proxyInfo = profile.proxy;
+ config.requiresInternetValidation = profile.requiresInternetValidation;
+ config.excludeLocalRoutes = profile.excludeLocalRoutes;
+ config.allowBypass = profile.isBypassable;
+ config.disallowedApplications = getAppExclusionList(mPackage);
+ mConfig = config;
switch (profile.type) {
case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS:
@@ -4805,6 +4800,7 @@
mVpnRunner.start();
break;
default:
+ mConfig = null;
updateState(DetailedState.FAILED, "Invalid platform VPN type");
Log.d(TAG, "Unknown VPN profile type: " + profile.type);
break;
@@ -5216,7 +5212,7 @@
pw.println("MOBIKE " + (runner.mMobikeEnabled ? "enabled" : "disabled"));
pw.println("Profile: " + runner.mProfile);
pw.println("Token: " + runner.mCurrentToken);
- if (mDataStallSuspected) pw.println("Data stall suspected");
+ pw.println("Validation failed retry count:" + runner.mValidationFailRetryCount);
if (runner.mScheduledHandleDataStallFuture != null) {
pw.println("Reset session scheduled");
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 6a177e0..3a8f9d5 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -2800,6 +2800,11 @@
void notifyConfigurationChanged();
/**
+ * This callback is invoked when the pointer location changes.
+ */
+ void notifyPointerLocationChanged(boolean pointerLocationEnabled);
+
+ /**
* This callback is invoked when the camera lens cover switch changes state.
* @param whenNanos the time when the change occurred
* @param lensCovered true is the lens is covered
@@ -3381,6 +3386,10 @@
}
}
+ void updatePointerLocationEnabled(boolean enabled) {
+ mWindowManagerCallbacks.notifyPointerLocationChanged(enabled);
+ }
+
void updateFocusEventDebugViewEnabled(boolean enabled) {
FocusEventDebugView view;
synchronized (mFocusEventDebugViewLock) {
diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java
index 42591f4..a608b4f 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -67,6 +67,8 @@
(reason) -> updateTouchpadRightClickZoneEnabled()),
Map.entry(Settings.System.getUriFor(Settings.System.SHOW_TOUCHES),
(reason) -> updateShowTouches()),
+ Map.entry(Settings.System.getUriFor(Settings.System.POINTER_LOCATION),
+ (reason) -> updatePointerLocation()),
Map.entry(
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON),
(reason) -> updateAccessibilityLargePointer()),
@@ -149,6 +151,11 @@
mNative.setShowTouches(getBoolean(Settings.System.SHOW_TOUCHES, false));
}
+ private void updatePointerLocation() {
+ mService.updatePointerLocationEnabled(
+ getBoolean(Settings.System.POINTER_LOCATION, false));
+ }
+
private void updateShowKeyPresses() {
mService.updateFocusEventDebugViewEnabled(
getBoolean(Settings.System.SHOW_KEY_PRESSES, false));
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
index 6a0550b..aa99dab 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
@@ -291,6 +291,10 @@
reset(false /* reinitializing */);
}
+ void setInkWindowInitializer(Runnable inkWindowInitializer) {
+ mInkWindowInitRunnable = inkWindowInitializer;
+ }
+
private void reset(boolean reinitializing) {
if (mHandwritingEventReceiver != null) {
mHandwritingEventReceiver.dispose();
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 1ab83f7..02ee96a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2472,6 +2472,9 @@
curInputMethodInfo != null && curInputMethodInfo.suppressesSpellChecker();
final SparseArray<IAccessibilityInputMethodSession> accessibilityInputMethodSessions =
createAccessibilityInputMethodSessions(mCurClient.mAccessibilitySessions);
+ if (mBindingController.supportsStylusHandwriting() && hasSupportedStylusLocked()) {
+ mHwController.setInkWindowInitializer(new InkWindowInitializer());
+ }
return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
session.mSession, accessibilityInputMethodSessions,
(session.mChannel != null ? session.mChannel.dup() : null),
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 68f49fd..e0e6410 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -9508,14 +9508,19 @@
* Determine whether the userId applies to the notification in question, either because
* they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
*/
- private static boolean notificationMatchesUserId(NotificationRecord r, int userId) {
- return
+ private static boolean notificationMatchesUserId(NotificationRecord r, int userId,
+ boolean isAutogroupSummary) {
+ if (isAutogroupSummary) {
+ return r.getUserId() == userId;
+ } else {
+ return
// looking for USER_ALL notifications? match everything
- userId == UserHandle.USER_ALL
- // a notification sent to USER_ALL matches any query
- || r.getUserId() == UserHandle.USER_ALL
- // an exact user match
- || r.getUserId() == userId;
+ userId == UserHandle.USER_ALL
+ // a notification sent to USER_ALL matches any query
+ || r.getUserId() == UserHandle.USER_ALL
+ // an exact user match
+ || r.getUserId() == userId;
+ }
}
/**
@@ -9524,7 +9529,7 @@
* because it matches one of the users profiles.
*/
private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
- return notificationMatchesUserId(r, userId)
+ return notificationMatchesUserId(r, userId, false)
|| mUserProfiles.isCurrentProfile(r.getUserId());
}
@@ -9593,7 +9598,7 @@
if (!notificationMatchesCurrentProfiles(r, userId)) {
continue;
}
- } else if (!notificationMatchesUserId(r, userId)) {
+ } else if (!notificationMatchesUserId(r, userId, false)) {
continue;
}
// Don't remove notifications to all, if there's no package name specified
@@ -9831,7 +9836,7 @@
final int len = list.size();
for (int i = 0; i < len; i++) {
NotificationRecord r = list.get(i);
- if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
+ if (notificationMatchesUserId(r, userId, false) && r.getGroupKey().equals(groupKey)
&& r.getSbn().getPackageName().equals(pkg)) {
records.add(r);
}
@@ -9873,8 +9878,8 @@
final int len = list.size();
for (int i = 0; i < len; i++) {
NotificationRecord r = list.get(i);
- if (notificationMatchesUserId(r, userId) && r.getSbn().getId() == id &&
- TextUtils.equals(r.getSbn().getTag(), tag)
+ if (notificationMatchesUserId(r, userId, (r.getFlags() & GroupHelper.BASE_FLAGS) != 0)
+ && r.getSbn().getId() == id && TextUtils.equals(r.getSbn().getTag(), tag)
&& r.getSbn().getPackageName().equals(pkg)) {
return r;
}
@@ -9888,8 +9893,8 @@
final int len = list.size();
for (int i = 0; i < len; i++) {
NotificationRecord r = list.get(i);
- if (notificationMatchesUserId(r, userId) && r.getSbn().getId() == id &&
- TextUtils.equals(r.getSbn().getTag(), tag)
+ if (notificationMatchesUserId(r, userId, false) && r.getSbn().getId() == id
+ && TextUtils.equals(r.getSbn().getTag(), tag)
&& r.getSbn().getPackageName().equals(pkg)) {
matching.add(r);
}
diff --git a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
index 9c3b38a..b999bbb3 100644
--- a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
+++ b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
@@ -314,7 +314,9 @@
if (eventTime < mLastDownTime + mActiveRule.getVeryLongPressTimeoutMs()) {
mHandler.removeMessages(MSG_KEY_VERY_LONG_PRESS);
} else {
- mHandledByLongPress = mActiveRule.supportVeryLongPress();
+ // If long press or very long press (~3.5s) had been handled, we should skip the
+ // short press behavior.
+ mHandledByLongPress |= mActiveRule.supportVeryLongPress();
}
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 143563a..ee7dc50 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1993,7 +1993,7 @@
WallpaperData data = null;
synchronized (mLock) {
if (mIsLockscreenLiveWallpaperEnabled) {
- clearWallpaperLocked(callingPackage, false, which, userId, null);
+ clearWallpaperLocked(callingPackage, false, which, userId);
} else {
clearWallpaperLocked(false, which, userId, null);
}
@@ -2014,7 +2014,7 @@
}
private void clearWallpaperLocked(String callingPackage, boolean defaultFailed,
- int which, int userId, IRemoteCallback reply) {
+ int which, int userId) {
// Might need to bring it in the first time to establish our rewrite
if (!mWallpaperMap.contains(userId)) {
@@ -2068,15 +2068,9 @@
withCleanCallingIdentity(() -> clearWallpaperComponentLocked(wallpaper));
}
+ // TODO(b/266818039) remove this version of the method
private void clearWallpaperLocked(boolean defaultFailed, int which, int userId,
IRemoteCallback reply) {
-
- if (mIsLockscreenLiveWallpaperEnabled) {
- String callingPackage = mPackageManagerInternal.getNameForUid(getCallingUid());
- clearWallpaperLocked(callingPackage, defaultFailed, which, userId, reply);
- return;
- }
-
if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to clear");
}
@@ -3246,21 +3240,15 @@
boolean setWallpaperComponent(ComponentName name, String callingPackage,
@SetWallpaperFlags int which, int userId) {
if (mIsLockscreenLiveWallpaperEnabled) {
- return setWallpaperComponentInternal(name, callingPackage, which, userId, null);
+ return setWallpaperComponentInternal(name, callingPackage, which, userId);
} else {
setWallpaperComponentInternalLegacy(name, callingPackage, which, userId);
return true;
}
}
- private boolean setWallpaperComponent(ComponentName name, @SetWallpaperFlags int which,
- int userId) {
- String callingPackage = mPackageManagerInternal.getNameForUid(getCallingUid());
- return setWallpaperComponentInternal(name, callingPackage, which, userId, null);
- }
-
private boolean setWallpaperComponentInternal(ComponentName name, String callingPackage,
- @SetWallpaperFlags int which, int userIdIn, IRemoteCallback reply) {
+ @SetWallpaperFlags int which, int userIdIn) {
if (DEBUG) {
Slog.v(TAG, "Setting new live wallpaper: which=" + which + ", component: " + name);
}
@@ -3309,7 +3297,6 @@
Slog.d(TAG, "publish system wallpaper changed!");
}
liveSync.complete();
- if (reply != null) reply.sendResult(null);
}
};
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 98c15dd2..2717a6a 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1284,6 +1284,12 @@
return ANIMATION_STYLEABLE;
}
+ // TODO (b/277891341): Remove this and related usages. This has been replaced by
+ // InsetsSource#FLAG_FORCE_CONSUMING.
+ public boolean areSystemBarsForcedConsumedLw() {
+ return false;
+ }
+
/**
* Computes the frames of display (its logical size, rotation and cutout should already be set)
* used to layout window. This method only changes the given display frames, insets state and
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 0a47fe0..20595ea 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -128,6 +128,21 @@
}
}
+ /** Notifies that the pointer location configuration has changed. */
+ @Override
+ public void notifyPointerLocationChanged(boolean pointerLocationEnabled) {
+ if (mService.mPointerLocationEnabled == pointerLocationEnabled) {
+ return;
+ }
+
+ synchronized (mService.mGlobalLock) {
+ mService.mPointerLocationEnabled = pointerLocationEnabled;
+ mService.mRoot.forAllDisplayPolicies(
+ p -> p.setPointerLocationEnabled(mService.mPointerLocationEnabled)
+ );
+ }
+ }
+
/** Notifies that the lid switch changed state. */
@Override
public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 4620266..835c92d 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -21,12 +21,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.view.InsetsController.ANIMATION_TYPE_HIDE;
-import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
-import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
-import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
import static android.view.InsetsSource.ID_IME;
-import static android.view.SyncRtSurfaceTransactionApplier.applyParams;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
@@ -39,16 +34,13 @@
import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.res.Resources;
+import android.os.Handler;
+import android.os.IBinder;
import android.util.SparseArray;
-import android.view.InsetsAnimationControlCallbacks;
-import android.view.InsetsAnimationControlImpl;
-import android.view.InsetsAnimationControlRunner;
import android.view.InsetsController;
import android.view.InsetsFrameProvider;
import android.view.InsetsSource;
-import android.view.InsetsSourceControl;
import android.view.InsetsState;
-import android.view.InternalInsetsAnimationController;
import android.view.SurfaceControl;
import android.view.SyncRtSurfaceTransactionApplier;
import android.view.WindowInsets;
@@ -56,15 +48,15 @@
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimation;
import android.view.WindowInsetsAnimation.Bounds;
-import android.view.WindowInsetsAnimationControlListener;
import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.DisplayThread;
import com.android.server.statusbar.StatusBarManagerInternal;
import java.io.PrintWriter;
+import java.util.List;
/**
* Policy that implements who gets control over the windows generating insets.
@@ -79,48 +71,19 @@
private final DisplayContent mDisplayContent;
private final DisplayPolicy mPolicy;
- /** For resetting visibilities of insets sources. */
- private final InsetsControlTarget mDummyControlTarget = new InsetsControlTarget() {
+ /** Used to show system bars transiently. This won't affect the layout. */
+ private final InsetsControlTarget mTransientControlTarget;
- @Override
- public void notifyInsetsControlChanged() {
- boolean hasLeash = false;
- final InsetsSourceControl[] controls =
- mStateController.getControlsForDispatch(this);
- if (controls == null) {
- return;
- }
- for (InsetsSourceControl control : controls) {
- if (isTransient(control.getType())) {
- // The visibilities of transient bars will be handled with animations.
- continue;
- }
- final SurfaceControl leash = control.getLeash();
- if (leash != null) {
- hasLeash = true;
-
- // We use alpha to control the visibility here which aligns the logic at
- // SurfaceAnimator.createAnimationLeash
- final boolean visible =
- (control.getType() & WindowInsets.Type.defaultVisible()) != 0;
- mDisplayContent.getPendingTransaction().setAlpha(leash, visible ? 1f : 0f);
- }
- }
- if (hasLeash) {
- mDisplayContent.scheduleAnimation();
- }
- }
- };
+ /** Used to show system bars permanently. This will affect the layout. */
+ private final InsetsControlTarget mPermanentControlTarget;
private WindowState mFocusedWin;
private final BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);
private final BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR);
private @InsetsType int mShowingTransientTypes;
private @InsetsType int mForcedShowingTypes;
- private boolean mAnimatingShown;
private final boolean mHideNavBarForKeyboard;
- private final float[] mTmpFloat9 = new float[9];
InsetsPolicy(InsetsStateController stateController, DisplayContent displayContent) {
mStateController = stateController;
@@ -128,6 +91,10 @@
mPolicy = displayContent.getDisplayPolicy();
final Resources r = mPolicy.getContext().getResources();
mHideNavBarForKeyboard = r.getBoolean(R.bool.config_hideNavBarForKeyboard);
+ mTransientControlTarget = new ControlTarget(
+ stateController, displayContent.mWmService.mH, "TransientControlTarget");
+ mPermanentControlTarget = new ControlTarget(
+ stateController, displayContent.mWmService.mH, "PermanentControlTarget");
}
/** Updates the target which can control system bars. */
@@ -144,13 +111,13 @@
final WindowState topApp = mPolicy.getTopFullscreenOpaqueWindow();
mStateController.onBarControlTargetChanged(
statusControlTarget,
- statusControlTarget == mDummyControlTarget
+ statusControlTarget == mTransientControlTarget
? getStatusControlTarget(focusedWin, true /* fake */)
: statusControlTarget == notificationShade
? getStatusControlTarget(topApp, true /* fake */)
: null,
navControlTarget,
- navControlTarget == mDummyControlTarget
+ navControlTarget == mTransientControlTarget
? getNavControlTarget(focusedWin, true /* fake */)
: navControlTarget == notificationShade
? getNavControlTarget(topApp, true /* fake */)
@@ -200,19 +167,19 @@
mFocusedWin,
(showingTransientTypes & (Type.statusBars() | Type.navigationBars())) != 0,
isGestureOnSystemBar);
-
- // The leashes can be created while updating bar control target. The surface transaction
- // of the new leashes might not be applied yet. The callback posted here ensures we can
- // get the valid leashes because the surface transaction will be applied in the next
- // animation frame which will be triggered if a new leash is created.
- mDisplayContent.mWmService.mAnimator.getChoreographer().postFrameCallback(time -> {
- synchronized (mDisplayContent.mWmService.mGlobalLock) {
- startAnimation(true /* show */, null /* callback */);
- }
- });
}
}
+ @VisibleForTesting
+ InsetsControlTarget getTransientControlTarget() {
+ return mTransientControlTarget;
+ }
+
+ @VisibleForTesting
+ InsetsControlTarget getPermanentControlTarget() {
+ return mPermanentControlTarget;
+ }
+
void hideTransient() {
if (mShowingTransientTypes == 0) {
return;
@@ -223,23 +190,8 @@
/* areVisible= */ false,
/* wereRevealedFromSwipeOnSystemBar= */ false);
- startAnimation(false /* show */, () -> {
- synchronized (mDisplayContent.mWmService.mGlobalLock) {
- final SparseArray<InsetsSourceProvider> providers =
- mStateController.getSourceProviders();
- for (int i = providers.size() - 1; i >= 0; i--) {
- final InsetsSourceProvider provider = providers.valueAt(i);
- if (!isTransient(provider.getSource().getType())) {
- continue;
- }
- // We are about to clear mShowingTransientTypes, we don't want the transient bar
- // can cause insets on the client. Restore the client visibility.
- provider.setClientVisible(false);
- }
- mShowingTransientTypes = 0;
- updateBarControlTarget(mFocusedWin);
- }
- });
+ mShowingTransientTypes = 0;
+ updateBarControlTarget(mFocusedWin);
}
boolean isTransient(@InsetsType int type) {
@@ -502,7 +454,7 @@
private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin,
boolean fake) {
if (!fake && isTransient(Type.statusBars())) {
- return mDummyControlTarget;
+ return mTransientControlTarget;
}
final WindowState notificationShade = mPolicy.getNotificationShade();
if (focusedWin == notificationShade) {
@@ -519,13 +471,13 @@
if (areTypesForciblyShowing(Type.statusBars())) {
// Status bar is forcibly shown. We don't want the client to control the status bar, and
// we will dispatch the real visibility of status bar to the client.
- return null;
+ return mPermanentControlTarget;
}
if (forceShowsStatusBarTransiently() && !fake) {
// Status bar is forcibly shown transiently, and its new visibility won't be
// dispatched to the client so that we can keep the layout stable. We will dispatch the
// fake control to the client, so that it can re-show the bar during this scenario.
- return mDummyControlTarget;
+ return mTransientControlTarget;
}
if (!canBeTopFullscreenOpaqueWindow(focusedWin)
&& mPolicy.topAppHidesSystemBar(Type.statusBars())
@@ -556,7 +508,7 @@
return null;
}
if (!fake && isTransient(Type.navigationBars())) {
- return mDummyControlTarget;
+ return mTransientControlTarget;
}
if (focusedWin == mPolicy.getNotificationShade()) {
// Notification shade has control anyways, no reason to force anything.
@@ -579,13 +531,13 @@
if (areTypesForciblyShowing(Type.navigationBars())) {
// Navigation bar is forcibly shown. We don't want the client to control the navigation
// bar, and we will dispatch the real visibility of navigation bar to the client.
- return null;
+ return mPermanentControlTarget;
}
if (forceShowsNavigationBarTransiently() && !fake) {
// Navigation bar is forcibly shown transiently, and its new visibility won't be
// dispatched to the client so that we can keep the layout stable. We will dispatch the
// fake control to the client, so that it can re-show the bar during this scenario.
- return mDummyControlTarget;
+ return mTransientControlTarget;
}
final WindowState notificationShade = mPolicy.getNotificationShade();
if (!canBeTopFullscreenOpaqueWindow(focusedWin)
@@ -662,34 +614,6 @@
&& (win.mAttrs.privateFlags & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
}
- @VisibleForTesting
- void startAnimation(boolean show, Runnable callback) {
- @InsetsType int typesReady = 0;
- final SparseArray<InsetsSourceControl> controlsReady = new SparseArray<>();
- final InsetsSourceControl[] controls =
- mStateController.getControlsForDispatch(mDummyControlTarget);
- if (controls == null) {
- if (callback != null) {
- DisplayThread.getHandler().post(callback);
- }
- return;
- }
- for (InsetsSourceControl control : controls) {
- if (isTransient(control.getType()) && control.getLeash() != null) {
- typesReady |= control.getType();
- controlsReady.put(control.getId(), new InsetsSourceControl(control));
- }
- }
- controlAnimationUnchecked(typesReady, controlsReady, show, callback);
- }
-
- private void controlAnimationUnchecked(int typesReady,
- SparseArray<InsetsSourceControl> controls, boolean show, Runnable callback) {
- InsetsPolicyAnimationControlListener listener =
- new InsetsPolicyAnimationControlListener(show, callback, typesReady);
- listener.mControlCallbacks.controlAnimationUnchecked(typesReady, controls, show);
- }
-
private void dispatchTransientSystemBarsVisibilityChanged(
@Nullable WindowState focusedWindow,
boolean areVisible,
@@ -760,105 +684,138 @@
}
}
- private class InsetsPolicyAnimationControlListener extends
- InsetsController.InternalAnimationControlListener {
- Runnable mFinishCallback;
- InsetsPolicyAnimationControlCallbacks mControlCallbacks;
+ private static class ControlTarget implements InsetsControlTarget {
- InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback, int types) {
- super(show, false /* hasCallbacks */, types, BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE,
- false /* disable */, 0 /* floatingImeBottomInsets */,
- null /* loggingListener */, null /* jankContext */);
- mFinishCallback = finishCallback;
- mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this);
+ private final InsetsState mState = new InsetsState();
+ private final InsetsController mInsetsController;
+ private final InsetsStateController mStateController;
+ private final String mName;
+
+ ControlTarget(InsetsStateController stateController, Handler handler, String name) {
+ mStateController = stateController;
+ mInsetsController = new InsetsController(new Host(handler, name));
+ mName = name;
}
@Override
- protected void onAnimationFinish() {
- super.onAnimationFinish();
- if (mFinishCallback != null) {
- DisplayThread.getHandler().post(mFinishCallback);
- }
+ public void notifyInsetsControlChanged() {
+ mState.set(mStateController.getRawInsetsState(), true /* copySources */);
+ mInsetsController.onStateChanged(mState);
+ mInsetsController.onControlsChanged(mStateController.getControlsForDispatch(this));
}
- private class InsetsPolicyAnimationControlCallbacks implements
- InsetsAnimationControlCallbacks {
- private InsetsAnimationControlImpl mAnimationControl = null;
- private InsetsPolicyAnimationControlListener mListener;
+ @Override
+ public String toString() {
+ return mName;
+ }
+ }
- InsetsPolicyAnimationControlCallbacks(InsetsPolicyAnimationControlListener listener) {
- mListener = listener;
+ private static class Host implements InsetsController.Host {
+
+ private final float[] mTmpFloat9 = new float[9];
+ private final Handler mHandler;
+ private final String mName;
+
+ Host(Handler handler, String name) {
+ mHandler = handler;
+ mName = name;
+ }
+
+ @Override
+ public Handler getHandler() {
+ return mHandler;
+ }
+
+ @Override
+ public void notifyInsetsChanged() { }
+
+ @Override
+ public void dispatchWindowInsetsAnimationPrepare(
+ @NonNull WindowInsetsAnimation animation) { }
+
+ @Override
+ public Bounds dispatchWindowInsetsAnimationStart(
+ @NonNull WindowInsetsAnimation animation,
+ @NonNull Bounds bounds) {
+ return bounds;
+ }
+
+ @Override
+ public WindowInsets dispatchWindowInsetsAnimationProgress(
+ @NonNull WindowInsets insets,
+ @NonNull List<WindowInsetsAnimation> runningAnimations) {
+ return insets;
+ }
+
+ @Override
+ public void dispatchWindowInsetsAnimationEnd(
+ @NonNull WindowInsetsAnimation animation) { }
+
+ @Override
+ public void applySurfaceParams(SyncRtSurfaceTransactionApplier.SurfaceParams... p) {
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ for (int i = p.length - 1; i >= 0; i--) {
+ SyncRtSurfaceTransactionApplier.applyParams(t, p[i], mTmpFloat9);
}
+ t.apply();
+ t.close();
+ }
- private void controlAnimationUnchecked(int typesReady,
- SparseArray<InsetsSourceControl> controls, boolean show) {
- if (typesReady == 0) {
- // nothing to animate.
- return;
- }
- mAnimatingShown = show;
+ @Override
+ public void updateRequestedVisibleTypes(int types) { }
- final InsetsState state = mFocusedWin.getInsetsState();
+ @Override
+ public boolean hasAnimationCallbacks() {
+ return false;
+ }
- // We are about to playing the default animation. Passing a null frame indicates
- // the controlled types should be animated regardless of the frame.
- mAnimationControl = new InsetsAnimationControlImpl(controls,
- null /* frame */, state, mListener, typesReady, this,
- mListener.getDurationMs(), getInsetsInterpolator(),
- show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE, show
- ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
- : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
- null /* translator */, null /* statsToken */);
- SurfaceAnimationThread.getHandler().post(
- () -> mListener.onReady(mAnimationControl, typesReady));
- }
+ @Override
+ public void setSystemBarsAppearance(int appearance, int mask) { }
- /** Called on SurfaceAnimationThread without global WM lock held. */
- @Override
- public void scheduleApplyChangeInsets(InsetsAnimationControlRunner runner) {
- if (mAnimationControl.applyChangeInsets(null /* outState */)) {
- mAnimationControl.finish(mAnimatingShown);
- }
- }
+ @Override
+ public int getSystemBarsAppearance() {
+ return 0;
+ }
- @Override
- public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) {
- // Nothing's needed here. Finish steps is handled in the listener
- // onAnimationFinished callback.
- }
+ @Override
+ public void setSystemBarsBehavior(int behavior) { }
- /** Called on SurfaceAnimationThread without global WM lock held. */
- @Override
- public void applySurfaceParams(
- final SyncRtSurfaceTransactionApplier.SurfaceParams... params) {
- SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- for (int i = params.length - 1; i >= 0; i--) {
- SyncRtSurfaceTransactionApplier.SurfaceParams surfaceParams = params[i];
- applyParams(t, surfaceParams, mTmpFloat9);
- }
- t.apply();
- t.close();
- }
+ @Override
+ public int getSystemBarsBehavior() {
+ return BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
+ }
- // Since we don't push applySurfaceParams to a Handler-queue we don't need
- // to push release in this case.
- @Override
- public void releaseSurfaceControlFromRt(SurfaceControl sc) {
- sc.release();
- }
+ @Override
+ public void releaseSurfaceControlFromRt(SurfaceControl surfaceControl) {
+ surfaceControl.release();
+ }
- @Override
- public <T extends InsetsAnimationControlRunner & InternalInsetsAnimationController>
- void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types,
- WindowInsetsAnimation animation,
- Bounds bounds) {
- }
+ @Override
+ public void addOnPreDrawRunnable(Runnable r) { }
- @Override
- public void reportPerceptible(int types, boolean perceptible) {
- // No-op for now - only client windows report perceptibility for now, with policy
- // controllers assumed to always be perceptible.
- }
+ @Override
+ public void postInsetsAnimationCallback(Runnable r) { }
+
+ @Override
+ public InputMethodManager getInputMethodManager() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getRootViewTitle() {
+ return mName;
+ }
+
+ @Override
+ public int dipToPx(int dips) {
+ return 0;
+ }
+
+ @Nullable
+ @Override
+ public IBinder getWindowToken() {
+ return null;
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 68a6384..0e19671 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -763,8 +763,6 @@
Settings.Secure.getUriFor(Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS);
private final Uri mPolicyControlUri =
Settings.Global.getUriFor(Settings.Global.POLICY_CONTROL);
- private final Uri mPointerLocationUri =
- Settings.System.getUriFor(Settings.System.POINTER_LOCATION);
private final Uri mForceDesktopModeOnExternalDisplaysUri = Settings.Global.getUriFor(
Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS);
private final Uri mFreeformWindowUri = Settings.Global.getUriFor(
@@ -792,7 +790,6 @@
resolver.registerContentObserver(mImmersiveModeConfirmationsUri, false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(mPolicyControlUri, false, this, UserHandle.USER_ALL);
- resolver.registerContentObserver(mPointerLocationUri, false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(mForceDesktopModeOnExternalDisplaysUri, false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(mFreeformWindowUri, false, this, UserHandle.USER_ALL);
@@ -816,11 +813,6 @@
return;
}
- if (mPointerLocationUri.equals(uri)) {
- updatePointerLocation();
- return;
- }
-
if (mForceDesktopModeOnExternalDisplaysUri.equals(uri)) {
updateForceDesktopModeOnExternalDisplays();
return;
@@ -869,7 +861,6 @@
void loadSettings() {
updateSystemUiSettings(false /* handleChange */);
- updatePointerLocation();
updateMaximumObscuringOpacityForTouch();
}
@@ -900,21 +891,6 @@
}
}
- void updatePointerLocation() {
- ContentResolver resolver = mContext.getContentResolver();
- final boolean enablePointerLocation = Settings.System.getIntForUser(resolver,
- Settings.System.POINTER_LOCATION, 0, UserHandle.USER_CURRENT) != 0;
-
- if (mPointerLocationEnabled == enablePointerLocation) {
- return;
- }
- mPointerLocationEnabled = enablePointerLocation;
- synchronized (mGlobalLock) {
- mRoot.forAllDisplayPolicies(
- p -> p.setPointerLocationEnabled(mPointerLocationEnabled));
- }
- }
-
void updateForceDesktopModeOnExternalDisplays() {
ContentResolver resolver = mContext.getContentResolver();
final boolean enableForceDesktopMode = Settings.Global.getInt(resolver,
@@ -1789,6 +1765,9 @@
winAnimator.mEnterAnimationPending = true;
winAnimator.mEnteringAnimation = true;
+ if (displayPolicy.areSystemBarsForcedConsumedLw()) {
+ res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS;
+ }
if (displayContent.isInTouchMode()) {
res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
}
@@ -2491,6 +2470,9 @@
if (win.mActivityRecord != null) {
win.mActivityRecord.updateReportedVisibilityLocked();
}
+ if (displayPolicy.areSystemBarsForcedConsumedLw()) {
+ result |= WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS;
+ }
if (!win.isGoneForLayout()) {
win.mResizedWhileGone = false;
}
@@ -9064,7 +9046,7 @@
}
@Override
- public void getWindowInsets(int displayId, IBinder token, InsetsState outInsetsState) {
+ public boolean getWindowInsets(int displayId, IBinder token, InsetsState outInsetsState) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -9075,6 +9057,7 @@
}
final WindowToken winToken = dc.getWindowToken(token);
dc.getInsetsPolicy().getInsetsForWindowMetrics(winToken, outInsetsState);
+ return dc.getDisplayPolicy().areSystemBarsForcedConsumedLw();
}
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ef447020..0d4c2d6 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3732,6 +3732,8 @@
final boolean isDragResizeChanged = isDragResizeChanged();
final boolean forceRelayout = syncWithBuffers || isDragResizeChanged;
final DisplayContent displayContent = getDisplayContent();
+ final boolean alwaysConsumeSystemBars =
+ displayContent.getDisplayPolicy().areSystemBarsForcedConsumedLw();
final int displayId = displayContent.getDisplayId();
if (isDragResizeChanged) {
@@ -3743,7 +3745,7 @@
try {
mClient.resized(mClientWindowFrames, reportDraw, mLastReportedConfiguration,
- getCompatInsetsState(), forceRelayout, displayId,
+ getCompatInsetsState(), forceRelayout, alwaysConsumeSystemBars, displayId,
syncWithBuffers ? mSyncSeqId : -1, isDragResizing);
if (drawPending && prevRotation >= 0 && prevRotation != mLastReportedConfiguration
.getMergedConfiguration().windowConfiguration.getRotation()) {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index e75fc21..81dd961 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -666,6 +666,21 @@
assertEquals(config.getCenterX(), actualConfig.getCenterX(), 0);
assertEquals(config.getCenterY(), actualConfig.getCenterY(), 0);
assertEquals(config.getScale(), actualConfig.getScale(), 0);
+
+ verify(mWindowMagnificationManager).onUserMagnificationScaleChanged(
+ /* userId= */ anyInt(), eq(TEST_DISPLAY), eq(config.getScale()));
+ }
+
+ @Test
+ public void onSourceBoundChanged_windowEnabled_notifyMagnificationChanged()
+ throws RemoteException {
+ setMagnificationEnabled(MODE_WINDOW);
+ reset(mWindowMagnificationManager);
+
+ mMagnificationController.onSourceBoundsChanged(TEST_DISPLAY, TEST_RECT);
+
+ verify(mWindowMagnificationManager).onUserMagnificationScaleChanged(
+ /* userId= */ anyInt(), eq(TEST_DISPLAY), eq(DEFAULT_SCALE));
}
@Test
@@ -794,6 +809,7 @@
verify(mMagnificationController).onWindowMagnificationActivationState(
eq(TEST_DISPLAY), eq(true));
}
+
@Test
public void deactivateWindowMagnification_windowActivated_triggerCallbackAndLogUsage()
throws RemoteException {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java
index 2357e65..8608199 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java
@@ -122,6 +122,15 @@
}
@Test
+ public void onUserMagnificationScaleChanged() throws RemoteException {
+ final int testUserId = 1;
+ final float testScale = 3f;
+ mConnectionWrapper.onUserMagnificationScaleChanged(testUserId, TEST_DISPLAY, testScale);
+ verify(mConnection).onUserMagnificationScaleChanged(
+ eq(testUserId), eq(TEST_DISPLAY), eq(testScale));
+ }
+
+ @Test
public void setMirrorWindowCallback() throws RemoteException {
mConnectionWrapper.setConnectionCallback(mCallback);
verify(mConnection).setConnectionCallback(mCallback);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
index c98de7c..e8b337a 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
@@ -548,6 +548,18 @@
}
@Test
+ public void onUserMagnificationScaleChanged_hasConnection_invokeConnectionMethod()
+ throws RemoteException {
+ mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
+
+ final float testScale = 3f;
+ mWindowMagnificationManager.onUserMagnificationScaleChanged(
+ CURRENT_USER_ID, TEST_DISPLAY, testScale);
+ verify(mMockConnection.getConnection()).onUserMagnificationScaleChanged(
+ eq(CURRENT_USER_ID), eq(TEST_DISPLAY), eq(testScale));
+ }
+
+ @Test
public void pointersInWindow_magnifierEnabled_returnCorrectValue() throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3.0f, NaN, NaN);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index ba07439..e49b290 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -867,13 +867,18 @@
}
private NotificationRecord generateNotificationRecord(NotificationChannel channel, int userId) {
+ return generateNotificationRecord(channel, 1, userId);
+ }
+
+ private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
+ int userId) {
if (channel == null) {
channel = mTestNotificationChannel;
}
Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
.setContentTitle("foo")
.setSmallIcon(android.R.drawable.sym_def_app_icon);
- StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", mUid, 0,
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id, "tag", mUid, 0,
nb.build(), new UserHandle(userId), null, 0);
return new NotificationRecord(mContext, sbn, channel);
}
@@ -10734,6 +10739,51 @@
}
@Test
+ public void testUngroupingAutoSummary_differentUsers() throws Exception {
+ NotificationRecord nr0 =
+ generateNotificationRecord(mTestNotificationChannel, 0, USER_SYSTEM);
+ NotificationRecord nr1 =
+ generateNotificationRecord(mTestNotificationChannel, 1, USER_SYSTEM);
+
+ // add notifications + summary for USER_SYSTEM
+ mService.addNotification(nr0);
+ mService.addNotification(nr1);
+ mService.addNotification(mService.createAutoGroupSummary(nr1.getUserId(),
+ nr1.getSbn().getPackageName(), nr1.getKey(), GroupHelper.BASE_FLAGS));
+
+ // add notifications + summary for USER_ALL
+ NotificationRecord nr0_all =
+ generateNotificationRecord(mTestNotificationChannel, 2, UserHandle.USER_ALL);
+ NotificationRecord nr1_all =
+ generateNotificationRecord(mTestNotificationChannel, 3, UserHandle.USER_ALL);
+
+ mService.addNotification(nr0_all);
+ mService.addNotification(nr1_all);
+ mService.addNotification(mService.createAutoGroupSummary(nr0_all.getUserId(),
+ nr0_all.getSbn().getPackageName(), nr0_all.getKey(), GroupHelper.BASE_FLAGS));
+
+ // cancel both children for USER_ALL
+ mBinderService.cancelNotificationWithTag(PKG, PKG, nr0_all.getSbn().getTag(),
+ nr0_all.getSbn().getId(), UserHandle.USER_ALL);
+ mBinderService.cancelNotificationWithTag(PKG, PKG, nr1_all.getSbn().getTag(),
+ nr1_all.getSbn().getId(), UserHandle.USER_ALL);
+ waitForIdle();
+
+ // group helper would send 'remove summary' event
+ mService.clearAutogroupSummaryLocked(UserHandle.USER_ALL,
+ nr0_all.getSbn().getPackageName());
+ waitForIdle();
+
+ // make sure the right summary was removed
+ assertThat(mService.getNotificationCount(nr0_all.getSbn().getPackageName(),
+ UserHandle.USER_ALL, 0, null)).isEqualTo(0);
+
+ // the USER_SYSTEM notifications + summary were not removed
+ assertThat(mService.getNotificationCount(nr0.getSbn().getPackageName(),
+ USER_SYSTEM, 0, null)).isEqualTo(3);
+ }
+
+ @Test
public void testStrongAuthTracker_isInLockDownMode() {
mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
index 6a1674b..63b8e17 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
@@ -38,13 +38,16 @@
import android.os.Process;
import android.os.RemoteException;
+import androidx.test.filters.FlakyTest;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.internal.util.FakeLatencyTracker;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.Timeout;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor;
@@ -52,8 +55,12 @@
import org.mockito.MockitoAnnotations;
@RunWith(JUnit4.class)
+@FlakyTest(bugId = 275746222)
public class SoundTriggerMiddlewareLoggingLatencyTest {
+ @Rule
+ public Timeout mGlobalTimeout = Timeout.seconds(30);
+
private FakeLatencyTracker mLatencyTracker;
@Mock
private BatteryStatsInternal mBatteryStatsInternal;
diff --git a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
index 280afba..3bb86a7 100644
--- a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
@@ -316,4 +316,16 @@
pressKey(KEYCODE_POWER, 0 /* pressTime */);
assertTrue(mShortPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
}
+
+ // Verify short press should not be triggered if no very long press behavior defined but the
+ // press time exceeded the very long press timeout.
+ @Test
+ public void testTimeoutExceedVeryLongPress() throws InterruptedException {
+ mVeryLongPressOnPowerBehavior = false;
+
+ pressKey(KEYCODE_POWER, mVeryLongPressTime + 50);
+ assertTrue(mLongPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
+ assertEquals(mVeryLongPressed.getCount(), 1);
+ assertEquals(mShortPressed.getCount(), 1);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 2e055e8..3db53eb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -3354,7 +3354,8 @@
// to client if the app didn't request IME visible.
assertFalse(app2.mActivityRecord.mImeInsetsFrozenUntilStartInput);
verify(app2.mClient, atLeastOnce()).resized(any(), anyBoolean(), any(),
- insetsStateCaptor.capture(), anyBoolean(), anyInt(), anyInt(), anyBoolean());
+ insetsStateCaptor.capture(), anyBoolean(), anyBoolean(), anyInt(), anyInt(),
+ anyBoolean());
assertFalse(app2.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime()));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index 204cbf7..994dcf1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -31,17 +31,12 @@
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.verify;
import android.app.StatusBarManager;
@@ -268,8 +263,6 @@
navBar.setHasSurface(true);
navBarProvider.setServerVisible(true);
final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
- spyOn(policy);
- doNothing().when(policy).startAnimation(anyBoolean(), any());
// Make both system bars invisible.
mAppWindow.setRequestedVisibleTypes(
@@ -305,8 +298,6 @@
addNavigationBar().getControllableInsetProvider().setServerVisible(true);
final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
- spyOn(policy);
- doNothing().when(policy).startAnimation(anyBoolean(), any());
policy.updateBarControlTarget(mAppWindow);
policy.showTransient(navigationBars() | statusBars(),
true /* isGestureOnSystemBar */);
@@ -341,8 +332,6 @@
mAppWindow.mAboveInsetsState.addSource(navBarSource);
mAppWindow.mAboveInsetsState.addSource(statusBarSource);
final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
- spyOn(policy);
- doNothing().when(policy).startAnimation(anyBoolean(), any());
policy.updateBarControlTarget(mAppWindow);
policy.showTransient(navigationBars() | statusBars(),
true /* isGestureOnSystemBar */);
@@ -390,8 +379,6 @@
final WindowState app2 = addWindow(TYPE_APPLICATION, "app");
final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
- spyOn(policy);
- doNothing().when(policy).startAnimation(anyBoolean(), any());
policy.updateBarControlTarget(app);
policy.showTransient(navigationBars() | statusBars(),
true /* isGestureOnSystemBar */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index 4639ee0..45ecc3f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -77,6 +77,10 @@
spyOn(inputMonitor);
doNothing().when(inputMonitor).resumeDispatchingLw(any());
+ final InsetsPolicy insetsPolicy = getInsetsPolicy();
+ WindowTestsBase.suppressInsetsAnimation(insetsPolicy.getPermanentControlTarget());
+ WindowTestsBase.suppressInsetsAnimation(insetsPolicy.getTransientControlTarget());
+
// For devices that set the sysprop ro.bootanim.set_orientation_<display_id>
// See DisplayRotation#readDefaultDisplayRotation for context.
// Without that, meaning of height and width in context of the tests can be swapped if
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index 40f86dd..3f8acc6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -46,7 +46,8 @@
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfig, InsetsState insetsState, boolean forceLayout,
- int displayId, int seqId, boolean dragResizing) throws RemoteException {
+ boolean alwaysConsumeSystemBars, int displayId, int seqId, boolean dragResizing)
+ throws RemoteException {
}
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index c13c2c3..0ddd31355 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -778,8 +778,8 @@
doThrow(new RemoteException("test")).when(win.mClient).resized(any() /* frames */,
anyBoolean() /* reportDraw */, any() /* mergedConfig */,
any() /* insetsState */, anyBoolean() /* forceLayout */,
- anyInt() /* displayId */, anyInt() /* seqId */,
- anyBoolean() /* dragResizing */);
+ anyBoolean() /* alwaysConsumeSystemBars */, anyInt() /* displayId */,
+ anyInt() /* seqId */, anyBoolean() /* dragResizing */);
} catch (RemoteException ignored) {
}
win.reportResized();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index be8ee78..d5547ec 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -222,6 +222,10 @@
displayPolicy.finishWindowsDrawn();
displayPolicy.finishScreenTurningOn();
+ final InsetsPolicy insetsPolicy = mDefaultDisplay.getInsetsPolicy();
+ suppressInsetsAnimation(insetsPolicy.getTransientControlTarget());
+ suppressInsetsAnimation(insetsPolicy.getPermanentControlTarget());
+
mTransaction = mSystemServicesTestRule.mTransaction;
mMockSession = mock(Session.class);
@@ -278,6 +282,15 @@
checkDeviceSpecificOverridesNotApplied();
}
+ /**
+ * The test doesn't create real SurfaceControls, but mocked ones. This prevents the target from
+ * controlling them, or it will cause {@link NullPointerException}.
+ */
+ static void suppressInsetsAnimation(InsetsControlTarget target) {
+ spyOn(target);
+ Mockito.doNothing().when(target).notifyInsetsControlChanged();
+ }
+
@After
public void tearDown() throws Exception {
if (mUseFakeSettingsProvider) {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index dc5b75a..3e79193 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -50,7 +50,6 @@
import android.telephony.ims.RcsUceAdapter;
import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.feature.RcsFeature;
-import android.telephony.ims.stub.ImsRegistrationImplBase;
import com.android.internal.telephony.ICarrierConfigLoader;
import com.android.telephony.Rlog;
@@ -5813,6 +5812,21 @@
*/
public static final int NR_SA_DISABLE_POLICY_VOWIFI_REGISTERED = 3;
+ /**
+ * This specifies whether the carrier support the global number format or not.
+ * {@link SubscriptionManager#getPhoneNumber(int)},
+ * {@link SubscriptionManager#getPhoneNumber(int, int)} with
+ * {@link SubscriptionManager#PHONE_NUMBER_SOURCE_IMS}
+ * In order to provide the phone number to the APIs, the framework extracts the phone
+ * number from the message received from the carrier server. If the carrier does not use
+ * global number format, the framework could not provide phone number.
+ * <p>
+ * If not set or set to false value, the framework handle only global number format URI.
+ * @hide
+ */
+ public static final String KEY_ALLOW_NON_GLOBAL_PHONE_NUMBER_FORMAT_BOOL =
+ KEY_PREFIX + "allow_non_global_phone_number_format_bool";
+
private Ims() {}
private static PersistableBundle getDefaults() {
@@ -5925,6 +5939,8 @@
defaults.putString(KEY_IMS_USER_AGENT_STRING,
"#MANUFACTURER#_#MODEL#_Android#AV#_#BUILD#");
+ defaults.putBoolean(KEY_ALLOW_NON_GLOBAL_PHONE_NUMBER_FORMAT_BOOL, false);
+
return defaults;
}
}
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 8faedeb..37b529b 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -37,6 +37,7 @@
name: "FlickerTestsActivityEmbedding-src",
srcs: [
"src/**/activityembedding/*.kt",
+ "src/**/activityembedding/open/*.kt",
"src/**/activityembedding/close/*.kt",
"src/**/activityembedding/rotation/*.kt",
],
@@ -108,6 +109,7 @@
":FlickerTestsAppLaunch-src",
":FlickerTestsQuickswitch-src",
":FlickerTestsRotation-src",
+ ":FlickerTestsNotification-src",
],
}
@@ -148,6 +150,9 @@
":FlickerTestsBase-src",
":FlickerTestsAppLaunch-src",
],
+ exclude_srcs: [
+ ":FlickerTestsActivityEmbedding-src",
+ ],
}
android_test {
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/AndroidTestTemplate.xml
index 1ede943..ed63ec0 100644
--- a/tests/FlickerTests/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/AndroidTestTemplate.xml
@@ -85,6 +85,8 @@
value="/data/user/0/com.android.server.wm.flicker.quickswitch/files"/>
<option name="directory-keys"
value="/data/user/0/com.android.server.wm.flicker.rotation/files"/>
+ <option name="directory-keys"
+ value="/data/user/0/com.android.server.wm.flicker.notification/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
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 1fdbe7f..b18a1a8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -255,20 +255,18 @@
invoke("snapshotStartingWindowLayerCoversExactlyOnApp") {
val snapshotLayers =
it.subjects.filter { subject ->
- subject.name.contains(ComponentNameMatcher.SNAPSHOT.toLayerName()) &&
+ ComponentNameMatcher.SNAPSHOT.layerMatchesAnyOf(subject.layer) &&
subject.isVisible
}
+ val visibleAreas =
+ snapshotLayers
+ .mapNotNull { snapshotLayer -> snapshotLayer.layer.visibleRegion }
+ .toTypedArray()
+ val snapshotRegion = RegionSubject(visibleAreas, timestamp)
// Verify the size of snapshotRegion covers appVisibleRegion exactly in animation.
- if (snapshotLayers.isNotEmpty()) {
- val visibleAreas =
- snapshotLayers
- .mapNotNull { snapshotLayer -> snapshotLayer.layer.visibleRegion }
- .toTypedArray()
- val snapshotRegion = RegionSubject(visibleAreas, timestamp)
+ if (snapshotRegion.region.isNotEmpty) {
val appVisibleRegion = it.visibleRegion(component)
- if (snapshotRegion.region.isNotEmpty) {
- snapshotRegion.coversExactly(appVisibleRegion.region)
- }
+ snapshotRegion.coversExactly(appVisibleRegion.region)
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
index 7a582f7..4530ef3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.flicker.activityembedding
+package com.android.server.wm.flicker.activityembedding.close
import android.platform.test.annotations.Presubmit
import android.tools.common.datatypes.Rect
@@ -24,6 +24,7 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import org.junit.FixMethodOrder
import org.junit.Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
index 48aaebd..0f406fd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.flicker.activityembedding
+package com.android.server.wm.flicker.activityembedding.open
import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
@@ -24,8 +24,10 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import org.junit.FixMethodOrder
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -54,7 +56,7 @@
testApp.launchViaIntent(wmHelper)
testApp.launchSecondaryActivity(wmHelper)
startDisplayBounds =
- wmHelper.currentState.layerState.physicalDisplayBounds ?: error("Display not found")
+ wmHelper.currentState.layerState.physicalDisplayBounds ?: error("Display not found")
}
transitions {
// Launch C with alwaysExpand
@@ -66,23 +68,14 @@
}
}
- @FlakyTest(bugId = 286952194)
- @Presubmit
- @Test
- override fun navBarWindowIsVisibleAtStartAndEnd() {}
+ @Ignore("Not applicable to this CUJ.") override fun navBarWindowIsVisibleAtStartAndEnd() {}
- @FlakyTest(bugId = 286952194)
- @Presubmit
- @Test
- override fun statusBarWindowIsAlwaysVisible() {}
+ @Ignore("Not applicable to this CUJ.") override fun statusBarWindowIsAlwaysVisible() {}
- @FlakyTest(bugId = 286952194)
- @Presubmit
- @Test
- override fun statusBarLayerPositionAtStartAndEnd() {}
+ @Ignore("Not applicable to this CUJ.") override fun statusBarLayerPositionAtStartAndEnd() {}
/** Transition begins with a split. */
- @Presubmit
+ @FlakyTest(bugId = 286952194)
@Test
fun startsWithSplit() {
flicker.assertWmStart {
@@ -94,7 +87,7 @@
}
/** Main activity should become invisible after being covered by always expand activity. */
- @Presubmit
+ @FlakyTest(bugId = 286952194)
@Test
fun mainActivityLayerBecomesInvisible() {
flicker.assertLayers {
@@ -105,7 +98,7 @@
}
/** Secondary activity should become invisible after being covered by always expand activity. */
- @Presubmit
+ @FlakyTest(bugId = 286952194)
@Test
fun secondaryActivityLayerBecomesInvisible() {
flicker.assertLayers {
@@ -116,7 +109,7 @@
}
/** At the end of transition always expand activity is in fullscreen. */
- @Presubmit
+ @FlakyTest(bugId = 286952194)
@Test
fun endsWithAlwaysExpandActivityCoveringFullScreen() {
flicker.assertWmEnd {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
index 27a5bd0..8a997dd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.flicker.activityembedding
+package com.android.server.wm.flicker.activityembedding.open
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
@@ -22,6 +22,7 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import org.junit.FixMethodOrder
import org.junit.Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
index 16dbfce..49aa84b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.flicker.activityembedding
+package com.android.server.wm.flicker.activityembedding.open
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
@@ -23,6 +23,7 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import org.junit.FixMethodOrder
import org.junit.Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
index 43f4ce9..27de12e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.flicker.activityembedding
+package com.android.server.wm.flicker.activityembedding.open
import android.platform.test.annotations.Presubmit
import android.tools.common.datatypes.Rect
@@ -24,6 +24,7 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -32,8 +33,8 @@
import org.junit.runners.Parameterized
/**
- * Test launching a secondary activity over an existing split. By default the new secondary
- * activity will stack over the previous secondary activity.
+ * Test launching a secondary activity over an existing split. By default the new secondary activity
+ * will stack over the previous secondary activity.
*
* Setup: From Activity A launch a split A|B.
*
@@ -45,8 +46,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenThirdActivityOverSplitTest (flicker: LegacyFlickerTest) :
- ActivityEmbeddingTestBase(flicker) {
+class OpenThirdActivityOverSplitTest(flicker: LegacyFlickerTest) :
+ ActivityEmbeddingTestBase(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit = {
setup {
@@ -56,12 +57,10 @@
testApp.launchSecondaryActivity(wmHelper)
startDisplayBounds =
- wmHelper.currentState.layerState.physicalDisplayBounds
- ?: error("Can't get display bounds")
+ wmHelper.currentState.layerState.physicalDisplayBounds
+ ?: error("Can't get display bounds")
}
- transitions {
- testApp.launchThirdActivity(wmHelper)
- }
+ transitions { testApp.launchThirdActivity(wmHelper) }
teardown {
tapl.goHome()
testApp.exit(wmHelper)
@@ -79,36 +78,33 @@
@Presubmit
@Test
fun mainActivityLayersAlwaysVisible() {
- flicker.assertLayers {
- isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
- }
+ flicker.assertLayers { isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) }
flicker.assertLayersStart {
- val display = this.entry.displays.firstOrNull { it.isOn && !it.isVirtual }
+ val display =
+ this.entry.displays.firstOrNull { it.isOn && !it.isVirtual }
?: error("No non-virtual and on display found")
val mainActivityRegion =
- this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
val secondaryActivityRegion =
- this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
- .region
- mainActivityRegion
- .plus(secondaryActivityRegion)
- .coversExactly(display.layerStackSpace)
+ this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT).region
+ mainActivityRegion.plus(secondaryActivityRegion).coversExactly(display.layerStackSpace)
}
flicker.assertLayersEnd {
- val display = this.entry.displays.firstOrNull { it.isOn && !it.isVirtual }
+ val display =
+ this.entry.displays.firstOrNull { it.isOn && !it.isVirtual }
?: error("No non-virtual and on display found")
val mainActivityRegion =
- this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
val secondaryActivityRegion =
- this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
secondaryActivityRegion.isEmpty()
val thirdActivityRegion =
- this.visibleRegion(ActivityEmbeddingAppHelper.THIRD_ACTIVITY_COMPONENT)
+ this.visibleRegion(ActivityEmbeddingAppHelper.THIRD_ACTIVITY_COMPONENT)
mainActivityRegion
- .plus(thirdActivityRegion.region)
- .coversExactly(display.layerStackSpace)
+ .plus(thirdActivityRegion.region)
+ .coversExactly(display.layerStackSpace)
}
}
@@ -118,13 +114,15 @@
fun thirdActivityWindowLaunchesIntoSplit() {
flicker.assertWm {
isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
- .isAppWindowInvisible(ActivityEmbeddingAppHelper.THIRD_ACTIVITY_COMPONENT)
- .then()
- .isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
- .isAppWindowVisible(ActivityEmbeddingAppHelper.THIRD_ACTIVITY_COMPONENT)
- .then()
- .isAppWindowVisible(ActivityEmbeddingAppHelper.THIRD_ACTIVITY_COMPONENT)
- .isAppWindowInvisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT) // expectation
+ .isAppWindowInvisible(ActivityEmbeddingAppHelper.THIRD_ACTIVITY_COMPONENT)
+ .then()
+ .isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ .isAppWindowVisible(ActivityEmbeddingAppHelper.THIRD_ACTIVITY_COMPONENT)
+ .then()
+ .isAppWindowVisible(ActivityEmbeddingAppHelper.THIRD_ACTIVITY_COMPONENT)
+ .isAppWindowInvisible(
+ ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT
+ ) // expectation
}
}
@@ -134,13 +132,13 @@
fun thirdActivityLayerLaunchesIntoSplit() {
flicker.assertLayers {
isVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
- .isInvisible(ActivityEmbeddingAppHelper.THIRD_ACTIVITY_COMPONENT)
- .then()
- .isVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
- .isVisible(ActivityEmbeddingAppHelper.THIRD_ACTIVITY_COMPONENT)
- .then()
- .isVisible(ActivityEmbeddingAppHelper.THIRD_ACTIVITY_COMPONENT)
- .isInvisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ .isInvisible(ActivityEmbeddingAppHelper.THIRD_ACTIVITY_COMPONENT)
+ .then()
+ .isVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ .isVisible(ActivityEmbeddingAppHelper.THIRD_ACTIVITY_COMPONENT)
+ .then()
+ .isVisible(ActivityEmbeddingAppHelper.THIRD_ACTIVITY_COMPONENT)
+ .isInvisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
}
}
@@ -149,9 +147,7 @@
@Test
fun backgroundLayerNeverVisible() {
val backgroundColorLayer = ComponentNameMatcher("", "Animation Background")
- flicker.assertLayers {
- isInvisible(backgroundColorLayer)
- }
+ flicker.assertLayers { isInvisible(backgroundColorLayer) }
}
companion object {
@@ -167,4 +163,4 @@
@JvmStatic
fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
index 856c9e2..da56500 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.flicker.activityembedding
+package com.android.server.wm.flicker.activityembedding.rotation
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
index 06beec1..ced7a1e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
@@ -62,18 +62,18 @@
/** Clicks the button to launch a third activity over a secondary activity. */
fun launchThirdActivity(wmHelper: WindowManagerStateHelper) {
val launchButton =
- uiDevice.wait(
- Until.findObject(By.res(getPackage(), "launch_third_activity_button")),
- FIND_TIMEOUT
- )
+ uiDevice.wait(
+ Until.findObject(By.res(getPackage(), "launch_third_activity_button")),
+ FIND_TIMEOUT
+ )
require(launchButton != null) { "Can't find launch third activity button on screen." }
launchButton.click()
wmHelper
- .StateSyncBuilder()
- .withActivityState(MAIN_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
- .withActivityState(SECONDARY_ACTIVITY_COMPONENT, PlatformConsts.STATE_STOPPED)
- .withActivityState(THIRD_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
- .waitForAndVerify()
+ .StateSyncBuilder()
+ .withActivityState(MAIN_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
+ .withActivityState(SECONDARY_ACTIVITY_COMPONENT, PlatformConsts.STATE_STOPPED)
+ .withActivityState(THIRD_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
+ .waitForAndVerify()
}
/**
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
index 24e231c..c975a50 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
@@ -250,10 +250,13 @@
waitConditions = arrayOf(ConditionsFactory.hasPipWindow())
)
+ val windowRegion = wmHelper.getWindowRegion(this)
+
wmHelper
.StateSyncBuilder()
.withWindowSurfaceAppeared(this)
.withPipShown()
+ .withSurfaceVisibleRegion(this, windowRegion)
.waitForAndVerify()
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
index 2a2a3db..7a16060 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
@@ -20,8 +20,8 @@
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.common.flicker.annotation.FlickerServiceCompatible
+import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
index 4a1bd7e..1bdb6e71 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
@@ -18,6 +18,8 @@
import android.os.SystemClock
import android.platform.test.annotations.Postsubmit
+import android.tools.common.flicker.subject.layers.LayersTraceSubject
+import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.apphelpers.CameraAppHelper
import android.tools.device.apphelpers.StandardAppHelper
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
@@ -137,8 +139,14 @@
@Postsubmit
@Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ flicker.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry(
+ LayersTraceSubject.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS +
+ listOf(CAMERA_BACKGROUND)
+ )
+ }
+ }
@Postsubmit
@Test
@@ -161,5 +169,12 @@
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
+
+ private val CAMERA_BACKGROUND =
+ ComponentNameMatcher(
+ "Background for SurfaceView" +
+ "[com.google.android.GoogleCamera/" +
+ "com.google.android.apps.camera.legacy.app.activity.main.CameraActivity]"
+ )
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
index c336399..4e8a697 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
@@ -28,6 +28,7 @@
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.ShowWhenLockedAppHelper
import org.junit.FixMethodOrder
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -106,9 +107,9 @@
super.visibleLayersShownMoreThanOneConsecutiveEntry()
/** {@inheritDoc} */
- @FlakyTest(bugId = 209599395)
@Test
- override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
+ @Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
+ override fun navBarLayerIsVisibleAtStartAndEnd() {}
/** {@inheritDoc} */
@Presubmit