diff options
294 files changed, 4514 insertions, 1895 deletions
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java index b732da29b754..19a47669b0dd 100644 --- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java +++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java @@ -24,11 +24,9 @@ import static org.junit.Assume.assumeTrue; import android.annotation.NonNull; import android.app.ActivityManager; -import android.app.ActivityTaskManager; import android.app.AppGlobals; import android.app.IActivityManager; import android.app.IStopUserCallback; -import android.app.WaitResult; import android.app.WallpaperManager; import android.content.BroadcastReceiver; import android.content.Context; @@ -69,6 +67,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; /** * Perf tests for user life cycle events. @@ -101,7 +100,6 @@ public class UserLifecycleTests { private static final long TIMEOUT_MAX_TEST_TIME_MS = 24 * 60_000; private static final int TIMEOUT_IN_SECOND = 30; - private static final int CHECK_USER_REMOVED_INTERVAL_MS = 200; /** Name of users/profiles in the test. Users with this name may be freely removed. */ private static final String TEST_USER_NAME = "UserLifecycleTests_test_user"; @@ -1261,15 +1259,13 @@ public class UserLifecycleTests { * <p> This should always be used for profiles since profiles cannot be started in foreground. */ private void startUserInBackgroundAndWaitForUnlock(int userId) { - final ProgressWaiter waiter = new ProgressWaiter(); - boolean success = false; try { - mIam.startUserInBackgroundWithListener(userId, waiter); - success = waiter.waitForFinish(TIMEOUT_IN_SECOND); - } catch (RemoteException e) { - Log.e(TAG, "startUserInBackgroundAndWaitForUnlock failed", e); + attestTrue("Failed to start user " + userId + " in background.", + ShellHelper.runShellCommandWithTimeout("am start-user -w " + userId, + TIMEOUT_IN_SECOND).startsWith("Success:")); + } catch (TimeoutException e) { + fail("Could not start user " + userId + " in " + TIMEOUT_IN_SECOND + " seconds"); } - attestTrue("Failed to start user " + userId + " in background.", success); } /** Starts the given user in the foreground. */ @@ -1389,14 +1385,20 @@ public class UserLifecycleTests { * Launches the given package in the given user. * Make sure the keyguard has been dismissed prior to calling. */ - private void startApp(int userId, String packageName) throws RemoteException { - final Context context = InstrumentationRegistry.getContext(); - final WaitResult result = ActivityTaskManager.getService().startActivityAndWait(null, - context.getPackageName(), context.getAttributionTag(), - context.getPackageManager().getLaunchIntentForPackage(packageName), null, null, - null, 0, 0, null, null, userId); - attestTrue("User " + userId + " failed to start " + packageName, - result.result == ActivityManager.START_SUCCESS); + private void startApp(int userId, String packageName) { + final String failMessage = "User " + userId + " failed to start " + packageName; + final String component = InstrumentationRegistry.getContext().getPackageManager() + .getLaunchIntentForPackage(packageName).getComponent().flattenToShortString(); + try { + final String result = ShellHelper.runShellCommandWithTimeout( + "am start -W -n " + component + " --user " + userId, TIMEOUT_IN_SECOND); + assertTrue(failMessage + ", component=" + component + ", result=" + result, + result.contains("Status: ok") + && !result.contains("Warning:") + && !result.contains("Error:")); + } catch (TimeoutException e) { + fail(failMessage + " in " + TIMEOUT_IN_SECOND + " seconds"); + } } private class ProgressWaiter extends IProgressListener.Stub { @@ -1471,17 +1473,11 @@ public class UserLifecycleTests { private void removeUser(int userId) throws RemoteException { stopUserAfterWaitingForBroadcastIdle(userId, true); try { - mUm.removeUser(userId); - final long startTime = System.currentTimeMillis(); - final long timeoutInMs = TIMEOUT_IN_SECOND * 1000; - while (mUm.getUserInfo(userId) != null && - System.currentTimeMillis() - startTime < timeoutInMs) { - TimeUnit.MILLISECONDS.sleep(CHECK_USER_REMOVED_INTERVAL_MS); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } catch (Exception e) { - // Ignore + ShellHelper.runShellCommandWithTimeout("pm remove-user -w " + userId, + TIMEOUT_IN_SECOND); + } catch (TimeoutException e) { + Log.e(TAG, String.format("Could not remove user %d in %d seconds", + userId, TIMEOUT_IN_SECOND), e); } if (mUm.getUserInfo(userId) != null) { mUsersToRemove.add(userId); @@ -1544,7 +1540,11 @@ public class UserLifecycleTests { } private void waitForBroadcastIdle() { - ShellHelper.runShellCommand("am wait-for-broadcast-idle"); + try { + ShellHelper.runShellCommandWithTimeout("am wait-for-broadcast-idle", TIMEOUT_IN_SECOND); + } catch (TimeoutException e) { + Log.e(TAG, "Ending waitForBroadcastIdle because it is taking too long", e); + } } private void sleep(long ms) { diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java b/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java index 7b52576c1abd..a35899ad541b 100644 --- a/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java +++ b/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java @@ -24,6 +24,10 @@ import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import java.io.FileInputStream; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicReference; /** * Provides Shell-based utilities such as running a command. @@ -31,6 +35,43 @@ import java.io.FileInputStream; public final class ShellHelper { /** + * Runs a Shell command with a timeout, returning a trimmed response. + */ + @NonNull + public static String runShellCommandWithTimeout(@NonNull String command, long timeoutInSecond) + throws TimeoutException { + AtomicReference<Exception> exception = new AtomicReference<>(null); + AtomicReference<String> result = new AtomicReference<>(null); + + CountDownLatch latch = new CountDownLatch(1); + + new Thread(() -> { + try { + result.set(runShellCommandRaw(command)); + } catch (Exception e) { + exception.set(e); + } finally { + latch.countDown(); + } + }).start(); + + try { + if (!latch.await(timeoutInSecond, TimeUnit.SECONDS)) { + throw new TimeoutException("Command: '" + command + "' could not run in " + + timeoutInSecond + " seconds"); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + if (exception.get() != null) { + throw new AndroidRuntimeException(exception.get()); + } + + return result.get(); + } + + /** * Runs a Shell command, returning a trimmed response. */ @NonNull diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java index 430a1e25e123..4d646de2e529 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java @@ -292,6 +292,10 @@ class Alarm { return "permission"; case EXACT_ALLOW_REASON_POLICY_PERMISSION: return "policy_permission"; + case EXACT_ALLOW_REASON_LISTENER: + return "listener"; + case EXACT_ALLOW_REASON_PRIORITIZED: + return "prioritized"; case EXACT_ALLOW_REASON_NOT_APPLICABLE: return "N/A"; default: diff --git a/core/api/test-current.txt b/core/api/test-current.txt index ae63816945e1..332c53cb224f 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -536,6 +536,12 @@ package android.app.admin { field @NonNull public static final android.app.admin.DeviceAdminAuthority DEVICE_ADMIN_AUTHORITY; } + public final class DevicePolicyIdentifiers { + field public static final String PERMITTED_INPUT_METHODS_POLICY = "permittedInputMethods"; + field public static final String PERSONAL_APPS_SUSPENDED_POLICY = "personalAppsSuspended"; + field public static final String SCREEN_CAPTURE_DISABLED_POLICY = "screenCaptureDisabled"; + } + public class DevicePolicyManager { method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void acknowledgeNewUserDisclaimer(); method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void calculateHasIncompatibleAccounts(); @@ -3783,6 +3789,7 @@ package android.view.inputmethod { method @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodListAsUser(int); method public boolean hasActiveInputConnection(@Nullable android.view.View); method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean hasPendingImeVisibilityRequests(); + method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isCurrentRootView(@NonNull android.view.View); method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isInputMethodPickerShown(); method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public void setStylusWindowIdleTimeoutForTest(long); field public static final long CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING = 214016041L; // 0xcc1a029L diff --git a/core/java/android/app/admin/DevicePolicyCache.java b/core/java/android/app/admin/DevicePolicyCache.java index b6e83c8bc8a1..29f657ec6ba7 100644 --- a/core/java/android/app/admin/DevicePolicyCache.java +++ b/core/java/android/app/admin/DevicePolicyCache.java @@ -19,8 +19,8 @@ import android.annotation.UserIdInt; import com.android.server.LocalServices; -import java.util.ArrayList; -import java.util.List; +import java.util.Collections; +import java.util.Map; /** * Stores a copy of the set of device policies maintained by {@link DevicePolicyManager} that @@ -64,10 +64,11 @@ public abstract class DevicePolicyCache { public abstract boolean canAdminGrantSensorsPermissions(); /** - * Returns a list of package names for which all launcher shortcuts should be modified to be - * launched in the managed profile and badged accordingly. + * Returns a map of package names to package names, for which all launcher shortcuts which + * match a key package name should be modified to launch the corresponding value package + * name in the managed profile. The overridden shortcut should be badged accordingly. */ - public abstract List<String> getLauncherShortcutOverrides(); + public abstract Map<String, String> getLauncherShortcutOverrides(); /** * Empty implementation. @@ -95,8 +96,8 @@ public abstract class DevicePolicyCache { return false; } @Override - public List<String> getLauncherShortcutOverrides() { - return new ArrayList<>(); + public Map<String, String> getLauncherShortcutOverrides() { + return Collections.EMPTY_MAP; } } } diff --git a/core/java/android/app/admin/DevicePolicyIdentifiers.java b/core/java/android/app/admin/DevicePolicyIdentifiers.java index 9b0a70d65d6f..aeac59b12a2e 100644 --- a/core/java/android/app/admin/DevicePolicyIdentifiers.java +++ b/core/java/android/app/admin/DevicePolicyIdentifiers.java @@ -17,6 +17,7 @@ package android.app.admin; import android.annotation.NonNull; +import android.annotation.TestApi; import android.os.UserManager; import java.util.Objects; @@ -118,6 +119,7 @@ public final class DevicePolicyIdentifiers { * * @hide */ + @TestApi public static final String PERMITTED_INPUT_METHODS_POLICY = "permittedInputMethods"; /** @@ -125,6 +127,7 @@ public final class DevicePolicyIdentifiers { * * @hide */ + @TestApi public static final String PERSONAL_APPS_SUSPENDED_POLICY = "personalAppsSuspended"; /** @@ -132,6 +135,7 @@ public final class DevicePolicyIdentifiers { * * @hide */ + @TestApi public static final String SCREEN_CAPTURE_DISABLED_POLICY = "screenCaptureDisabled"; /** diff --git a/core/java/android/view/IRemoteAnimationRunner.aidl b/core/java/android/view/IRemoteAnimationRunner.aidl index 1981c9d66c8b..1f64fb8ca2ec 100644 --- a/core/java/android/view/IRemoteAnimationRunner.aidl +++ b/core/java/android/view/IRemoteAnimationRunner.aidl @@ -46,5 +46,5 @@ oneway interface IRemoteAnimationRunner { * won't have any effect anymore. */ @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) - void onAnimationCancelled(boolean isKeyguardOccluded); + void onAnimationCancelled(); } diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java index 43828d58afc4..97148969e17f 100644 --- a/core/java/android/view/ImeFocusController.java +++ b/core/java/android/view/ImeFocusController.java @@ -86,9 +86,12 @@ public final class ImeFocusController { void onPreWindowFocus(boolean hasWindowFocus, WindowManager.LayoutParams windowAttribute) { mHasImeFocus = WindowManager.LayoutParams.mayUseInputMethod(windowAttribute.flags); if (!hasWindowFocus || !mHasImeFocus || isInLocalFocusMode(windowAttribute)) { - return; + if (!hasWindowFocus) { + getImmDelegate().onWindowLostFocus(mViewRootImpl); + } + } else { + getImmDelegate().onPreWindowGainedFocus(mViewRootImpl); } - getImmDelegate().onPreWindowGainedFocus(mViewRootImpl); } @UiThread @@ -163,6 +166,7 @@ public final class ImeFocusController { void onPreWindowGainedFocus(ViewRootImpl viewRootImpl); void onPostWindowGainedFocus(View viewForWindowFocus, @NonNull WindowManager.LayoutParams windowAttribute); + void onWindowLostFocus(@NonNull ViewRootImpl viewRootImpl); void onViewFocusChanged(@NonNull View view, boolean hasFocus); void onScheduledCheckFocus(@NonNull ViewRootImpl viewRootImpl); void onViewDetachedFromWindow(View view, ViewRootImpl viewRootImpl); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index c0ac04ccd4d8..8f20e2d044ac 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -961,12 +961,20 @@ public final class ViewRootImpl implements ViewParent, } sAnrReported = true; + // If we're making an in-process call to ActivityManagerService + // and the previous binder call on this thread was oneway, the + // calling PID will be 0. Clearing the calling identity fixes + // this and ensures ActivityManager gets the correct calling + // pid. + final long identityToken = Binder.clearCallingIdentity(); try { ActivityManager.getService().appNotResponding(reason); } catch (RemoteException e) { // We asked the system to crash us, but the system // already crashed. Unfortunately things may be // out of control. + } finally { + Binder.restoreCallingIdentity(identityToken); } } }; diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 82cf07355a56..41ef44e1ac1f 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -482,13 +482,21 @@ public final class InputMethodManager { private View mNextServedView; /** - * This is the root view of the overall window that currently has input - * method focus. + * The latest {@link ViewRootImpl} that has, or most recently had, input method focus. + * + * <p>This value will be cleared when it becomes inactive and no longer has window focus. */ + @Nullable @GuardedBy("mH") ViewRootImpl mCurRootView; /** + * Whether the {@link #mCurRootView} currently has window focus. + */ + @GuardedBy("mH") + boolean mCurRootViewWindowFocused; + + /** * This is set when we are in the process of connecting, to determine * when we have actually finished. */ @@ -745,6 +753,7 @@ public final class InputMethodManager { public void onPreWindowGainedFocus(ViewRootImpl viewRootImpl) { synchronized (mH) { setCurrentRootViewLocked(viewRootImpl); + mCurRootViewWindowFocused = true; } } @@ -822,6 +831,17 @@ public final class InputMethodManager { } @Override + public void onWindowLostFocus(@NonNull ViewRootImpl viewRootImpl) { + synchronized (mH) { + if (mCurRootView == viewRootImpl) { + mCurRootViewWindowFocused = false; + + clearCurRootViewIfNeeded(); + } + } + } + + @Override public void onViewFocusChanged(@Nullable View view, boolean hasFocus) { onViewFocusChangedInternal(view, hasFocus); } @@ -1114,6 +1134,10 @@ public final class InputMethodManager { // Note that finishComposingText() is allowed to run // even when we are not active. mFallbackInputConnection.finishComposingTextFromImm(); + + if (clearCurRootViewIfNeeded()) { + return; + } } // Check focus again in case that "onWindowFocus" is called before // handling this message. @@ -1756,8 +1780,7 @@ public final class InputMethodManager { } /** - * Return true if the given view is the currently active view for the - * input method. + * Return {@code true} if the given view is the currently active view for the input method. */ public boolean isActive(View view) { // Re-dispatch if there is a context mismatch. @@ -1773,7 +1796,7 @@ public final class InputMethodManager { } /** - * Return true if any view is currently active in the input method. + * Return {@code true} if any view is currently active for the input method. */ public boolean isActive() { checkFocus(); @@ -1783,6 +1806,20 @@ public final class InputMethodManager { } /** + * Returns {@code true} if the given view's {@link ViewRootImpl} is the currently active one + * for the {@code InputMethodManager}. + * + * @hide + */ + @TestApi + @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD) + public boolean isCurrentRootView(@NonNull View attachedView) { + synchronized (mH) { + return mCurRootView == attachedView.getViewRootImpl(); + } + } + + /** * Return {@code true} if the currently served view is accepting full text edits. * If {@code false}, it has no input connection, so it can only handle raw key events. */ @@ -1908,6 +1945,24 @@ public final class InputMethodManager { mImeDispatcher.clear(); } + /** + * Clears the {@link #mCurRootView} if it's no longer window focused and the connection is + * no longer active. + * + * @return {@code} true iff it was cleared. + */ + @GuardedBy("mH") + private boolean clearCurRootViewIfNeeded() { + if (!mActive && !mCurRootViewWindowFocused) { + finishInputLocked(); + mDelegate.setCurrentRootViewLocked(null); + + return true; + } + + return false; + } + public void displayCompletions(View view, CompletionInfo[] completions) { // Re-dispatch if there is a context mismatch. final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); diff --git a/core/java/android/view/inputmethod/TextBoundsInfo.java b/core/java/android/view/inputmethod/TextBoundsInfo.java index d42d94e91933..d9f59d634295 100644 --- a/core/java/android/view/inputmethod/TextBoundsInfo.java +++ b/core/java/android/view/inputmethod/TextBoundsInfo.java @@ -1025,6 +1025,7 @@ public final class TextBoundsInfo implements Parcelable { mEnd = -1; mCharacterBounds = null; mCharacterFlags = null; + mCharacterBidiLevels = null; mLineSegmentFinder = null; mWordSegmentFinder = null; mGraphemeSegmentFinder = null; diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 7931d1a06d39..2dbff581fe84 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -724,7 +724,10 @@ public class Editor { } getPositionListener().addSubscriber(mCursorAnchorInfoNotifier, true); - makeBlink(); + // Call resumeBlink here instead of makeBlink to ensure that if mBlink is not null the + // Blink object is uncancelled. This ensures when a view is removed and added back the + // cursor will resume blinking. + resumeBlink(); } void onDetachedFromWindow() { @@ -1094,8 +1097,10 @@ public class Editor { private void resumeBlink() { if (mBlink != null) { mBlink.uncancel(); - makeBlink(); } + // Moving makeBlink outside of the null check block ensures that mBlink object gets + // instantiated when the view is added to the window if mBlink is still null. + makeBlink(); } void adjustInputType(boolean password, boolean passwordInputType, @@ -2921,6 +2926,9 @@ public class Editor { if (shouldBlink()) { mShowCursor = SystemClock.uptimeMillis(); if (mBlink == null) mBlink = new Blink(); + // Call uncancel as mBlink could have previously been cancelled and cursor will not + // resume blinking unless uncancelled. + mBlink.uncancel(); mTextView.removeCallbacks(mBlink); mTextView.postDelayed(mBlink, BLINK); } else { diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java index 3a8f427d54bc..4f9fc39300ae 100644 --- a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java +++ b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java @@ -32,6 +32,9 @@ import android.content.pm.ResolveInfo; import android.os.Build; import android.os.UserHandle; import android.provider.Settings; +import android.telecom.TelecomManager; +import android.telephony.Annotation; +import android.telephony.TelephonyManager; import android.text.ParcelableSpan; import android.text.Spanned; import android.text.TextUtils; @@ -204,6 +207,32 @@ public final class AccessibilityUtils { } /** + * Intercepts the {@link AccessibilityService#GLOBAL_ACTION_KEYCODE_HEADSETHOOK} action + * by directly interacting with TelecomManager if a call is incoming or in progress. + * + * <p> + * Provided here in shared utils to be used by both the legacy and modern (SysUI) + * system action implementations. + * </p> + * + * @return True if the action was propagated to TelecomManager, otherwise false. + */ + public static boolean interceptHeadsetHookForActiveCall(Context context) { + final TelecomManager telecomManager = context.getSystemService(TelecomManager.class); + @Annotation.CallState final int callState = + telecomManager != null ? telecomManager.getCallState() + : TelephonyManager.CALL_STATE_IDLE; + if (callState == TelephonyManager.CALL_STATE_RINGING) { + telecomManager.acceptRingingCall(); + return true; + } else if (callState == TelephonyManager.CALL_STATE_OFFHOOK) { + telecomManager.endCall(); + return true; + } + return false; + } + + /** * Indicates whether the current user has completed setup via the setup wizard. * {@link android.provider.Settings.Secure#USER_SETUP_COMPLETE} * diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java index 302d2e797e74..a7a69c9e43fb 100644 --- a/core/java/com/android/internal/widget/NotificationActionListLayout.java +++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java @@ -50,6 +50,8 @@ public class NotificationActionListLayout extends LinearLayout { private boolean mEmphasizedMode; private int mDefaultPaddingBottom; private int mDefaultPaddingTop; + private int mEmphasizedPaddingTop; + private int mEmphasizedPaddingBottom; private int mEmphasizedHeight; private int mRegularHeight; @DimenRes private int mCollapsibleIndentDimen = R.dimen.notification_actions_padding_start; @@ -322,13 +324,16 @@ public class NotificationActionListLayout extends LinearLayout { } private void updateHeights() { - int paddingTop = getResources().getDimensionPixelSize( - com.android.internal.R.dimen.notification_content_margin); + int inset = getResources().getDimensionPixelSize( + com.android.internal.R.dimen.button_inset_vertical_material); + mEmphasizedPaddingTop = getResources().getDimensionPixelSize( + com.android.internal.R.dimen.notification_content_margin) - inset; // same padding on bottom and at end - int paddingBottom = getResources().getDimensionPixelSize( - com.android.internal.R.dimen.notification_content_margin_end); - mEmphasizedHeight = paddingBottom + paddingTop + getResources().getDimensionPixelSize( - com.android.internal.R.dimen.notification_action_emphasized_height); + mEmphasizedPaddingBottom = getResources().getDimensionPixelSize( + com.android.internal.R.dimen.notification_content_margin_end) - inset; + mEmphasizedHeight = mEmphasizedPaddingTop + mEmphasizedPaddingBottom + + getResources().getDimensionPixelSize( + com.android.internal.R.dimen.notification_action_emphasized_height); mRegularHeight = getResources().getDimensionPixelSize( com.android.internal.R.dimen.notification_action_list_height); } @@ -356,18 +361,10 @@ public class NotificationActionListLayout extends LinearLayout { mEmphasizedMode = emphasizedMode; int height; if (emphasizedMode) { - int paddingTop = getResources().getDimensionPixelSize( - com.android.internal.R.dimen.notification_content_margin); - // same padding on bottom and at end - int paddingBottom = getResources().getDimensionPixelSize( - com.android.internal.R.dimen.notification_content_margin_end); - int buttonPaddingInternal = getResources().getDimensionPixelSize( - com.android.internal.R.dimen.button_inset_vertical_material); setPaddingRelative(getPaddingStart(), - paddingTop - buttonPaddingInternal, + mEmphasizedPaddingTop, getPaddingEnd(), - paddingBottom - buttonPaddingInternal); - + mEmphasizedPaddingBottom); setMinimumHeight(mEmphasizedHeight); height = ViewGroup.LayoutParams.WRAP_CONTENT; } else { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 31220b438ac4..fefa79f65201 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -8067,16 +8067,6 @@ </intent-filter> </receiver> - <!-- Broadcast Receiver listen to sufficient verifier requests from Package Manager - when install new SDK, to verifier SDK code during installation time - and terminate install if SDK not compatible with privacy sandbox restrictions. --> - <receiver android:name="com.android.server.sdksandbox.SdkSandboxVerifierReceiver" - android:exported="false"> - <intent-filter> - <action android:name="android.intent.action.PACKAGE_NEEDS_VERIFICATION"/> - </intent-filter> - </receiver> - <service android:name="android.hardware.location.GeofenceHardwareService" android:permission="android.permission.LOCATION_HARDWARE" android:exported="false" /> @@ -8204,6 +8194,10 @@ android:permission="android.permission.BIND_JOB_SERVICE"> </service> + <service android:name="com.android.server.healthconnect.backuprestore.BackupRestore$BackupRestoreJobService" + android:permission="android.permission.BIND_JOB_SERVICE"> + </service> + <service android:name="com.android.server.pm.PackageManagerShellCommandDataLoader" android:exported="false"> <intent-filter> @@ -8228,6 +8222,8 @@ <service android:name="com.android.server.companion.datatransfer.contextsync.CallMetadataSyncInCallService" android:permission="android.permission.BIND_INCALL_SERVICE" android:exported="true"> + <meta-data android:name="android.telecom.INCLUDE_SELF_MANAGED_CALLS" + android:value="true" /> <intent-filter> <action android:name="android.telecom.InCallService"/> </intent-filter> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index c5f7ea6501ff..12dad7eb1faa 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -558,6 +558,9 @@ docked if the dock is configured to enable the accelerometer. --> <bool name="config_supportAutoRotation">true</bool> + <!-- If true, allows rotation resolver service to help resolve screen rotation. --> + <bool name="config_allowRotationResolver">true</bool> + <!-- If true, the screen can be rotated via the accelerometer in all 4 rotations as the default behavior. --> <bool name="config_allowAllRotations">false</bool> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index b1b1edf85a09..bc0af12e9569 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -257,8 +257,8 @@ <!-- The margin of the notification action list at the top --> <dimen name="notification_action_list_margin_top">0dp</dimen> - <!-- The visual height of the emphasized notification action --> - <dimen name="notification_action_emphasized_height">36dp</dimen> + <!-- The overall height of the emphasized notification action --> + <dimen name="notification_action_emphasized_height">48dp</dimen> <!-- The padding of the actions in non-conversation layout. For conversations, the analogous value is calculated in ConversationLayout#updateActionListPadding() --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index ae107fd648d3..bb10f7ae7c93 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1715,6 +1715,7 @@ <java-symbol type="integer" name="config_motionPredictionOffsetNanos" /> <java-symbol type="bool" name="config_showNavigationBar" /> <java-symbol type="bool" name="config_supportAutoRotation" /> + <java-symbol type="bool" name="config_allowRotationResolver" /> <java-symbol type="bool" name="config_dockedStackDividerFreeSnapMode" /> <java-symbol type="dimen" name="docked_stack_divider_thickness" /> <java-symbol type="dimen" name="docked_stack_divider_insets" /> diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/RadioServiceUserControllerTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/RadioServiceUserControllerTest.java index 3e9e9922431b..516253b0ebff 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/RadioServiceUserControllerTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/RadioServiceUserControllerTest.java @@ -58,7 +58,7 @@ public final class RadioServiceUserControllerTest extends ExtendedRadioMockitoTe } @Test - public void isCurrentUser_forCurrentUser_returnsFalse() { + public void isCurrentOrSystemUser_forCurrentUser_returnsFalse() { when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1); assertWithMessage("Current user") @@ -66,7 +66,7 @@ public final class RadioServiceUserControllerTest extends ExtendedRadioMockitoTe } @Test - public void isCurrentUser_forNonCurrentUser_returnsFalse() { + public void isCurrentOrSystemUser_forNonCurrentUser_returnsFalse() { when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_2); assertWithMessage("Non-current user") @@ -74,7 +74,8 @@ public final class RadioServiceUserControllerTest extends ExtendedRadioMockitoTe } @Test - public void isCurrentUser_forSystemUser_returnsTrue() { + public void isCurrentOrSystemUser_forSystemUser_returnsTrue() { + when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1); when(mUserHandleMock.getIdentifier()).thenReturn(UserHandle.USER_SYSTEM); assertWithMessage("System user") @@ -82,10 +83,26 @@ public final class RadioServiceUserControllerTest extends ExtendedRadioMockitoTe } @Test - public void isCurrentUser_withActivityManagerFails_returnsFalse() { - doThrow(new RuntimeException()).when(() -> ActivityManager.getCurrentUser()); + public void isCurrentOrSystemUser_withActivityManagerFailure_returnsFalse() { + when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1); + doThrow(new RuntimeException()).when(ActivityManager::getCurrentUser); assertWithMessage("User when activity manager fails") .that(RadioServiceUserController.isCurrentOrSystemUser()).isFalse(); } + + @Test + public void getCurrentUser() { + assertWithMessage("Current user") + .that(RadioServiceUserController.getCurrentUser()).isEqualTo(USER_ID_1); + } + + @Test + public void getCurrentUser_withActivityManagerFailure_returnsUserNull() { + when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1); + doThrow(new RuntimeException()).when(ActivityManager::getCurrentUser); + + assertWithMessage("Current user when activity manager fails") + .that(RadioServiceUserController.getCurrentUser()).isEqualTo(UserHandle.USER_NULL); + } } diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java index 78b5a4ad71de..f85748c93c57 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java @@ -47,9 +47,11 @@ import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; import android.hardware.radio.RadioTuner; +import android.os.Binder; import android.os.ParcelableException; import android.os.RemoteException; import android.os.ServiceSpecificException; +import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; @@ -73,6 +75,8 @@ import java.util.Set; */ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { + private static final int USER_ID_1 = 11; + private static final int USER_ID_2 = 12; private static final VerificationWithTimeout CALLBACK_TIMEOUT = timeout(/* millis= */ 200); private static final int SIGNAL_QUALITY = 90; @@ -109,7 +113,10 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { SIGNAL_QUALITY); // Mocks - @Mock private IBroadcastRadio mBroadcastRadioMock; + @Mock + private UserHandle mUserHandleMock; + @Mock + private IBroadcastRadio mBroadcastRadioMock; private android.hardware.radio.ITunerCallback[] mAidlTunerCallbackMocks; // RadioModule under test @@ -124,14 +131,18 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { @Override protected void initializeSession(StaticMockitoSessionBuilder builder) { - builder.spyStatic(RadioServiceUserController.class).spyStatic(CompatChanges.class); + builder.spyStatic(RadioServiceUserController.class).spyStatic(CompatChanges.class) + .spyStatic(Binder.class); } @Before public void setup() throws Exception { + when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1); doReturn(true).when(() -> CompatChanges.isChangeEnabled( eq(ConversionUtils.RADIO_U_VERSION_REQUIRED), anyInt())); doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + doReturn(USER_ID_1).when(() -> RadioServiceUserController.getCurrentUser()); + doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle()); mRadioModule = new RadioModule(mBroadcastRadioMock, AidlTestUtils.makeDefaultModuleProperties()); @@ -421,6 +432,21 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { } @Test + public void tune_forSystemUser() throws Exception { + when(mUserHandleMock.getIdentifier()).thenReturn(UserHandle.USER_SYSTEM); + doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle()); + doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); + RadioManager.ProgramInfo tuneInfo = + AidlTestUtils.makeProgramInfo(initialSel, SIGNAL_QUALITY); + openAidlClients(/* numClients= */ 1); + + mTunerSessions[0].tune(initialSel); + + verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo); + } + + @Test public void tune_withUnknownErrorFromHal_fails() throws Exception { openAidlClients(/* numClients= */ 1); ProgramSelector sel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); @@ -1136,6 +1162,19 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { } @Test + public void onCurrentProgramInfoChanged_withNoncurrentUser_doesNotInvokeCallback() + throws Exception { + openAidlClients(1); + doReturn(USER_ID_2).when(() -> RadioServiceUserController.getCurrentUser()); + + mHalTunerCallback.onCurrentProgramInfoChanged(AidlTestUtils.makeHalProgramInfo( + AidlTestUtils.makeHalFmSelector(/* freq= */ 97300), SIGNAL_QUALITY)); + + verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) + .onCurrentProgramInfoChanged(any()); + } + + @Test public void onAntennaStateChange_forTunerCallback() throws Exception { int numSessions = 3; openAidlClients(numSessions); diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java index 3815008bd4fb..fac9eaafe94c 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java @@ -46,8 +46,10 @@ import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; import android.hardware.radio.RadioTuner; +import android.os.Binder; import android.os.ParcelableException; import android.os.RemoteException; +import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; @@ -74,6 +76,8 @@ import java.util.Map; @RunWith(MockitoJUnitRunner.class) public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { + private static final int USER_ID_1 = 11; + private static final int USER_ID_2 = 12; private static final VerificationWithTimeout CALLBACK_TIMEOUT = timeout(/* millis= */ 200); private static final int SIGNAL_QUALITY = 1; @@ -94,18 +98,25 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { private ProgramInfo mHalCurrentInfo; private TunerSession[] mTunerSessions; - @Mock private IBroadcastRadio mBroadcastRadioMock; - @Mock ITunerSession mHalTunerSessionMock; + @Mock + private UserHandle mUserHandleMock; + @Mock + private IBroadcastRadio mBroadcastRadioMock; + @Mock + ITunerSession mHalTunerSessionMock; private android.hardware.radio.ITunerCallback[] mAidlTunerCallbackMocks; @Override protected void initializeSession(StaticMockitoSessionBuilder builder) { - builder.spyStatic(RadioServiceUserController.class); + builder.spyStatic(RadioServiceUserController.class).spyStatic(Binder.class); } @Before public void setup() throws Exception { + when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1); + doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle()); doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + doReturn(USER_ID_1).when(() -> RadioServiceUserController.getCurrentUser()); mRadioModule = new RadioModule(mBroadcastRadioMock, TestUtils.makeDefaultModuleProperties()); @@ -387,6 +398,20 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { } @Test + public void tune_forSystemUser() throws Exception { + when(mUserHandleMock.getIdentifier()).thenReturn(UserHandle.USER_SYSTEM); + doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle()); + doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + ProgramSelector initialSel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); + RadioManager.ProgramInfo tuneInfo = TestUtils.makeProgramInfo(initialSel, SIGNAL_QUALITY); + openAidlClients(/* numClients= */ 1); + + mTunerSessions[0].tune(initialSel); + + verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo); + } + + @Test public void step_withDirectionUp() throws Exception { long initFreq = AM_FM_FREQUENCY_LIST[1]; ProgramSelector initialSel = TestUtils.makeFmSelector(initFreq); @@ -858,6 +883,19 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { } @Test + public void onCurrentProgramInfoChanged_withNoncurrentUser_doesNotInvokeCallback() + throws Exception { + openAidlClients(1); + doReturn(USER_ID_2).when(() -> RadioServiceUserController.getCurrentUser()); + + mHalTunerCallback.onCurrentProgramInfoChanged(TestUtils.makeHalProgramInfo( + TestUtils.makeHalFmSelector(/* freq= */ 97300), SIGNAL_QUALITY)); + + verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) + .onCurrentProgramInfoChanged(any()); + } + + @Test public void onConfigFlagUpdated_forTunerCallback() throws Exception { int numSessions = 3; openAidlClients(numSessions); diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java index fb0f3d419002..af81957d1e03 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java @@ -62,7 +62,6 @@ import android.util.MergedConfiguration; import android.view.Display; import android.view.View; -import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.rule.ActivityTestRule; @@ -616,7 +615,6 @@ public class ActivityThreadTest { } @Test - @FlakyTest(bugId = 176134235) public void testHandleConfigurationChanged_DoesntOverrideActivityConfig() { final TestActivity activity = mActivityTestRule.launchActivity(new Intent()); diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java index b917ac80256c..d9b73a8290f5 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java @@ -83,10 +83,7 @@ class TaskFragmentAnimationRunner extends IRemoteAnimationRunner.Stub { } @Override - public void onAnimationCancelled(boolean isKeyguardOccluded) { - if (TaskFragmentAnimationController.DEBUG) { - Log.v(TAG, "onAnimationCancelled: isKeyguardOccluded=" + isKeyguardOccluded); - } + public void onAnimationCancelled() { mHandler.post(this::cancelAnimation); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java index 22c90153bb39..edefe9e3ab06 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java @@ -404,7 +404,7 @@ class CrossActivityAnimation { } @Override - public void onAnimationCancelled(boolean isKeyguardOccluded) { + public void onAnimationCancelled() { finishAnimation(); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java index f0c5d8b29b2f..2d6ec7547187 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java @@ -323,7 +323,7 @@ class CustomizeActivityAnimation { } @Override - public void onAnimationCancelled(boolean isKeyguardOccluded) { + public void onAnimationCancelled() { finishAnimation(); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index 2afe8ee83391..b9ff5f0e820a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -282,6 +282,11 @@ public class BubbleStackView extends FrameLayout /** Whether the expanded view has been hidden, because we are dragging out a bubble. */ private boolean mExpandedViewTemporarilyHidden = false; + /** + * Whether the last bubble is being removed when expanded, which impacts the collapse animation. + */ + private boolean mRemovingLastBubbleWhileExpanded = false; + /** Animator for animating the expanded view's alpha (including the TaskView inside it). */ private final ValueAnimator mExpandedViewAlphaAnimator = ValueAnimator.ofFloat(0f, 1f); @@ -765,7 +770,7 @@ public class BubbleStackView extends FrameLayout // Update scrim if (!mScrimAnimating) { - showScrim(true); + showScrim(true, null /* runnable */); } } } @@ -880,6 +885,7 @@ public class BubbleStackView extends FrameLayout final Runnable onBubbleAnimatedOut = () -> { if (getBubbleCount() == 0) { + mExpandedViewTemporarilyHidden = false; mBubbleController.onAllBubblesAnimatedOut(); } }; @@ -1773,6 +1779,20 @@ public class BubbleStackView extends FrameLayout if (DEBUG_BUBBLE_STACK_VIEW) { Log.d(TAG, "removeBubble: " + bubble); } + if (isExpanded() && getBubbleCount() == 1) { + mRemovingLastBubbleWhileExpanded = true; + // We're expanded while the last bubble is being removed. Let the scrim animate away + // and then remove our views (removing the icon view triggers the removal of the + // bubble window so do that at the end of the animation so we see the scrim animate). + showScrim(false, () -> { + mRemovingLastBubbleWhileExpanded = false; + bubble.cleanupExpandedView(); + mBubbleContainer.removeView(bubble.getIconView()); + bubble.cleanupViews(); // cleans up the icon view + updateExpandedView(); // resets state for no expanded bubble + }); + return; + } // Remove it from the views for (int i = 0; i < getBubbleCount(); i++) { View v = mBubbleContainer.getChildAt(i); @@ -2143,7 +2163,7 @@ public class BubbleStackView extends FrameLayout mExpandedViewAlphaAnimator.start(); } - private void showScrim(boolean show) { + private void showScrim(boolean show, Runnable after) { AnimatorListenerAdapter listener = new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { @@ -2153,6 +2173,9 @@ public class BubbleStackView extends FrameLayout @Override public void onAnimationEnd(Animator animation) { mScrimAnimating = false; + if (after != null) { + after.run(); + } } }; if (show) { @@ -2179,7 +2202,7 @@ public class BubbleStackView extends FrameLayout } beforeExpandedViewAnimation(); - showScrim(true); + showScrim(true, null /* runnable */); updateZOrder(); updateBadges(false /* setBadgeForCollapsedStack */); mBubbleContainer.setActiveController(mExpandedAnimationController); @@ -2303,7 +2326,10 @@ public class BubbleStackView extends FrameLayout mIsExpanded = false; mIsExpansionAnimating = true; - showScrim(false); + if (!mRemovingLastBubbleWhileExpanded) { + // When we remove the last bubble it animates the scrim. + showScrim(false, null /* runnable */); + } mBubbleContainer.cancelAllAnimations(); 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 2f25511a1f4d..643245943916 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 @@ -460,7 +460,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, } } @Override - public void onAnimationCancelled(boolean isKeyguardOccluded) { + public void onAnimationCancelled() { final WindowContainerTransaction evictWct = new WindowContainerTransaction(); mStageCoordinator.prepareEvictInvisibleChildTasks(evictWct); mSyncQueue.queue(evictWct); 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 49e8227c98f1..4c903f500651 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 @@ -483,7 +483,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } @Override - public void onAnimationCancelled(boolean isKeyguardOccluded) { + public void onAnimationCancelled() { if (isEnteringSplit) { mMainExecutor.execute(() -> exitSplitScreen( mSideStage.getChildCount() == 0 ? mMainStage : mSideStage, @@ -869,7 +869,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, onRemoteAnimationFinished(apps); t.apply(); try { - adapter.getRunner().onAnimationCancelled(mKeyguardShowing); + adapter.getRunner().onAnimationCancelled(); } catch (RemoteException e) { Slog.e(TAG, "Error starting remote animation", e); } @@ -1013,11 +1013,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } @Override - public void onAnimationCancelled(boolean isKeyguardOccluded) { + public void onAnimationCancelled() { onRemoteAnimationFinishedOrCancelled(evictWct); setDividerVisibility(true, null); try { - adapter.getRunner().onAnimationCancelled(isKeyguardOccluded); + adapter.getRunner().onAnimationCancelled(); } catch (RemoteException e) { Slog.e(TAG, "Error starting remote animation", e); } @@ -1038,7 +1038,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, onRemoteAnimationFinished(apps); t.apply(); try { - adapter.getRunner().onAnimationCancelled(mKeyguardShowing); + adapter.getRunner().onAnimationCancelled(); } catch (RemoteException e) { Slog.e(TAG, "Error starting remote animation", e); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java index 61e92f355dc2..61e11e877b90 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java @@ -107,7 +107,7 @@ public class LegacyTransitions { } @Override - public void onAnimationCancelled(boolean isKeyguardOccluded) throws RemoteException { + public void onAnimationCancelled() throws RemoteException { mCancelled = true; mApps = mWallpapers = mNonApps = null; checkApply(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java index 5b7231c5a5fb..ef2a511177b2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java @@ -94,9 +94,11 @@ public class RemoteTransitionHandler implements Transitions.TransitionHandler { @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { - if (!Transitions.SHELL_TRANSITIONS_ROTATION && TransitionUtil.hasDisplayChange(info)) { + if (!Transitions.SHELL_TRANSITIONS_ROTATION && TransitionUtil.hasDisplayChange(info) + && !TransitionUtil.alwaysReportToKeyguard(info)) { // Note that if the remote doesn't have permission ACCESS_SURFACE_FLINGER, some // operations of the start transaction may be ignored. + mRequestedRemotes.remove(transition); return false; } RemoteTransition pendingRemote = mRequestedRemotes.get(transition); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index 5c8791effe18..a4057b1328f4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -650,7 +650,7 @@ public class Transitions implements RemoteCallable<Transitions> { active.mToken, info, active.mStartT, active.mFinishT); } - if (info.getRootCount() == 0 && !alwaysReportToKeyguard(info)) { + if (info.getRootCount() == 0 && !TransitionUtil.alwaysReportToKeyguard(info)) { // No root-leashes implies that the transition is empty/no-op, so just do // housekeeping and return. ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "No transition roots in %s so" @@ -699,23 +699,6 @@ public class Transitions implements RemoteCallable<Transitions> { return true; } - /** - * Some transitions we always need to report to keyguard even if they are empty. - * TODO (b/274954192): Remove this once keyguard dispatching moves to Shell. - */ - private static boolean alwaysReportToKeyguard(TransitionInfo info) { - // occlusion status of activities can change while screen is off so there will be no - // visibility change but we still need keyguardservice to be notified. - if (info.getType() == TRANSIT_KEYGUARD_UNOCCLUDE) return true; - - // It's possible for some activities to stop with bad timing (esp. since we can't yet - // queue activity transitions initiated by apps) that results in an empty transition for - // keyguard going-away. In general, we should should always report Keyguard-going-away. - if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_GOING_AWAY) != 0) return true; - - return false; - } - private boolean areTracksIdle() { for (int i = 0; i < mTracks.size(); ++i) { if (!mTracks.get(i).isIdle()) return false; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java index ce102917352d..c5cd2d91eb39 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java @@ -24,7 +24,9 @@ import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; +import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY; +import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; @@ -77,6 +79,23 @@ public class TransitionUtil { return false; } + /** + * Some transitions we always need to report to keyguard even if they are empty. + * TODO (b/274954192): Remove this once keyguard dispatching moves to Shell. + */ + public static boolean alwaysReportToKeyguard(TransitionInfo info) { + // occlusion status of activities can change while screen is off so there will be no + // visibility change but we still need keyguardservice to be notified. + if (info.getType() == TRANSIT_KEYGUARD_UNOCCLUDE) return true; + + // It's possible for some activities to stop with bad timing (esp. since we can't yet + // queue activity transitions initiated by apps) that results in an empty transition for + // keyguard going-away. In general, we should should always report Keyguard-going-away. + if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_GOING_AWAY) != 0) return true; + + return false; + } + /** Returns `true` if `change` is a wallpaper. */ public static boolean isWallpaper(TransitionInfo.Change change) { return (change.getTaskInfo() == null) 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 f9fdd831a42c..836efe0347c3 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 @@ -23,6 +23,7 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; +import android.content.res.TypedArray; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Region; @@ -95,7 +96,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin private int mWindowingPillHeight; private int mMoreActionsPillHeight; private int mShadowRadius; - private int mCornerRadius; + private int mMenuCornerRadius; DesktopModeWindowDecoration( Context context, @@ -182,6 +183,11 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mRelayoutParams.mShadowRadiusId = shadowRadiusID; mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw; + final TypedArray ta = mContext.obtainStyledAttributes( + new int[]{android.R.attr.dialogCornerRadius}); + mRelayoutParams.mCornerRadius = ta.getDimensionPixelSize(0, 0); + ta.recycle(); + relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult); // After this line, mTaskInfo is up-to-date and should be used instead of taskInfo 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 e772fc25f8cf..ac5ff2075901 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 @@ -16,6 +16,8 @@ package com.android.wm.shell.windowdecor; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; + import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; import android.content.res.Configuration; @@ -256,13 +258,17 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f; mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f; mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f; - Point taskPosition = mTaskInfo.positionInParent; + final Point taskPosition = mTaskInfo.positionInParent; startT.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight) .setShadowRadius(mTaskSurface, shadowRadius) .setColor(mTaskSurface, mTmpColor) .show(mTaskSurface); finishT.setPosition(mTaskSurface, taskPosition.x, taskPosition.y) .setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight); + if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) { + startT.setCornerRadius(mTaskSurface, params.mCornerRadius); + finishT.setCornerRadius(mTaskSurface, params.mCornerRadius); + } if (mCaptionWindowManager == null) { // Put caption under a container surface because ViewRootImpl sets the destination frame @@ -414,6 +420,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> int mCaptionWidthId; int mShadowRadiusId; + int mCornerRadius; + int mCaptionX; int mCaptionY; @@ -425,6 +433,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> mCaptionWidthId = Resources.ID_NULL; mShadowRadiusId = Resources.ID_NULL; + mCornerRadius = 0; + mCaptionX = 0; mCaptionY = 0; diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt index c5ee7b722617..86edc25b64d3 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker import android.app.Instrumentation import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.flicker.junit.FlickerBuilderProvider import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.FlickerTest diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt index 45024f387c25..798cc95c020f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt @@ -20,9 +20,9 @@ package com.android.wm.shell.flicker import android.tools.common.Rotation import android.tools.common.datatypes.Region -import android.tools.common.datatypes.component.IComponentMatcher import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject import android.tools.common.flicker.subject.layers.LayersTraceSubject +import android.tools.common.traces.component.IComponentMatcher import android.tools.device.flicker.legacy.FlickerTest import android.tools.device.helpers.WindowUtils @@ -218,11 +218,11 @@ fun FlickerTest.splitAppLayerBoundsChanges( assertLayers { if (landscapePosLeft) { splitAppLayerBoundsSnapToDivider( - component, - landscapePosLeft, - portraitPosTop, - scenario.endRotation - ) + component, + landscapePosLeft, + portraitPosTop, + scenario.endRotation + ) } else { splitAppLayerBoundsSnapToDivider( component, diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt index 983640a70c4b..3bc1e2acd015 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui" const val LAUNCHER_UI_PACKAGE_NAME = "com.google.android.apps.nexuslauncher" diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt index d01a0ee67f25..11c5951faa1f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt @@ -20,11 +20,11 @@ import android.content.Context import android.system.helpers.CommandsHelper import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.FlickerTest -import com.android.wm.shell.flicker.BaseTest -import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.flicker.helpers.LetterboxAppHelper import android.tools.device.flicker.legacy.FlickerTestFactory import android.tools.device.flicker.legacy.IFlickerTestData +import com.android.server.wm.flicker.helpers.LetterboxAppHelper +import com.android.server.wm.flicker.helpers.setRotation +import com.android.wm.shell.flicker.BaseTest import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd import com.android.wm.shell.flicker.appWindowIsVisibleAtStart import org.junit.Assume @@ -104,8 +104,8 @@ abstract class BaseAppCompat(flicker: FlickerTest) : BaseTest(flicker) { /** * Creates the test configurations. * - * See [FlickerTestFactory.rotationTests] for configuring screen orientation and - * navigation modes. + * See [FlickerTestFactory.rotationTests] for configuring screen orientation and navigation + * modes. */ @Parameterized.Parameters(name = "{0}") @JvmStatic diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt index c57100e44c17..f212a4e0417e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt @@ -17,11 +17,11 @@ package com.android.wm.shell.flicker.appcompat import android.platform.test.annotations.Postsubmit -import androidx.test.filters.RequiresDevice +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.FlickerTest -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.common.datatypes.component.ComponentNameMatcher +import androidx.test.filters.RequiresDevice import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized @@ -35,13 +35,13 @@ import org.junit.runners.Parameterized * ``` * Rotate non resizable portrait only app to opposite orientation to trigger size compat mode * ``` + * * Notes: * ``` * Some default assertions (e.g., nav bar, status bar and screen covered) * are inherited [BaseTest] * ``` */ - @RequiresDevice @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @@ -86,4 +86,4 @@ class OpenAppInSizeCompatModeTest(flicker: FlickerTest) : BaseAppCompat(flicker) .isInvisible(ComponentNameMatcher.ROTATION) } } -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt index f111a8d62d83..8e75439889b2 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt @@ -17,11 +17,11 @@ package com.android.wm.shell.flicker.appcompat import android.platform.test.annotations.Postsubmit -import androidx.test.filters.RequiresDevice +import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.FlickerTest -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.helpers.WindowUtils +import androidx.test.filters.RequiresDevice import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized @@ -36,13 +36,13 @@ import org.junit.runners.Parameterized * Rotate app to opposite orientation to trigger size compat mode * Press restart button and wait for letterboxed app to resize * ``` + * * Notes: * ``` * Some default assertions (e.g., nav bar, status bar and screen covered) * are inherited [BaseTest] * ``` */ - @RequiresDevice @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @@ -56,9 +56,7 @@ class RestartAppInSizeCompatModeTest(flicker: FlickerTest) : BaseAppCompat(flick teardown { letterboxApp.exit(wmHelper) } } - @Postsubmit - @Test - fun appVisibleAtStartAndEnd() = assertLetterboxAppVisibleAtStartAndEnd() + @Postsubmit @Test fun appVisibleAtStartAndEnd() = assertLetterboxAppVisibleAtStartAndEnd() @Postsubmit @Test @@ -83,4 +81,4 @@ class RestartAppInSizeCompatModeTest(flicker: FlickerTest) : BaseAppCompat(flick val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.endRotation) flicker.assertLayersEnd { visibleRegion(letterboxApp).coversAtMost(displayBounds) } } -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt index 18a3aa79f6e2..889e1771593d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.bubble import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.Postsubmit -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest @@ -149,9 +149,7 @@ class OpenActivityFromBubbleOnLocksreenTest(flicker: FlickerTest) : BaseBubbleSc @Ignore("Not applicable to this CUJ. Taskbar is not shown on lock screen") override fun taskBarWindowIsAlwaysVisible() {} - /** - * Checks that the [ComponentNameMatcher.TASK_BAR] is visible at the end of the transition - */ + /** Checks that the [ComponentNameMatcher.TASK_BAR] is visible at the end of the transition */ @Postsubmit @Test fun taskBarLayerIsVisibleAtEnd() { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt index 59918fb7b6a9..e6544c9f39bc 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt @@ -17,7 +17,7 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt index 36c6f7c438c4..2417c45bf9a0 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit import android.tools.common.Rotation -import android.tools.common.datatypes.component.ComponentNameMatcher.Companion.LAUNCHER +import android.tools.common.traces.component.ComponentNameMatcher.Companion.LAUNCHER import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.FlickerTest import android.tools.device.flicker.legacy.FlickerTestFactory diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt index db18edba9cc4..4b4613704a16 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt @@ -21,7 +21,7 @@ import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit import android.tools.common.Rotation -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt index 51f01364ec9c..bfd57786e615 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit import android.tools.common.Rotation -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.FlickerTest import android.tools.device.flicker.legacy.FlickerTestFactory diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt index 2001f484ed96..5ac9829b6c8f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit import android.tools.common.Rotation -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.flicker.legacy.FlickerTest import android.tools.device.flicker.legacy.FlickerTestFactory import com.android.server.wm.flicker.helpers.SimpleAppHelper diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt index 6deba1b68f38..bbb1c6c2ac63 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit import android.tools.common.Rotation -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt index a626713aaa11..6b061bbb1565 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit import android.tools.common.Rotation -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt index b30f30830156..eb1245b9ab86 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt @@ -20,7 +20,7 @@ import android.app.Instrumentation import android.content.Intent import android.platform.test.annotations.Presubmit import android.tools.common.Rotation -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.FlickerTest import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome 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 0c9c16153ea3..d53eac073e6b 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 @@ -19,8 +19,8 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.IwTest import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.component.ComponentNameMatcher -import android.tools.common.datatypes.component.EdgeExtensionComponentMatcher +import android.tools.common.traces.component.ComponentNameMatcher +import android.tools.common.traces.component.EdgeExtensionComponentMatcher import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.FlickerTest 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/splitscreen/SplitScreenUtils.kt index 625987a2e7ef..1063dfd8d737 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/splitscreen/SplitScreenUtils.kt @@ -19,9 +19,9 @@ package com.android.wm.shell.flicker.splitscreen import android.app.Instrumentation import android.graphics.Point import android.os.SystemClock -import android.tools.common.datatypes.component.ComponentNameMatcher -import android.tools.common.datatypes.component.IComponentMatcher -import android.tools.common.datatypes.component.IComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher +import android.tools.common.traces.component.IComponentMatcher +import android.tools.common.traces.component.IComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.traces.parsers.WindowManagerStateHelper import android.tools.device.traces.parsers.toFlickerComponent diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java index fc4bfd9754a0..5a2326b9c393 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java @@ -16,6 +16,8 @@ package com.android.wm.shell.windowdecor; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; + import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlBuilder; import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlTransaction; @@ -86,6 +88,7 @@ import java.util.function.Supplier; public class WindowDecorationTests extends ShellTestCase { private static final Rect TASK_BOUNDS = new Rect(100, 300, 400, 400); private static final Point TASK_POSITION_IN_PARENT = new Point(40, 60); + private static final int CORNER_RADIUS = 20; private final WindowDecoration.RelayoutResult<TestView> mRelayoutResult = new WindowDecoration.RelayoutResult<>(); @@ -130,6 +133,7 @@ public class WindowDecorationTests extends ShellTestCase { mCaptionMenuShadowRadiusId = R.dimen.test_caption_menu_shadow_radius; mCaptionMenuCornerRadiusId = R.dimen.test_caption_menu_corner_radius; mRelayoutParams.mShadowRadiusId = R.dimen.test_window_decor_shadow_radius; + mRelayoutParams.mCornerRadius = CORNER_RADIUS; doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory) .create(any(), any(), any()); @@ -209,6 +213,7 @@ public class WindowDecorationTests extends ShellTestCase { .setBounds(TASK_BOUNDS) .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y) .setVisible(true) + .setWindowingMode(WINDOWING_MODE_FREEFORM) .build(); taskInfo.isFocused = true; // Density is 2. Shadow radius is 10px. Caption height is 64px. @@ -249,6 +254,8 @@ public class WindowDecorationTests extends ShellTestCase { .setPosition(taskSurface, TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y); verify(mMockSurfaceControlFinishT) .setWindowCrop(taskSurface, 300, 100); + verify(mMockSurfaceControlStartT).setCornerRadius(taskSurface, CORNER_RADIUS); + verify(mMockSurfaceControlFinishT).setCornerRadius(taskSurface, CORNER_RADIUS); verify(mMockSurfaceControlStartT) .show(taskSurface); verify(mMockSurfaceControlStartT) diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index 193544edbf99..88b9643c12c1 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -934,13 +934,25 @@ public final class MediaCodecInfo { } } levelCaps = createFromProfileLevel(mMime, profile, maxLevel); - // remove profile from this format otherwise levelCaps.isFormatSupported will - // get into this same conditon and loop forever. - Map<String, Object> mapWithoutProfile = new HashMap<>(map); - mapWithoutProfile.remove(MediaFormat.KEY_PROFILE); - MediaFormat formatWithoutProfile = new MediaFormat(mapWithoutProfile); - if (levelCaps != null && !levelCaps.isFormatSupported(formatWithoutProfile)) { - return false; + // We must remove the profile from this format otherwise levelCaps.isFormatSupported + // will get into this same condition and loop forever. Furthermore, since levelCaps + // does not contain features and bitrate specific keys, keep only keys relevant for + // a level check. + Map<String, Object> levelCriticalFormatMap = new HashMap<>(map); + final Set<String> criticalKeys = + isVideo() ? VideoCapabilities.VIDEO_LEVEL_CRITICAL_FORMAT_KEYS : + isAudio() ? AudioCapabilities.AUDIO_LEVEL_CRITICAL_FORMAT_KEYS : + null; + + // critical keys will always contain KEY_MIME, but should also contain others to be + // meaningful + if (criticalKeys != null && criticalKeys.size() > 1 && levelCaps != null) { + levelCriticalFormatMap.keySet().retainAll(criticalKeys); + + MediaFormat levelCriticalFormat = new MediaFormat(levelCriticalFormatMap); + if (!levelCaps.isFormatSupported(levelCriticalFormat)) { + return false; + } } } if (mAudioCaps != null && !mAudioCaps.supportsFormat(format)) { @@ -1633,6 +1645,16 @@ public final class MediaCodecInfo { } } + /* package private */ + // must not contain KEY_PROFILE + static final Set<String> AUDIO_LEVEL_CRITICAL_FORMAT_KEYS = Set.of( + // We don't set level-specific limits for audio codecs today. Key candidates would + // be sample rate, bit rate or channel count. + // MediaFormat.KEY_SAMPLE_RATE, + // MediaFormat.KEY_CHANNEL_COUNT, + // MediaFormat.KEY_BIT_RATE, + MediaFormat.KEY_MIME); + /** @hide */ public boolean supportsFormat(MediaFormat format) { Map<String, Object> map = format.getMap(); @@ -2357,6 +2379,15 @@ public final class MediaCodecInfo { return ok; } + /* package private */ + // must not contain KEY_PROFILE + static final Set<String> VIDEO_LEVEL_CRITICAL_FORMAT_KEYS = Set.of( + MediaFormat.KEY_WIDTH, + MediaFormat.KEY_HEIGHT, + MediaFormat.KEY_FRAME_RATE, + MediaFormat.KEY_BIT_RATE, + MediaFormat.KEY_MIME); + /** * @hide * @throws java.lang.ClassCastException */ diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java index b6d70afa85b7..783528711877 100644 --- a/media/java/android/media/soundtrigger/SoundTriggerManager.java +++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java @@ -54,7 +54,6 @@ import android.util.Slog; import com.android.internal.app.ISoundTriggerService; import com.android.internal.app.ISoundTriggerSession; -import com.android.internal.util.Preconditions; import java.util.HashMap; import java.util.List; @@ -67,6 +66,8 @@ import java.util.concurrent.Executor; * models. Usage of this class is restricted to system or signature applications only. This allows * OEMs to write apps that can manage non-voice based sound trigger models. * + * If no ST module is available, {@link getModuleProperties()} will return {@code null}, and all + * other methods will throw {@link IllegalStateException}. * @hide */ @SystemApi @@ -82,7 +83,7 @@ public final class SoundTriggerManager { // Stores a mapping from the sound model UUID to the SoundTriggerInstance created by // the createSoundTriggerDetector() call. - private final HashMap<UUID, SoundTriggerDetector> mReceiverInstanceMap; + private final HashMap<UUID, SoundTriggerDetector> mReceiverInstanceMap = new HashMap<>(); /** * @hide @@ -121,7 +122,6 @@ public final class SoundTriggerManager { } mContext = context; mSoundTriggerService = soundTriggerService; - mReceiverInstanceMap = new HashMap<UUID, SoundTriggerDetector>(); } /** @@ -160,7 +160,7 @@ public final class SoundTriggerManager { .findFirst() .orElse(null); if (moduleProps == null) { - throw new IllegalStateException("Fake ST HAL should always be available"); + throw new AssertionError("Fake ST HAL should always be available"); } return moduleProps; } @@ -183,7 +183,6 @@ public final class SoundTriggerManager { } mContext = Objects.requireNonNull(context); mSoundTriggerService = Objects.requireNonNull(soundTriggerService); - mReceiverInstanceMap = new HashMap<UUID, SoundTriggerDetector>(); } /** @@ -241,7 +240,8 @@ public final class SoundTriggerManager { } try { GenericSoundModel model = - mSoundTriggerSession.getSoundModel(new ParcelUuid(soundModelId)); + mSoundTriggerSession.getSoundModel( + new ParcelUuid(Objects.requireNonNull(soundModelId))); if (model == null) { return null; } @@ -265,7 +265,8 @@ public final class SoundTriggerManager { } try { - mSoundTriggerSession.deleteSoundModel(new ParcelUuid(soundModelId)); + mSoundTriggerSession.deleteSoundModel( + new ParcelUuid(Objects.requireNonNull(soundModelId))); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -291,8 +292,8 @@ public final class SoundTriggerManager { @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public SoundTriggerDetector createSoundTriggerDetector(UUID soundModelId, @NonNull SoundTriggerDetector.Callback callback, @Nullable Handler handler) { - if (soundModelId == null || mSoundTriggerSession == null) { - return null; + if (mSoundTriggerSession == null) { + throw new IllegalStateException("No underlying SoundTriggerModule available"); } SoundTriggerDetector oldInstance = mReceiverInstanceMap.get(soundModelId); @@ -301,7 +302,8 @@ public final class SoundTriggerManager { } try { SoundTriggerDetector newInstance = new SoundTriggerDetector(mSoundTriggerSession, - mSoundTriggerSession.getSoundModel(new ParcelUuid(soundModelId)), + mSoundTriggerSession.getSoundModel( + new ParcelUuid(Objects.requireNonNull(soundModelId))), callback, handler); mReceiverInstanceMap.put(soundModelId, newInstance); return newInstance; @@ -469,8 +471,8 @@ public final class SoundTriggerManager { @UnsupportedAppUsage @TestApi public int loadSoundModel(@NonNull SoundModel soundModel) { - if (soundModel == null || mSoundTriggerSession == null) { - return STATUS_ERROR; + if (mSoundTriggerSession == null) { + throw new IllegalStateException("No underlying SoundTriggerModule available"); } try { @@ -513,11 +515,11 @@ public final class SoundTriggerManager { @UnsupportedAppUsage public int startRecognition(@NonNull UUID soundModelId, @Nullable Bundle params, @NonNull ComponentName detectionService, @NonNull RecognitionConfig config) { - Preconditions.checkNotNull(soundModelId); - Preconditions.checkNotNull(detectionService); - Preconditions.checkNotNull(config); + Objects.requireNonNull(soundModelId); + Objects.requireNonNull(detectionService); + Objects.requireNonNull(config); if (mSoundTriggerSession == null) { - return STATUS_ERROR; + throw new IllegalStateException("No underlying SoundTriggerModule available"); } try { return mSoundTriggerSession.startRecognitionForService(new ParcelUuid(soundModelId), @@ -534,11 +536,12 @@ public final class SoundTriggerManager { @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public int stopRecognition(UUID soundModelId) { - if (soundModelId == null || mSoundTriggerSession == null) { - return STATUS_ERROR; + if (mSoundTriggerSession == null) { + throw new IllegalStateException("No underlying SoundTriggerModule available"); } try { - return mSoundTriggerSession.stopRecognitionForService(new ParcelUuid(soundModelId)); + return mSoundTriggerSession.stopRecognitionForService( + new ParcelUuid(Objects.requireNonNull(soundModelId))); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -551,12 +554,12 @@ public final class SoundTriggerManager { @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public int unloadSoundModel(UUID soundModelId) { - if (soundModelId == null || mSoundTriggerSession == null) { - return STATUS_ERROR; + if (mSoundTriggerSession == null) { + throw new IllegalStateException("No underlying SoundTriggerModule available"); } try { return mSoundTriggerSession.unloadSoundModel( - new ParcelUuid(soundModelId)); + new ParcelUuid(Objects.requireNonNull(soundModelId))); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -604,7 +607,10 @@ public final class SoundTriggerManager { @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) @UnsupportedAppUsage public int getModelState(UUID soundModelId) { - if (soundModelId == null || mSoundTriggerSession == null) { + if (mSoundTriggerSession == null) { + throw new IllegalStateException("No underlying SoundTriggerModule available"); + } + if (soundModelId == null) { return STATUS_ERROR; } try { @@ -652,11 +658,12 @@ public final class SoundTriggerManager { public int setParameter(@Nullable UUID soundModelId, @ModelParams int modelParam, int value) { if (mSoundTriggerSession == null) { - return SoundTrigger.STATUS_INVALID_OPERATION; + throw new IllegalStateException("No underlying SoundTriggerModule available"); } try { - return mSoundTriggerSession.setParameter(new ParcelUuid(soundModelId), modelParam, + return mSoundTriggerSession.setParameter( + new ParcelUuid(Objects.requireNonNull(soundModelId)), modelParam, value); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -679,11 +686,11 @@ public final class SoundTriggerManager { public int getParameter(@NonNull UUID soundModelId, @ModelParams int modelParam) { if (mSoundTriggerSession == null) { - throw new IllegalArgumentException("Sound model is not loaded: " - + soundModelId.toString()); + throw new IllegalStateException("No underlying SoundTriggerModule available"); } try { - return mSoundTriggerSession.getParameter(new ParcelUuid(soundModelId), modelParam); + return mSoundTriggerSession.getParameter( + new ParcelUuid(Objects.requireNonNull(soundModelId)), modelParam); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -703,10 +710,11 @@ public final class SoundTriggerManager { public ModelParamRange queryParameter(@Nullable UUID soundModelId, @ModelParams int modelParam) { if (mSoundTriggerSession == null) { - return null; + throw new IllegalStateException("No underlying SoundTriggerModule available"); } try { - return mSoundTriggerSession.queryParameter(new ParcelUuid(soundModelId), modelParam); + return mSoundTriggerSession.queryParameter( + new ParcelUuid(Objects.requireNonNull(soundModelId)), modelParam); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 95522001d342..44aff6408f5b 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -385,6 +385,10 @@ android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz, jobject piidParcel) process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." ); + if (env->ExceptionCheck()) { + return UNKNOWN_ERROR; + } + // update the piid Parcel *request = parcelForJavaObject(env, piidParcel); auto reply = std::make_unique<Parcel>(); @@ -407,6 +411,10 @@ android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz, jobject piidPa process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." ); + if (env->ExceptionCheck()) { + return UNKNOWN_ERROR; + } + // update the piid Parcel *request = parcelForJavaObject(env, piidParcel); auto reply = std::make_unique<Parcel>(); diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml index 905e0ca92733..a3b27529d857 100644 --- a/packages/CredentialManager/res/values/strings.xml +++ b/packages/CredentialManager/res/values/strings.xml @@ -114,13 +114,13 @@ <!-- Strings for the get flow. --> <!-- This appears as the title of the modal bottom sheet asking for user confirmation to use the single previously saved passkey to sign in to the app. [CHAR LIMIT=200] --> <string name="get_dialog_title_use_passkey_for">Use your saved passkey for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string> - <!-- This appears as the title of the dialog asking for user confirmation to use the single previously saved credential to sign in to the app. [CHAR LIMIT=200] --> - <string name="get_dialog_title_use_sign_in_for">Use your saved sign-in for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string> - <!-- This appears as the title of the dialog asking for user to make a choice from various previously saved credentials to sign in to the app. [CHAR LIMIT=200] --> - <string name="get_dialog_title_choose_sign_in_for">Choose a saved sign-in for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g></string> - <!-- This appears as the title of the dialog asking for user to make a choice from various previously saved credentials to sign in to the app. [CHAR LIMIT=200] --> + <!-- This appears as the title of the dialog asking for user confirmation to use the single user credential (previously saved or to be created) to sign in to the app. [CHAR LIMIT=200] --> + <string name="get_dialog_title_use_sign_in_for">Use your sign-in for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string> + <!-- This appears as the title of the dialog asking for user to make a choice from various available user credentials (previously saved or to be created) to sign in to the app. [CHAR LIMIT=200] --> + <string name="get_dialog_title_choose_sign_in_for">Choose a sign-in for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g></string> + <!-- This appears as the title of the dialog asking for user to make a choice from options of available user information (e.g. driver's license, vaccination status) to pass to the app. [CHAR LIMIT=200] --> <string name="get_dialog_title_choose_option_for">Choose an option for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string> - <!-- This appears as the title of the dialog asking user to use a previously saved credentials to sign in to the app. [CHAR LIMIT=200] --> + <!-- This appears as the title of the dialog asking user to send a piece of user information (e.g. driver's license, vaccination status) to the app. [CHAR LIMIT=200] --> <string name="get_dialog_title_use_info_on">Use this info on <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string> <!-- This is a label for a button that links the user to different sign-in methods . [CHAR LIMIT=80] --> <string name="get_dialog_use_saved_passkey_for">Sign in another way</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java index 45c0d7823e99..adaf4a1d3ab5 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java @@ -14,7 +14,9 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL; import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; @@ -26,6 +28,8 @@ import android.net.NetworkKey; import android.net.NetworkRequest; import android.net.NetworkScoreManager; import android.net.ScoredNetwork; +import android.net.TransportInfo; +import android.net.vcn.VcnTransportInfo; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wifi.WifiNetworkScoreCache; @@ -34,8 +38,9 @@ import android.os.HandlerThread; import android.os.Looper; import android.provider.Settings; +import androidx.annotation.Nullable; + import com.android.settingslib.R; -import com.android.settingslib.Utils; import java.io.PrintWriter; import java.text.SimpleDateFormat; @@ -46,6 +51,7 @@ import java.util.Set; /** * Track status of Wi-Fi for the Sys UI. */ +@SuppressLint("MissingPermission") public class WifiStatusTracker { private static final int HISTORY_SIZE = 32; private static final SimpleDateFormat SSDF = new SimpleDateFormat("MM-dd HH:mm:ss.SSS"); @@ -66,8 +72,9 @@ public class WifiStatusTracker { private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder() .clearCapabilities() .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).build(); + .addTransportType(TRANSPORT_WIFI) + .addTransportType(TRANSPORT_CELLULAR) + .build(); private final NetworkCallback mNetworkCallback = new NetworkCallback(NetworkCallback.FLAG_INCLUDE_LOCATION_INFO) { // Note: onCapabilitiesChanged is guaranteed to be called "immediately" after onAvailable @@ -75,18 +82,10 @@ public class WifiStatusTracker { @Override public void onCapabilitiesChanged( Network network, NetworkCapabilities networkCapabilities) { - boolean isVcnOverWifi = false; - boolean isWifi = false; - WifiInfo wifiInfo = null; - if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { - wifiInfo = Utils.tryGetWifiInfoForVcn(networkCapabilities); - isVcnOverWifi = (wifiInfo != null); - } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { - wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo(); - isWifi = true; - } + WifiInfo wifiInfo = getMainOrUnderlyingWifiInfo(networkCapabilities); + boolean isWifi = connectionIsWifi(networkCapabilities, wifiInfo); // As long as it is a WiFi network, we will log it in the dumpsys for debugging. - if (isVcnOverWifi || isWifi) { + if (isWifi) { String log = new StringBuilder() .append(SSDF.format(System.currentTimeMillis())).append(",") .append("onCapabilitiesChanged: ") @@ -303,17 +302,8 @@ public class WifiStatusTracker { return; } NetworkCapabilities networkCapabilities; - isDefaultNetwork = false; - if (mDefaultNetworkCapabilities != null) { - boolean isWifi = mDefaultNetworkCapabilities.hasTransport( - NetworkCapabilities.TRANSPORT_WIFI); - boolean isVcnOverWifi = mDefaultNetworkCapabilities.hasTransport( - NetworkCapabilities.TRANSPORT_CELLULAR) - && (Utils.tryGetWifiInfoForVcn(mDefaultNetworkCapabilities) != null); - if (isWifi || isVcnOverWifi) { - isDefaultNetwork = true; - } - } + isDefaultNetwork = mDefaultNetworkCapabilities != null + && connectionIsWifi(mDefaultNetworkCapabilities); if (isDefaultNetwork) { // Wifi is connected and the default network. networkCapabilities = mDefaultNetworkCapabilities; @@ -352,6 +342,70 @@ public class WifiStatusTracker { ? null : AccessPoint.getSpeedLabel(mContext, scoredNetwork, rssi); } + @Nullable + private WifiInfo getMainOrUnderlyingWifiInfo(NetworkCapabilities networkCapabilities) { + WifiInfo mainWifiInfo = getMainWifiInfo(networkCapabilities); + if (mainWifiInfo != null) { + return mainWifiInfo; + } + + // Only CELLULAR networks may have underlying wifi information that's relevant to SysUI, + // so skip the underlying network check if it's not CELLULAR. + if (!networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) { + return mainWifiInfo; + } + + List<Network> underlyingNetworks = networkCapabilities.getUnderlyingNetworks(); + if (underlyingNetworks == null) { + return null; + } + + // Some connections, like VPN connections, may have underlying networks that are + // eventually traced to a wifi or carrier merged connection. So, check those underlying + // networks for possible wifi information as well. See b/225902574. + for (Network underlyingNetwork : underlyingNetworks) { + NetworkCapabilities underlyingNetworkCapabilities = + mConnectivityManager.getNetworkCapabilities(underlyingNetwork); + WifiInfo underlyingWifiInfo = getMainWifiInfo(underlyingNetworkCapabilities); + if (underlyingWifiInfo != null) { + return underlyingWifiInfo; + } + } + + return null; + } + + @Nullable + private WifiInfo getMainWifiInfo(NetworkCapabilities networkCapabilities) { + boolean canHaveWifiInfo = networkCapabilities.hasTransport(TRANSPORT_WIFI) + || networkCapabilities.hasTransport(TRANSPORT_CELLULAR); + if (!canHaveWifiInfo) { + return null; + } + + TransportInfo transportInfo = networkCapabilities.getTransportInfo(); + if (transportInfo instanceof VcnTransportInfo) { + // This VcnTransportInfo logic is copied from + // [com.android.settingslib.Utils.tryGetWifiInfoForVcn]. It's copied instead of + // re-used because it makes the logic here clearer. + return ((VcnTransportInfo) transportInfo).getWifiInfo(); + } else if (transportInfo instanceof WifiInfo) { + return (WifiInfo) transportInfo; + } else { + return null; + } + } + + private boolean connectionIsWifi(NetworkCapabilities networkCapabilities) { + return connectionIsWifi( + networkCapabilities, + getMainOrUnderlyingWifiInfo(networkCapabilities)); + } + + private boolean connectionIsWifi(NetworkCapabilities networkCapabilities, WifiInfo wifiInfo) { + return wifiInfo != null || networkCapabilities.hasTransport(TRANSPORT_WIFI); + } + /** Refresh the status label on Locale changed. */ public void refreshLocale() { updateStatusLabel(); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java index dc7e313dfcfa..6e975cf9d8f3 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java @@ -40,6 +40,8 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; +import java.util.Arrays; + @RunWith(RobolectricTestRunner.class) public class WifiStatusTrackerTest { @Mock Context mContext; @@ -48,13 +50,32 @@ public class WifiStatusTrackerTest { @Mock ConnectivityManager mConnectivityManager; @Mock Runnable mCallback; + private WifiStatusTracker mWifiStatusTracker; + private final ArgumentCaptor<ConnectivityManager.NetworkCallback> mNetworkCallbackCaptor = ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class); + private final ArgumentCaptor<ConnectivityManager.NetworkCallback> + mDefaultNetworkCallbackCaptor = + ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class); + @Before public void setUp() { MockitoAnnotations.initMocks(this); + + mWifiStatusTracker = new WifiStatusTracker( + mContext, + mWifiManager, + mNetworkScoreManager, + mConnectivityManager, + mCallback); + mWifiStatusTracker.setListening(true); + + verify(mConnectivityManager) + .registerNetworkCallback(any(), mNetworkCallbackCaptor.capture(), any()); + verify(mConnectivityManager) + .registerDefaultNetworkCallback(mDefaultNetworkCallbackCaptor.capture(), any()); } /** @@ -62,13 +83,6 @@ public class WifiStatusTrackerTest { */ @Test public void testWifiInfoClearedOnPrimaryNetworkLost() { - WifiStatusTracker wifiStatusTracker = new WifiStatusTracker(mContext, mWifiManager, - mNetworkScoreManager, mConnectivityManager, mCallback); - wifiStatusTracker.setListening(true); - - verify(mConnectivityManager) - .registerNetworkCallback(any(), mNetworkCallbackCaptor.capture(), any()); - // Trigger a validation callback for the primary Wifi network. WifiInfo primaryWifiInfo = Mockito.mock(WifiInfo.class); when(primaryWifiInfo.makeCopy(anyLong())).thenReturn(primaryWifiInfo); @@ -86,8 +100,8 @@ public class WifiStatusTrackerTest { mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap); // Verify primary wifi info is the one being used. - assertThat(wifiStatusTracker.connected).isTrue(); - assertThat(wifiStatusTracker.rssi).isEqualTo(primaryRssi); + assertThat(mWifiStatusTracker.connected).isTrue(); + assertThat(mWifiStatusTracker.rssi).isEqualTo(primaryRssi); // Trigger a validation callback for the non-primary Wifi network. WifiInfo nonPrimaryWifiInfo = Mockito.mock(WifiInfo.class); @@ -106,20 +120,189 @@ public class WifiStatusTrackerTest { mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(nonPrimaryNetwork, nonPrimaryCap); // Verify primary wifi info is still the one being used. - assertThat(wifiStatusTracker.connected).isTrue(); - assertThat(wifiStatusTracker.rssi).isEqualTo(primaryRssi); + assertThat(mWifiStatusTracker.connected).isTrue(); + assertThat(mWifiStatusTracker.rssi).isEqualTo(primaryRssi); // Lose the non-primary network. mNetworkCallbackCaptor.getValue().onLost(nonPrimaryNetwork); // Verify primary wifi info is still the one being used. - assertThat(wifiStatusTracker.connected).isTrue(); - assertThat(wifiStatusTracker.rssi).isEqualTo(primaryRssi); + assertThat(mWifiStatusTracker.connected).isTrue(); + assertThat(mWifiStatusTracker.rssi).isEqualTo(primaryRssi); // Lose the primary network. mNetworkCallbackCaptor.getValue().onLost(primaryNetwork); // Verify we aren't connected anymore. - assertThat(wifiStatusTracker.connected).isFalse(); + assertThat(mWifiStatusTracker.connected).isFalse(); + } + + @Test + public void isCarrierMerged_typicalWifi_false() { + WifiInfo primaryWifiInfo = Mockito.mock(WifiInfo.class); + when(primaryWifiInfo.isPrimary()).thenReturn(true); + + NetworkCapabilities primaryCap = Mockito.mock(NetworkCapabilities.class); + when(primaryCap.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)).thenReturn(true); + when(primaryCap.getTransportInfo()).thenReturn(primaryWifiInfo); + + Network primaryNetwork = Mockito.mock(Network.class); + int primaryNetworkId = 1; + when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId); + + mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap); + + assertThat(mWifiStatusTracker.isCarrierMerged).isFalse(); + } + + @Test + public void isCarrierMerged_typicalCellular_false() { + NetworkCapabilities primaryCap = Mockito.mock(NetworkCapabilities.class); + when(primaryCap.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).thenReturn(true); + + Network primaryNetwork = Mockito.mock(Network.class); + int primaryNetworkId = 1; + when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId); + + mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap); + + assertThat(mWifiStatusTracker.isCarrierMerged).isFalse(); + } + + @Test + public void isCarrierMerged_cellularCarrierMergedWifi_true() { + WifiInfo primaryWifiInfo = Mockito.mock(WifiInfo.class); + when(primaryWifiInfo.isPrimary()).thenReturn(true); + when(primaryWifiInfo.isCarrierMerged()).thenReturn(true); + + NetworkCapabilities primaryCap = Mockito.mock(NetworkCapabilities.class); + when(primaryCap.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).thenReturn(true); + when(primaryCap.getTransportInfo()).thenReturn(primaryWifiInfo); + + Network primaryNetwork = Mockito.mock(Network.class); + int primaryNetworkId = 1; + when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId); + + mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap); + + assertThat(mWifiStatusTracker.isCarrierMerged).isTrue(); + } + + /** Test for b/225902574. */ + @Test + public void isCarrierMerged_cellularWithUnderlyingCarrierMergedWifi_true() { + WifiInfo underlyingCarrierMergedInfo = Mockito.mock(WifiInfo.class); + when(underlyingCarrierMergedInfo.isPrimary()).thenReturn(true); + when(underlyingCarrierMergedInfo.isCarrierMerged()).thenReturn(true); + + NetworkCapabilities underlyingNetworkCapabilities = Mockito.mock(NetworkCapabilities.class); + when(underlyingNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) + .thenReturn(true); + when(underlyingNetworkCapabilities.getTransportInfo()) + .thenReturn(underlyingCarrierMergedInfo); + + Network underlyingNetwork = Mockito.mock(Network.class); + when(mConnectivityManager.getNetworkCapabilities(underlyingNetwork)) + .thenReturn(underlyingNetworkCapabilities); + + NetworkCapabilities mainCapabilities = Mockito.mock(NetworkCapabilities.class); + when(mainCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) + .thenReturn(true); + when(mainCapabilities.getTransportInfo()).thenReturn(null); + when(mainCapabilities.getUnderlyingNetworks()) + .thenReturn(Arrays.asList(underlyingNetwork)); + + Network primaryNetwork = Mockito.mock(Network.class); + int primaryNetworkId = 1; + when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId); + + mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, mainCapabilities); + + assertThat(mWifiStatusTracker.isCarrierMerged).isTrue(); + } + + @Test + public void isDefaultNetwork_typicalWifi_true() { + WifiInfo primaryWifiInfo = Mockito.mock(WifiInfo.class); + when(primaryWifiInfo.isPrimary()).thenReturn(true); + + NetworkCapabilities primaryCap = Mockito.mock(NetworkCapabilities.class); + when(primaryCap.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)).thenReturn(true); + when(primaryCap.getTransportInfo()).thenReturn(primaryWifiInfo); + + Network primaryNetwork = Mockito.mock(Network.class); + int primaryNetworkId = 1; + when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId); + + mDefaultNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap); + + assertThat(mWifiStatusTracker.isDefaultNetwork).isTrue(); + } + + @Test + public void isDefaultNetwork_typicalCellular_false() { + NetworkCapabilities primaryCap = Mockito.mock(NetworkCapabilities.class); + when(primaryCap.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).thenReturn(true); + + Network primaryNetwork = Mockito.mock(Network.class); + int primaryNetworkId = 1; + when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId); + + mDefaultNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap); + + assertThat(mWifiStatusTracker.isDefaultNetwork).isFalse(); + } + + @Test + public void isDefaultNetwork_cellularCarrierMergedWifi_true() { + WifiInfo primaryWifiInfo = Mockito.mock(WifiInfo.class); + when(primaryWifiInfo.isPrimary()).thenReturn(true); + when(primaryWifiInfo.isCarrierMerged()).thenReturn(true); + + NetworkCapabilities primaryCap = Mockito.mock(NetworkCapabilities.class); + when(primaryCap.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).thenReturn(true); + when(primaryCap.getTransportInfo()).thenReturn(primaryWifiInfo); + + Network primaryNetwork = Mockito.mock(Network.class); + int primaryNetworkId = 1; + when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId); + + mDefaultNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap); + + assertThat(mWifiStatusTracker.isDefaultNetwork).isTrue(); + } + + /** Test for b/225902574. */ + @Test + public void isDefaultNetwork_cellularWithUnderlyingCarrierMergedWifi_true() { + WifiInfo underlyingCarrierMergedInfo = Mockito.mock(WifiInfo.class); + when(underlyingCarrierMergedInfo.isPrimary()).thenReturn(true); + when(underlyingCarrierMergedInfo.isCarrierMerged()).thenReturn(true); + + NetworkCapabilities underlyingNetworkCapabilities = Mockito.mock(NetworkCapabilities.class); + when(underlyingNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) + .thenReturn(true); + when(underlyingNetworkCapabilities.getTransportInfo()) + .thenReturn(underlyingCarrierMergedInfo); + + Network underlyingNetwork = Mockito.mock(Network.class); + when(mConnectivityManager.getNetworkCapabilities(underlyingNetwork)) + .thenReturn(underlyingNetworkCapabilities); + + NetworkCapabilities mainCapabilities = Mockito.mock(NetworkCapabilities.class); + when(mainCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) + .thenReturn(true); + when(mainCapabilities.getTransportInfo()).thenReturn(null); + when(mainCapabilities.getUnderlyingNetworks()) + .thenReturn(Arrays.asList(underlyingNetwork)); + + Network primaryNetwork = Mockito.mock(Network.class); + int primaryNetworkId = 1; + when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId); + + mDefaultNetworkCallbackCaptor.getValue() + .onCapabilitiesChanged(primaryNetwork, mainCapabilities); + + assertThat(mWifiStatusTracker.isDefaultNetwork).isTrue(); } } diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index b95a149eb0cc..a5908a888449 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -252,9 +252,11 @@ filegroup { // domain "tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt", "tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt", + "tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt", "tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt", "tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt", "tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt", + "tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt", "tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt", // ui "tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt", @@ -263,6 +265,7 @@ filegroup { "tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt", "tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt", "tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt", + "tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt", // Keyguard helper "tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt", "tests/src/com/android/systemui/dump/LogBufferHelper.kt", diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 4652ef195a0c..32d6b70f7f47 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -966,22 +966,6 @@ android:permission="android.permission.BIND_JOB_SERVICE"/> <!-- region Note Task --> - <activity - android:name=".notetask.shortcut.CreateNoteTaskShortcutActivity" - android:enabled="false" - android:exported="true" - android:excludeFromRecents="true" - android:resizeableActivity="false" - android:theme="@android:style/Theme.NoDisplay" - android:label="@string/note_task_button_label" - android:icon="@drawable/ic_note_task_shortcut_widget"> - - <intent-filter> - <action android:name="android.intent.action.CREATE_SHORTCUT" /> - <category android:name="android.intent.category.DEFAULT" /> - </intent-filter> - </activity> - <service android:name=".notetask.NoteTaskControllerUpdateService" /> <activity diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt index 296c2ae5cf99..94b37403b232 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt @@ -436,8 +436,8 @@ class ActivityLaunchAnimator( } @BinderThread - override fun onAnimationCancelled(isKeyguardOccluded: Boolean) { - context.mainExecutor.execute { delegate.onAnimationCancelled(isKeyguardOccluded) } + override fun onAnimationCancelled() { + context.mainExecutor.execute { delegate.onAnimationCancelled() } } } @@ -744,7 +744,7 @@ class ActivityLaunchAnimator( } @UiThread - override fun onAnimationCancelled(isKeyguardOccluded: Boolean) { + override fun onAnimationCancelled() { if (timedOut) { return } @@ -754,7 +754,7 @@ class ActivityLaunchAnimator( removeTimeout() animation?.cancel() - controller.onLaunchAnimationCancelled(newKeyguardOccludedState = isKeyguardOccluded) + controller.onLaunchAnimationCancelled() } private fun IRemoteAnimationFinishedCallback.invoke() { diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationDelegate.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationDelegate.kt index 337408bb9c5d..d465962d6edf 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationDelegate.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationDelegate.kt @@ -26,5 +26,5 @@ interface RemoteAnimationDelegate<in T : IRemoteAnimationFinishedCallback> { ) /** Called on the UI thread when a signal is received to cancel the animation. */ - @UiThread fun onAnimationCancelled(isKeyguardOccluded: Boolean) + @UiThread fun onAnimationCancelled() } diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt index 9d1dd1b67801..3a19990f0627 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt @@ -22,12 +22,11 @@ import android.annotation.IntRange import android.annotation.SuppressLint import android.content.Context import android.graphics.Canvas -import android.graphics.Rect import android.text.Layout import android.text.TextUtils import android.text.format.DateFormat import android.util.AttributeSet -import android.util.MathUtils +import android.util.MathUtils.constrainedMap import android.widget.TextView import com.android.internal.annotations.VisibleForTesting import com.android.systemui.animation.GlyphCallback @@ -40,8 +39,6 @@ import java.io.PrintWriter import java.util.Calendar import java.util.Locale import java.util.TimeZone -import kotlin.math.max -import kotlin.math.min /** * Displays the time with the hour positioned above the minutes. (ie: 09 above 30 is 9:30) @@ -478,122 +475,56 @@ class AnimatableClockView @JvmOverloads constructor( pw.println(" time=$time") } - fun moveForSplitShade(fromRect: Rect, toRect: Rect, fraction: Float) { - // Do we need to cancel an in-flight animation? - // Need to also check against 0.0f here; we can sometimes get two calls with fraction == 0, - // which trips up the check otherwise. - if (lastSeenAnimationProgress != 1.0f && - lastSeenAnimationProgress != 0.0f && - fraction == 0.0f) { - // New animation, but need to stop the old one. Figure out where each glyph currently - // is in relation to the box position. After that, use the leading digit's current - // position as the stop target. - currentAnimationNeededStop = true - - // We assume that the current glyph offsets would be relative to the "from" position. - val moveAmount = toRect.left - fromRect.left - - // Remap the current glyph offsets to be relative to the new "end" position, and figure - // out the start/end positions for the stop animation. - for (i in 0 until NUM_DIGITS) { - glyphOffsets[i] = -moveAmount + glyphOffsets[i] - animationCancelStartPosition[i] = glyphOffsets[i] - } + private val moveToCenterDelays + get() = if (isLayoutRtl) MOVE_LEFT_DELAYS else MOVE_RIGHT_DELAYS - // Use the leading digit's offset as the stop position. - if (toRect.left > fromRect.left) { - // It _was_ moving left - animationCancelStopPosition = glyphOffsets[0] - } else { - // It was moving right - animationCancelStopPosition = glyphOffsets[1] - } - } - - // Is there a cancellation in progress? - if (currentAnimationNeededStop && fraction < ANIMATION_CANCELLATION_TIME) { - val animationStopProgress = MathUtils.constrainedMap( - 0.0f, 1.0f, 0.0f, ANIMATION_CANCELLATION_TIME, fraction - ) + private val moveToSideDelays + get() = if (isLayoutRtl) MOVE_RIGHT_DELAYS else MOVE_LEFT_DELAYS - // One of the digits has already stopped. - val animationStopStep = 1.0f / (NUM_DIGITS - 1) - - for (i in 0 until NUM_DIGITS) { - val stopAmount = if (toRect.left > fromRect.left) { - // It was moving left (before flipping) - MOVE_LEFT_DELAYS[i] * animationStopStep - } else { - // It was moving right (before flipping) - MOVE_RIGHT_DELAYS[i] * animationStopStep - } - - // Leading digit stops immediately. - if (stopAmount == 0.0f) { - glyphOffsets[i] = animationCancelStopPosition - } else { - val actualStopAmount = MathUtils.constrainedMap( - 0.0f, 1.0f, 0.0f, stopAmount, animationStopProgress + /** + * Offsets the glyphs of the clock for the step clock animation. + * + * The animation makes the glyphs of the clock move at different speeds, when the clock is + * moving horizontally. + * + * @param clockStartLeft the [getLeft] position of the clock, before it started moving. + * @param clockMoveDirection the direction in which it is moving. A positive number means right, + * and negative means left. + * @param moveFraction fraction of the clock movement. 0 means it is at the beginning, and 1 + * means it finished moving. + */ + fun offsetGlyphsForStepClockAnimation( + clockStartLeft: Int, + clockMoveDirection: Int, + moveFraction: Float + ) { + val isMovingToCenter = if (isLayoutRtl) clockMoveDirection < 0 else clockMoveDirection > 0 + val currentMoveAmount = left - clockStartLeft + val digitOffsetDirection = if (isLayoutRtl) -1 else 1 + for (i in 0 until NUM_DIGITS) { + // The delay for the digit, in terms of fraction (i.e. the digit should not move + // during 0.0 - 0.1). + val digitInitialDelay = + if (isMovingToCenter) { + moveToCenterDelays[i] * MOVE_DIGIT_STEP + } else { + moveToSideDelays[i] * MOVE_DIGIT_STEP + } + val digitFraction = + MOVE_INTERPOLATOR.getInterpolation( + constrainedMap( + 0.0f, + 1.0f, + digitInitialDelay, + digitInitialDelay + AVAILABLE_ANIMATION_TIME, + moveFraction + ) ) - val easedProgress = MOVE_INTERPOLATOR.getInterpolation(actualStopAmount) - val glyphMoveAmount = - animationCancelStopPosition - animationCancelStartPosition[i] - glyphOffsets[i] = - animationCancelStartPosition[i] + glyphMoveAmount * easedProgress - } - } - } else { - // Normal part of the animation. - // Do we need to remap the animation progress to take account of the cancellation? - val actualFraction = if (currentAnimationNeededStop) { - MathUtils.constrainedMap( - 0.0f, 1.0f, ANIMATION_CANCELLATION_TIME, 1.0f, fraction - ) - } else { - fraction - } - - val digitFractions = (0 until NUM_DIGITS).map { - // The delay for each digit, in terms of fraction (i.e. the digit should not move - // during 0.0 - 0.1). - val initialDelay = if (toRect.left > fromRect.left) { - MOVE_RIGHT_DELAYS[it] * MOVE_DIGIT_STEP - } else { - MOVE_LEFT_DELAYS[it] * MOVE_DIGIT_STEP - } - - val f = MathUtils.constrainedMap( - 0.0f, 1.0f, - initialDelay, initialDelay + AVAILABLE_ANIMATION_TIME, - actualFraction - ) - MOVE_INTERPOLATOR.getInterpolation(max(min(f, 1.0f), 0.0f)) - } - - // Was there an animation halt? - val moveAmount = if (currentAnimationNeededStop) { - // Only need to animate over the remaining space if the animation was aborted. - -animationCancelStopPosition - } else { - toRect.left.toFloat() - fromRect.left.toFloat() - } - - for (i in 0 until NUM_DIGITS) { - glyphOffsets[i] = -moveAmount + (moveAmount * digitFractions[i]) - } + val moveAmountForDigit = currentMoveAmount * digitFraction + val moveAmountDeltaForDigit = moveAmountForDigit - currentMoveAmount + glyphOffsets[i] = digitOffsetDirection * moveAmountDeltaForDigit } - invalidate() - - if (fraction == 1.0f) { - // Reset - currentAnimationNeededStop = false - } - - lastSeenAnimationProgress = fraction - - // Ensure that the actual clock container is always in the "end" position. - this.setLeftTopRightBottom(toRect.left, toRect.top, toRect.right, toRect.bottom) } // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often. @@ -647,9 +578,6 @@ class AnimatableClockView @JvmOverloads constructor( private const val NUM_DIGITS = 4 private const val DIGITS_PER_LINE = 2 - // How much of "fraction" to spend on canceling the animation, if needed - private const val ANIMATION_CANCELLATION_TIME = 0f - // Delays. Each digit's animation should have a slight delay, so we get a nice // "stepping" effect. When moving right, the second digit of the hour should move first. // When moving left, the first digit of the hour should move first. The lists encode @@ -668,6 +596,6 @@ class AnimatableClockView @JvmOverloads constructor( // Total available transition time for each digit, taking into account the step. If step is // 0.1, then digit 0 would animate over 0.0 - 0.7, making availableTime 0.7. - private val AVAILABLE_ANIMATION_TIME = 1.0f - MOVE_DIGIT_STEP * (NUM_DIGITS - 1) + private const val AVAILABLE_ANIMATION_TIME = 1.0f - MOVE_DIGIT_STEP * (NUM_DIGITS - 1) } } diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt index f57432c073c1..b0c02407873c 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt @@ -151,6 +151,7 @@ open class ClockRegistry( { str1 = id }, { "Clock Id conflict on load: $str1 is double registered" } ) + manager.unloadPlugin() continue } diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt index 3fda83d7b6f4..2cc36008e4f8 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt @@ -189,8 +189,9 @@ class DefaultClockController( view.setLayoutParams(lp) } - fun moveForSplitShade(fromRect: Rect, toRect: Rect, fraction: Float) { - view.moveForSplitShade(fromRect, toRect, fraction) + /** See documentation at [AnimatableClockView.offsetGlyphsForStepClockAnimation]. */ + fun offsetGlyphsForStepClockAnimation(fromLeft: Int, direction: Int, fraction: Float) { + view.offsetGlyphsForStepClockAnimation(fromLeft, direction, fraction) } } @@ -277,8 +278,8 @@ class DefaultClockController( dozeFraction: Float, foldFraction: Float, ) : DefaultClockAnimations(view, dozeFraction, foldFraction) { - override fun onPositionUpdated(fromRect: Rect, toRect: Rect, fraction: Float) { - largeClock.moveForSplitShade(fromRect, toRect, fraction) + override fun onPositionUpdated(fromLeft: Int, direction: Int, fraction: Float) { + largeClock.offsetGlyphsForStepClockAnimation(fromLeft, direction, fraction) } } diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt index 8ef2d8033000..ca3e710a4acb 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt @@ -141,8 +141,16 @@ interface ClockAnimations { /** Runs the battery animation (if any). */ fun charge() {} - /** Move the clock, for example, if the notification tray appears in split-shade mode. */ - fun onPositionUpdated(fromRect: Rect, toRect: Rect, fraction: Float) {} + /** + * Runs when the clock's position changed during the move animation. + * + * @param fromLeft the [View.getLeft] position of the clock, before it started moving. + * @param direction the direction in which it is moving. A positive number means right, and + * negative means left. + * @param fraction fraction of the clock movement. 0 means it is at the beginning, and 1 means + * it finished moving. + */ + fun onPositionUpdated(fromLeft: Int, direction: Int, fraction: Float) {} /** * Runs when swiping clock picker, swipingFraction: 1.0 -> clock is scaled up in the preview, diff --git a/packages/SystemUI/res/layout/screen_record_dialog.xml b/packages/SystemUI/res/layout/screen_record_dialog.xml index ab38dd2aebba..ae052502a110 100644 --- a/packages/SystemUI/res/layout/screen_record_dialog.xml +++ b/packages/SystemUI/res/layout/screen_record_dialog.xml @@ -49,13 +49,13 @@ android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:fontFamily="@*android:string/config_headlineFontFamily" - android:text="@string/screenrecord_start_label" + android:text="@string/screenrecord_permission_dialog_title" android:layout_marginTop="22dp" android:layout_marginBottom="15dp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/screenrecord_description" + android:text="@string/screenrecord_permission_dialog_warning_entire_screen" android:textAppearance="?android:attr/textAppearanceSmall" android:textColor="?android:textColorSecondary" android:gravity="center" @@ -168,7 +168,7 @@ android:layout_height="wrap_content" android:layout_weight="0" android:layout_gravity="end" - android:text="@string/screenrecord_start" + android:text="@string/screenrecord_continue" style="@style/Widget.Dialog.Button" /> </LinearLayout> </LinearLayout> diff --git a/packages/SystemUI/res/layout/screen_share_dialog.xml b/packages/SystemUI/res/layout/screen_share_dialog.xml index bd719894e25f..7dbe0598f3c8 100644 --- a/packages/SystemUI/res/layout/screen_share_dialog.xml +++ b/packages/SystemUI/res/layout/screen_share_dialog.xml @@ -63,7 +63,7 @@ android:id="@+id/text_warning" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/screenrecord_description" + android:text="@string/screenrecord_permission_dialog_warning_entire_screen" android:textAppearance="?android:attr/textAppearanceSmall" android:textColor="?android:textColorSecondary" android:gravity="start" @@ -91,7 +91,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="0" - android:text="@string/screenrecord_start" + android:text="@string/screenrecord_continue" style="@style/Widget.Dialog.Button" /> </LinearLayout> </LinearLayout> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 4e68efeea870..853930e174a7 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -251,25 +251,22 @@ <string name="app_clips_save_add_to_note">Add to note</string> <!-- Notification title displayed for screen recording [CHAR LIMIT=50]--> - <string name="screenrecord_name">Screen Recorder</string> + <string name="screenrecord_title">Screen Recorder</string> <!-- Processing screen recoding video in the background [CHAR LIMIT=30]--> <string name="screenrecord_background_processing_label">Processing screen recording</string> <!-- Description of the screen recording notification channel [CHAR LIMIT=NONE]--> <string name="screenrecord_channel_description">Ongoing notification for a screen record session</string> + + <!-- For updated Screen Recording permission dialog (i.e. with PSS)--> <!-- Title for the screen prompting the user to begin recording their screen [CHAR LIMIT=NONE]--> - <string name="screenrecord_start_label">Start Recording?</string> - <!-- Message reminding the user that sensitive information may be captured during a screen recording [CHAR_LIMIT=NONE]--> - <string name="screenrecord_description">While recording, Android System can capture any sensitive information that\u2019s visible on your screen or played on your device. This includes passwords, payment info, photos, messages, and audio.</string> - <!-- Dropdown option to record the entire screen [CHAR_LIMIT=30]--> - <string name="screenrecord_option_entire_screen">Record entire screen</string> - <!-- Dropdown option to record a single app [CHAR_LIMIT=30]--> - <string name="screenrecord_option_single_app">Record a single app</string> + <string name="screenrecord_permission_dialog_title">Start Recording?</string> <!-- Message reminding the user that sensitive information may be captured during a full screen recording for the updated dialog that includes partial screen sharing option [CHAR_LIMIT=350]--> - <string name="screenrecord_warning_entire_screen">While you\'re recording, Android has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages, or other sensitive information.</string> + <string name="screenrecord_permission_dialog_warning_entire_screen">While you’re recording, Android has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string> <!-- Message reminding the user that sensitive information may be captured during a single app screen recording for the updated dialog that includes partial screen sharing option [CHAR_LIMIT=350]--> - <string name="screenrecord_warning_single_app">While you\'re recording an app, Android has access to anything shown or played on that app. So be careful with passwords, payment details, messages, or other sensitive information.</string> + <string name="screenrecord_permission_dialog_warning_single_app">While you’re recording an app, Android has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string> <!-- Button to start a screen recording in the updated screen record dialog that allows to select an app to record [CHAR LIMIT=50]--> - <string name="screenrecord_start_recording">Start recording</string> + <string name="screenrecord_permission_dialog_continue">Start recording</string> + <!-- Label for a switch to enable recording audio [CHAR LIMIT=NONE]--> <string name="screenrecord_audio_label">Record audio</string> <!-- Label for the option to record audio from the device [CHAR LIMIT=NONE]--> @@ -281,7 +278,7 @@ <!-- Label for an option to record audio from both device and microphone [CHAR LIMIT=NONE]--> <string name="screenrecord_device_audio_and_mic_label">Device audio and microphone</string> <!-- Button to start a screen recording [CHAR LIMIT=50]--> - <string name="screenrecord_start">Start</string> + <string name="screenrecord_continue">Start</string> <!-- Notification text displayed when we are recording the screen [CHAR LIMIT=100]--> <string name="screenrecord_ongoing_screen_only">Recording screen</string> <!-- Notification text displayed when we are recording both the screen and audio [CHAR LIMIT=100]--> @@ -1064,47 +1061,52 @@ <!-- Label for button in confirmation dialog when exiting guest session [CHAR LIMIT=35] --> <string name="user_remove_user_remove">Remove</string> - <!-- Media projection permission dialog warning text. [CHAR LIMIT=NONE] --> - <string name="media_projection_dialog_text"><xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages, and audio that you play.</string> - - <!-- Media projection permission dialog warning text for system services. [CHAR LIMIT=NONE] --> - <string name="media_projection_dialog_service_text">The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages, and audio that you play.</string> - - <!-- Media projection permission dialog warning title for system services. [CHAR LIMIT=NONE] --> - <string name="media_projection_dialog_service_title">Start recording or casting?</string> - + <!-- Media projection without Partial Screenshare --> <!-- Media projection permission dialog warning title. [CHAR LIMIT=NONE] --> <string name="media_projection_dialog_title">Start recording or casting with <xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g>?</string> + <!-- Media projection permission dialog warning text. [CHAR LIMIT=NONE] --> + <string name="media_projection_dialog_warning"><xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages, and audio that you play.</string> + <!-- Media projection permission dialog warning title for system services. [CHAR LIMIT=NONE] --> + <string name="media_projection_sys_service_dialog_title">Start recording or casting?</string> + <!-- Media projection permission dialog warning text for system services. [CHAR LIMIT=NONE] --> + <string name="media_projection_sys_service_dialog_warning">The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages, and audio that you play.</string> - <!-- Media projection permission dialog title. [CHAR LIMIT=NONE] --> - <string name="media_projection_permission_dialog_title">Allow <xliff:g id="app_seeking_permission" example="Meet">%s</xliff:g> to share or record?</string> - - <!-- Media projection permission dropdown option for capturing the whole screen. [CHAR LIMIT=30] --> - <string name="media_projection_permission_dialog_option_entire_screen">Entire screen</string> - - <!-- Media projection permission dropdown option for capturing single app. [CHAR LIMIT=30] --> - <string name="media_projection_permission_dialog_option_single_app">A single app</string> - - <!-- Media projection permission warning for capturing the whole screen. [CHAR LIMIT=350] --> - <string name="media_projection_permission_dialog_warning_entire_screen">When you\'re sharing, recording, or casting, <xliff:g id="app_seeking_permission" example="Meet">%s</xliff:g> has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages, or other sensitive information.</string> - - <!-- Media projection permission warning for capturing an app. [CHAR LIMIT=350] --> - <string name="media_projection_permission_dialog_warning_single_app">When you\'re sharing, recording, or casting an app, <xliff:g id="app_seeking_permission" example="Meet">%s</xliff:g> has access to anything shown or played on that app. So be careful with passwords, payment details, messages, or other sensitive information.</string> - - <!-- Media projection permission button to continue with app selection or recording [CHAR LIMIT=60] --> - <string name="media_projection_permission_dialog_continue">Continue</string> - + <!-- Permission dropdown option for sharing or recording the whole screen. [CHAR LIMIT=30] --> + <string name="screen_share_permission_dialog_option_entire_screen">Entire screen</string> + <!-- Permission dropdown option for sharing or recording single app. [CHAR LIMIT=30] --> + <string name="screen_share_permission_dialog_option_single_app">A single app</string> <!-- Title of the dialog that allows to select an app to share or record [CHAR LIMIT=NONE] --> - <string name="media_projection_permission_app_selector_title">Share or record an app</string> - - <!-- Media projection permission dialog title when there is no app name (e.g. it could be a system service when casting). [CHAR LIMIT=100] --> - <string name="media_projection_permission_dialog_system_service_title">Allow this app to share or record?</string> - - <!-- Media projection permission warning for capturing the whole screen when a system service requests it (e.g. when casting). [CHAR LIMIT=350] --> - <string name="media_projection_permission_dialog_system_service_warning_entire_screen">When you\'re sharing, recording, or casting, this app has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages, or other sensitive information.</string> - - <!-- Media projection permission warning for capturing a single app when a system service requests it (e.g. when casting). [CHAR LIMIT=350] --> - <string name="media_projection_permission_dialog_system_service_warning_single_app">When you\'re sharing, recording, or casting an app, this app has access to anything shown or played on that app. So be careful with passwords, payment details, messages, or other sensitive information.</string> + <string name="screen_share_permission_app_selector_title">Share or record an app</string> + + <!-- Media projection that launched from 1P/3P apps --> + <!-- 1P/3P app media projection permission dialog title. [CHAR LIMIT=NONE] --> + <string name="media_projection_entry_app_permission_dialog_title">Start recording or casting with <xliff:g id="app_seeking_permission" example="Meet">%s</xliff:g>?</string> + <!-- 1P/3P app media projection permission warning for capturing the whole screen. [CHAR LIMIT=350] --> + <string name="media_projection_entry_app_permission_dialog_warning_entire_screen">When you’re sharing, recording, or casting, <xliff:g id="app_seeking_permission" example="Meet">%s</xliff:g> has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string> + <!-- 1P/3P app media projection permission warning for capturing an app. [CHAR LIMIT=350] --> + <string name="media_projection_entry_app_permission_dialog_warning_single_app">When you’re sharing, recording, or casting an app, <xliff:g id="app_seeking_permission" example="Meet">%s</xliff:g> has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string> + <!-- 1P/3P apps media projection permission button to continue with app selection or recording [CHAR LIMIT=60] --> + <string name="media_projection_entry_app_permission_dialog_continue">Start</string> + + <!-- Casting that launched by SysUI (i.e. when there is no app name) --> + <!-- System casting media projection permission dialog title. [CHAR LIMIT=100] --> + <string name="media_projection_entry_cast_permission_dialog_title">Start casting?</string> + <!-- System casting media projection permission warning for capturing the whole screen when SysUI casting requests it. [CHAR LIMIT=350] --> + <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen">When you’re casting, Android has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string> + <!-- System casting media projection permission warning for capturing a single app when SysUI casting requests it. [CHAR LIMIT=350] --> + <string name="media_projection_entry_cast_permission_dialog_warning_single_app">When you’re casting an app, Android has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string> + <!-- System casting media projection permission button to continue for SysUI casting. [CHAR LIMIT=60] --> + <string name="media_projection_entry_cast_permission_dialog_continue">Start casting</string> + + <!-- Other sharing (not recording nor casting) that launched by SysUI (currently not in use) --> + <!-- System sharing media projection permission dialog title. [CHAR LIMIT=100] --> + <string name="media_projection_entry_generic_permission_dialog_title">Start sharing?</string> + <!-- System sharing media projection permission warning for capturing the whole screen. [CHAR LIMIT=350] --> + <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen">When you’re sharing, recording, or casting, Android has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string> + <!-- System sharing media projection permission warning for capturing a single app. [CHAR LIMIT=350] --> + <string name="media_projection_entry_generic_permission_dialog_warning_single_app">When you’re sharing, recording, or casting an app, Android has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string> + <!-- System sharing media projection permission button to continue. [CHAR LIMIT=60] --> + <string name="media_projection_entry_generic_permission_dialog_continue">Start</string> <!-- Title for the dialog that is shown when screen capturing is disabled by enterprise policy. [CHAR LIMIT=100] --> <string name="screen_capturing_disabled_by_policy_dialog_title">Blocked by your IT admin</string> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java index 3d05542116e0..4f73fc426c3b 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java @@ -109,7 +109,7 @@ public class PluginActionManager<T extends Plugin> { /** Load all plugins matching this instance's action. */ public void loadAll() { if (DEBUG) Log.d(TAG, "startListening"); - mBgExecutor.execute(this::queryAll); + mBgExecutor.execute(() -> queryAll()); } /** Unload all plugins managed by this instance. */ @@ -255,17 +255,18 @@ public class PluginActionManager<T extends Plugin> { intent.setPackage(pkgName); } List<ResolveInfo> result = mPm.queryIntentServices(intent, 0); - if (DEBUG) Log.d(TAG, "Found " + result.size() + " plugins"); + if (DEBUG) { + Log.d(TAG, "Found " + result.size() + " plugins"); + for (ResolveInfo info : result) { + ComponentName name = new ComponentName(info.serviceInfo.packageName, + info.serviceInfo.name); + Log.d(TAG, " " + name); + } + } + if (result.size() > 1 && !mAllowMultiple) { // TODO: Show warning. Log.w(TAG, "Multiple plugins found for " + mAction); - if (DEBUG) { - for (ResolveInfo info : result) { - ComponentName name = new ComponentName(info.serviceInfo.packageName, - info.serviceInfo.name); - Log.w(TAG, " " + name); - } - } return; } for (ResolveInfo info : result) { @@ -307,7 +308,7 @@ public class PluginActionManager<T extends Plugin> { // TODO: Only create the plugin before version check if we need it for // legacy version check. if (DEBUG) { - Log.d(TAG, "createPlugin"); + Log.d(TAG, "createPlugin: " + component); } try { return mPluginInstanceFactory.create( @@ -317,7 +318,7 @@ public class PluginActionManager<T extends Plugin> { reportInvalidVersion(component, component.getClassName(), e); } } catch (Throwable e) { - Log.w(TAG, "Couldn't load plugin: " + packageName, e); + Log.w(TAG, "Couldn't load plugin: " + component, e); return null; } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java index 1b0dacc327c1..8dcd2aaac9ef 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java @@ -206,7 +206,7 @@ public abstract class RemoteAnimationRunnerCompat extends IRemoteAnimationRunner t.close(); info.releaseAllSurfaces(); if (finishRunnable == null) return; - onAnimationCancelled(false /* isKeyguardOccluded */); + onAnimationCancelled(); finishRunnable.run(); } }; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java index edfcb8d0d1a6..0826f8a8b985 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java @@ -363,8 +363,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV } else { View clockView = clockContainerView.getChildAt(0); - transition.excludeTarget(clockView, /* exclude= */ true); - TransitionSet set = new TransitionSet(); set.addTransition(transition); @@ -389,8 +387,9 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV @VisibleForTesting static class SplitShadeTransitionAdapter extends Transition { - private static final String PROP_BOUNDS = "splitShadeTransitionAdapter:bounds"; - private static final String[] TRANSITION_PROPERTIES = { PROP_BOUNDS }; + private static final String PROP_BOUNDS_LEFT = "splitShadeTransitionAdapter:boundsLeft"; + private static final String PROP_X_IN_WINDOW = "splitShadeTransitionAdapter:xInWindow"; + private static final String[] TRANSITION_PROPERTIES = { PROP_BOUNDS_LEFT, PROP_X_IN_WINDOW}; private final KeyguardClockSwitchController mController; @@ -400,12 +399,10 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV } private void captureValues(TransitionValues transitionValues) { - Rect boundsRect = new Rect(); - boundsRect.left = transitionValues.view.getLeft(); - boundsRect.top = transitionValues.view.getTop(); - boundsRect.right = transitionValues.view.getRight(); - boundsRect.bottom = transitionValues.view.getBottom(); - transitionValues.values.put(PROP_BOUNDS, boundsRect); + transitionValues.values.put(PROP_BOUNDS_LEFT, transitionValues.view.getLeft()); + int[] locationInWindowTmp = new int[2]; + transitionValues.view.getLocationInWindow(locationInWindowTmp); + transitionValues.values.put(PROP_X_IN_WINDOW, locationInWindowTmp[0]); } @Override @@ -427,8 +424,12 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV } ValueAnimator anim = ValueAnimator.ofFloat(0, 1); - Rect from = (Rect) startValues.values.get(PROP_BOUNDS); - Rect to = (Rect) endValues.values.get(PROP_BOUNDS); + int fromLeft = (int) startValues.values.get(PROP_BOUNDS_LEFT); + int fromWindowX = (int) startValues.values.get(PROP_X_IN_WINDOW); + int toWindowX = (int) endValues.values.get(PROP_X_IN_WINDOW); + // Using windowX, to determine direction, instead of left, as in RTL the difference of + // toLeft - fromLeft is always positive, even when moving left. + int direction = toWindowX - fromWindowX > 0 ? 1 : -1; anim.addUpdateListener(animation -> { ClockController clock = mController.getClock(); @@ -437,7 +438,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV } clock.getLargeClock().getAnimations() - .onPositionUpdated(from, to, animation.getAnimatedFraction()); + .onPositionUpdated(fromLeft, direction, animation.getAnimatedFraction()); }); return anim; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 2c669bbb8fed..9573913e5e2f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -396,6 +396,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private int mFaceRunningState = BIOMETRIC_STATE_STOPPED; private boolean mIsDreaming; private boolean mLogoutEnabled; + private boolean mIsFaceEnrolled; private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID; private int mPostureState = DEVICE_POSTURE_UNKNOWN; private FingerprintInteractiveToAuthProvider mFingerprintInteractiveToAuthProvider; @@ -2572,6 +2573,16 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } + private void updateFaceEnrolled(int userId) { + final Boolean isFaceEnrolled = isFaceSupported() + && mBiometricEnabledForUser.get(userId) + && mAuthController.isFaceAuthEnrolled(userId); + if (mIsFaceEnrolled != isFaceEnrolled) { + mLogger.logFaceEnrolledUpdated(mIsFaceEnrolled, isFaceEnrolled); + } + mIsFaceEnrolled = isFaceEnrolled; + } + private boolean isFaceSupported() { return mFaceManager != null && !mFaceSensorProperties.isEmpty(); } @@ -2611,17 +2622,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } /** - * @return true if there's at least one face enrolled for the given user - */ - private boolean isFaceEnrolled(int userId) { - return mAuthController.isFaceAuthEnrolled(userId); - } - - /** - * @return true if there's at least one face enrolled for the current user + * @return true if there's at least one face enrolled */ public boolean isFaceEnrolled() { - return isFaceEnrolled(getCurrentUser()); + return mIsFaceEnrolled; } private final UserTracker.Callback mUserChangedCallback = new UserTracker.Callback() { @@ -3280,13 +3284,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @SuppressLint("MissingPermission") @VisibleForTesting boolean isUnlockWithFingerprintPossible(int userId) { - boolean newFpPossible = isFingerprintSupported() - && !isFingerprintDisabled(userId) && mAuthController.isFingerprintEnrolled(userId); - Boolean oldFpPossible = mIsUnlockWithFingerprintPossible.getOrDefault(userId, false); - if (oldFpPossible != newFpPossible) { - mLogger.logFpPossibleUpdated(userId, oldFpPossible, newFpPossible); - } - mIsUnlockWithFingerprintPossible.put(userId, newFpPossible); + // TODO (b/242022358), make this rely on onEnrollmentChanged event and update it only once. + boolean newFpEnrolled = isFingerprintSupported() + && !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId); + Boolean oldFpEnrolled = mIsUnlockWithFingerprintPossible.getOrDefault(userId, false); + if (oldFpEnrolled != newFpEnrolled) { + mLogger.logFpEnrolledUpdated(userId, oldFpEnrolled, newFpEnrolled); + } + mIsUnlockWithFingerprintPossible.put(userId, newFpEnrolled); return mIsUnlockWithFingerprintPossible.get(userId); } @@ -3301,13 +3306,24 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab /** * @deprecated This is being migrated to use modern architecture. */ - @VisibleForTesting @Deprecated - public boolean isUnlockWithFacePossible(int userId) { + private boolean isUnlockWithFacePossible(int userId) { if (isFaceAuthInteractorEnabled()) { return getFaceAuthInteractor().canFaceAuthRun(); } - return isFaceSupported() && isFaceEnrolled(userId) && !isFaceDisabled(userId); + return isFaceAuthEnabledForUser(userId) && !isFaceDisabled(userId); + } + + /** + * If face hardware is available, user has enrolled and enabled auth via setting. + * + * @deprecated This is being migrated to use modern architecture. + */ + @Deprecated + public boolean isFaceAuthEnabledForUser(int userId) { + // TODO (b/242022358), make this rely on onEnrollmentChanged event and update it only once. + updateFaceEnrolled(userId); + return mIsFaceEnrolled; } private void stopListeningForFingerprint() { diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt index fe4014575156..16618064f249 100644 --- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt +++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt @@ -630,7 +630,7 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { ) } - fun logFpPossibleUpdated(userId: Int, oldValue: Boolean, newValue: Boolean) { + fun logFpEnrolledUpdated(userId: Int, oldValue: Boolean, newValue: Boolean) { logBuffer.log( TAG, DEBUG, @@ -639,7 +639,7 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { bool1 = oldValue bool2 = newValue }, - { "Fp possible state changed for userId: $int1 old: $bool1, new: $bool2" } + { "Fp enrolled state changed for userId: $int1 old: $bool1, new: $bool2" } ) } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/OWNERS b/packages/SystemUI/src/com/android/systemui/accessibility/OWNERS new file mode 100644 index 000000000000..1f66c91b3573 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 44215 + +include /core/java/android/view/accessibility/OWNERS
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java index f3c71da63594..4158390ec953 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java @@ -45,6 +45,8 @@ import android.view.accessibility.AccessibilityManager; import com.android.internal.R; import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity; +import com.android.internal.accessibility.util.AccessibilityUtils; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ScreenshotHelper; import com.android.systemui.CoreStartable; import com.android.systemui.dagger.SysUISingleton; @@ -520,8 +522,11 @@ public class SystemActions implements CoreStartable { SCREENSHOT_ACCESSIBILITY_ACTIONS, new Handler(Looper.getMainLooper()), null); } - private void handleHeadsetHook() { - sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HEADSETHOOK); + @VisibleForTesting + void handleHeadsetHook() { + if (!AccessibilityUtils.interceptHeadsetHookForActiveCall(mContext)) { + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HEADSETHOOK); + } } private void handleAccessibilityButton() { diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java index 7bfd84e4b647..155c26d9fe9d 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java @@ -463,13 +463,17 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest if ((configDiff & ActivityInfo.CONFIG_UI_MODE) != 0 || (configDiff & ActivityInfo.CONFIG_ASSETS_PATHS) != 0 || (configDiff & ActivityInfo.CONFIG_FONT_SCALE) != 0 + || (configDiff & ActivityInfo.CONFIG_LOCALE) != 0 || (configDiff & ActivityInfo.CONFIG_DENSITY) != 0) { // We listen to following config changes to trigger layout inflation: // CONFIG_UI_MODE: theme change // CONFIG_ASSETS_PATHS: wallpaper change // CONFIG_FONT_SCALE: font size change + // CONFIG_LOCALE: language change // CONFIG_DENSITY: display size change + mParams.accessibilityTitle = getAccessibilityWindowTitle(mContext); + boolean showSettingPanelAfterThemeChange = mIsVisible; hideSettingPanel(/* resetPosition= */ false); inflateView(); @@ -490,11 +494,6 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest + mDraggableWindowBounds.top; return; } - - if ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0) { - updateAccessibilityWindowTitle(); - return; - } } private void onWindowInsetChanged() { @@ -515,13 +514,6 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest } } - private void updateAccessibilityWindowTitle() { - mParams.accessibilityTitle = getAccessibilityWindowTitle(mContext); - if (mIsVisible) { - mWindowManager.updateViewLayout(mSettingView, mParams); - } - } - public void editMagnifierSizeMode(boolean enable) { setEditMagnifierSizeMode(enable); updateSelectedButton(MagnificationSize.NONE); diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt index 3d6d3356fb55..18bd46756660 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt @@ -41,7 +41,8 @@ open class ControlsBindingControllerImpl @Inject constructor( private val context: Context, @Background private val backgroundExecutor: DelayableExecutor, private val lazyController: Lazy<ControlsController>, - userTracker: UserTracker + private val packageUpdateMonitorFactory: PackageUpdateMonitor.Factory, + userTracker: UserTracker, ) : ControlsBindingController { companion object { @@ -93,7 +94,8 @@ open class ControlsBindingControllerImpl @Inject constructor( backgroundExecutor, actionCallbackService, currentUser, - component + component, + packageUpdateMonitorFactory ) } diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt index 217f4d89e24c..cb2476ce0ebf 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt @@ -16,6 +16,7 @@ package com.android.systemui.controls.controller +import android.annotation.WorkerThread import android.content.ComponentName import android.content.Context import android.content.Intent @@ -23,7 +24,6 @@ import android.content.ServiceConnection import android.os.Binder import android.os.Bundle import android.os.IBinder -import android.os.RemoteException import android.os.UserHandle import android.service.controls.ControlsProviderService import android.service.controls.ControlsProviderService.CALLBACK_BUNDLE @@ -38,6 +38,7 @@ import android.util.Log import com.android.internal.annotations.GuardedBy import com.android.systemui.util.concurrency.DelayableExecutor import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicBoolean /** * Manager for the lifecycle of the connection to a given [ControlsProviderService]. @@ -45,6 +46,9 @@ import java.util.concurrent.TimeUnit * This class handles binding and unbinding and requests to the service. The class will queue * requests until the service is connected and dispatch them then. * + * If the provider app is updated, and we are currently bound to it, it will try to rebind after + * update is completed. + * * @property context A SystemUI context for binding to the services * @property executor A delayable executor for posting timeouts * @property actionCallbackService a callback interface to hand the remote service for sending @@ -59,22 +63,22 @@ class ControlsProviderLifecycleManager( private val executor: DelayableExecutor, private val actionCallbackService: IControlsActionCallback.Stub, val user: UserHandle, - val componentName: ComponentName -) : IBinder.DeathRecipient { + val componentName: ComponentName, + packageUpdateMonitorFactory: PackageUpdateMonitor.Factory, +) { val token: IBinder = Binder() private var requiresBound = false @GuardedBy("queuedServiceMethods") private val queuedServiceMethods: MutableSet<ServiceMethod> = ArraySet() private var wrapper: ServiceWrapper? = null - private var bindTryCount = 0 private val TAG = javaClass.simpleName private var onLoadCanceller: Runnable? = null + private var lastForPanel = false + companion object { - private const val BIND_RETRY_DELAY = 1000L // ms private const val LOAD_TIMEOUT_SECONDS = 20L // seconds - private const val MAX_BIND_RETRIES = 5 private const val DEBUG = true private val BIND_FLAGS = Context.BIND_AUTO_CREATE or Context.BIND_FOREGROUND_SERVICE or Context.BIND_NOT_PERCEPTIBLE @@ -91,60 +95,56 @@ class ControlsProviderLifecycleManager( }) } + private val packageUpdateMonitor = packageUpdateMonitorFactory.create( + user, + componentName.packageName, + ) { + if (requiresBound) { + // Let's unbind just in case. onBindingDied should have been called and unbound before. + executor.execute { + unbindAndCleanup("package updated") + bindService(true, lastForPanel) + } + } + } + private fun bindService(bind: Boolean, forPanel: Boolean = false) { executor.execute { - requiresBound = bind - if (bind) { - if (bindTryCount != MAX_BIND_RETRIES && wrapper == null) { - if (DEBUG) { - Log.d(TAG, "Binding service $intent") - } - bindTryCount++ - try { - val flags = if (forPanel) BIND_FLAGS_PANEL else BIND_FLAGS - val bound = context - .bindServiceAsUser(intent, serviceConnection, flags, user) - if (!bound) { - context.unbindService(serviceConnection) - } - } catch (e: SecurityException) { - Log.e(TAG, "Failed to bind to service", e) - } - } - } else { - if (DEBUG) { - Log.d(TAG, "Unbinding service $intent") - } - bindTryCount = 0 - wrapper?.run { - context.unbindService(serviceConnection) - } - wrapper = null - } + bindServiceBackground(bind, forPanel) } } private val serviceConnection = object : ServiceConnection { + + val connected = AtomicBoolean(false) + override fun onServiceConnected(name: ComponentName, service: IBinder) { if (DEBUG) Log.d(TAG, "onServiceConnected $name") - bindTryCount = 0 wrapper = ServiceWrapper(IControlsProvider.Stub.asInterface(service)) - try { - service.linkToDeath(this@ControlsProviderLifecycleManager, 0) - } catch (_: RemoteException) {} + packageUpdateMonitor.startMonitoring() handlePendingServiceMethods() } override fun onServiceDisconnected(name: ComponentName?) { if (DEBUG) Log.d(TAG, "onServiceDisconnected $name") wrapper = null - bindService(false) + // No need to call unbind. We may get a new `onServiceConnected` } override fun onNullBinding(name: ComponentName?) { if (DEBUG) Log.d(TAG, "onNullBinding $name") wrapper = null - context.unbindService(this) + executor.execute { + unbindAndCleanup("null binding") + } + } + + override fun onBindingDied(name: ComponentName?) { + super.onBindingDied(name) + if (DEBUG) Log.d(TAG, "onBindingDied $name") + executor.execute { + unbindAndCleanup("binder died") + } } } @@ -159,14 +159,55 @@ class ControlsProviderLifecycleManager( } } - override fun binderDied() { - if (wrapper == null) return - wrapper = null - if (requiresBound) { - if (DEBUG) { - Log.d(TAG, "binderDied") + @WorkerThread + private fun bindServiceBackground(bind: Boolean, forPanel: Boolean = true) { + requiresBound = bind + if (bind) { + if (wrapper == null) { + if (DEBUG) { + Log.d(TAG, "Binding service $intent") + } + try { + lastForPanel = forPanel + val flags = if (forPanel) BIND_FLAGS_PANEL else BIND_FLAGS + var bound = false + if (serviceConnection.connected.compareAndSet(false, true)) { + bound = context + .bindServiceAsUser(intent, serviceConnection, flags, user) + } + if (!bound) { + Log.d(TAG, "Couldn't bind to $intent") + doUnbind() + } + } catch (e: SecurityException) { + Log.e(TAG, "Failed to bind to service", e) + // Couldn't even bind. Let's reset the connected value + serviceConnection.connected.set(false) + } } - // Try rebinding some time later + } else { + unbindAndCleanup("unbind requested") + packageUpdateMonitor.stopMonitoring() + } + } + + @WorkerThread + private fun unbindAndCleanup(reason: String) { + if (DEBUG) { + Log.d(TAG, "Unbinding service $intent. Reason: $reason") + } + wrapper = null + try { + doUnbind() + } catch (e: IllegalArgumentException) { + Log.e(TAG, "Failed to unbind service", e) + } + } + + @WorkerThread + private fun doUnbind() { + if (serviceConnection.connected.compareAndSet(true, false)) { + context.unbindService(serviceConnection) } } @@ -313,7 +354,7 @@ class ControlsProviderLifecycleManager( fun run() { if (!callWrapper()) { queueServiceMethod(this) - binderDied() + executor.execute { unbindAndCleanup("couldn't call through binder") } } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/PackageUpdateMonitor.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/PackageUpdateMonitor.kt new file mode 100644 index 000000000000..1973b620b34f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/PackageUpdateMonitor.kt @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.controls.controller + +import android.content.Context +import android.os.Handler +import android.os.UserHandle +import com.android.internal.content.PackageMonitor +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import java.util.concurrent.atomic.AtomicBoolean + +/** [PackageMonitor] that tracks when [packageName] has finished updating for user [user]. */ +class PackageUpdateMonitor +@AssistedInject +constructor( + @Assisted private val user: UserHandle, + @Assisted private val packageName: String, + @Assisted private val callback: Runnable, + @Background private val bgHandler: Handler, + @Application private val context: Context, +) : PackageMonitor() { + + private val monitoring = AtomicBoolean(false) + + @AssistedFactory + fun interface Factory { + /** + * Create a [PackageUpdateMonitor] for a given [user] and [packageName]. It will run + * [callback] every time the package finishes updating. + */ + fun create(user: UserHandle, packageName: String, callback: Runnable): PackageUpdateMonitor + } + + /** Start monitoring for package updates. No-op if already monitoring. */ + fun startMonitoring() { + if (monitoring.compareAndSet(/* expected */ false, /* new */ true)) { + register(context, user, false, bgHandler) + } + } + + /** Stop monitoring for package updates. No-op if not monitoring. */ + fun stopMonitoring() { + if (monitoring.compareAndSet(/* expected */ true, /* new */ false)) { + unregister() + } + } + + /** + * If the package and the user match the ones for this [PackageUpdateMonitor], it will run + * [callback]. + */ + override fun onPackageUpdateFinished(packageName: String?, uid: Int) { + super.onPackageUpdateFinished(packageName, uid) + if (packageName == this.packageName && UserHandle.getUserHandleForUid(uid) == user) { + callback.run() + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt index 2c717f5af8da..45cb13be361e 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt @@ -16,11 +16,11 @@ package com.android.systemui.controls.controller -import android.service.controls.actions.ControlAction import android.service.controls.IControlsActionCallback import android.service.controls.IControlsProvider import android.service.controls.IControlsSubscriber import android.service.controls.IControlsSubscription +import android.service.controls.actions.ControlAction import android.service.controls.actions.ControlActionWrapper import android.util.Log diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt new file mode 100644 index 000000000000..eb7929095a4b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.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.dreams + +import com.android.systemui.log.dagger.DreamLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel +import javax.inject.Inject + +/** Logs dream-related stuff to a {@link LogBuffer}. */ +class DreamLogger @Inject constructor(@DreamLog private val buffer: LogBuffer) { + /** Logs a debug message to the buffer. */ + fun d(tag: String, message: String) { + buffer.log(tag, LogLevel.DEBUG, { str1 = message }, { message }) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt index 5b56c04ae8aa..df46e07e0911 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt @@ -21,6 +21,7 @@ import android.animation.AnimatorSet import android.animation.ValueAnimator import android.view.View import android.view.animation.Interpolator +import androidx.core.animation.doOnCancel import androidx.core.animation.doOnEnd import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle @@ -65,7 +66,11 @@ constructor( private val mDreamInTranslationYDistance: Int, @Named(DreamOverlayModule.DREAM_IN_TRANSLATION_Y_DURATION) private val mDreamInTranslationYDurationMs: Long, + private val mLogger: DreamLogger, ) { + companion object { + private const val TAG = "DreamOverlayAnimationsController" + } private var mAnimator: Animator? = null private lateinit var view: View @@ -169,8 +174,11 @@ constructor( doOnEnd { mAnimator = null mOverlayStateController.setEntryAnimationsFinished(true) + mLogger.d(TAG, "Dream overlay entry animations finished.") } + doOnCancel { mLogger.d(TAG, "Dream overlay entry animations canceled.") } start() + mLogger.d(TAG, "Dream overlay entry animations started.") } } @@ -232,8 +240,11 @@ constructor( doOnEnd { mAnimator = null mOverlayStateController.setExitAnimationsRunning(false) + mLogger.d(TAG, "Dream overlay exit animations finished.") } + doOnCancel { mLogger.d(TAG, "Dream overlay exit animations canceled.") } start() + mLogger.d(TAG, "Dream overlay exit animations started.") } mOverlayStateController.setExitAnimationsRunning(true) return mAnimator as AnimatorSet diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 942730344f20..e31834cef5b4 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -68,8 +68,6 @@ object Flags { val NOTIFICATION_MEMORY_LOGGING_ENABLED = unreleasedFlag(119, "notification_memory_logging_enabled") - @JvmField val USE_ROUNDNESS_SOURCETYPES = releasedFlag(116, "use_roundness_sourcetype") - @JvmField val SIMPLIFIED_APPEAR_FRACTION = releasedFlag(259395680, "simplified_appear_fraction") @@ -81,7 +79,8 @@ object Flags { // TODO(b/278873737): Tracking Bug @JvmField val LOAD_NOTIFICATIONS_BEFORE_THE_USER_SWITCH_IS_COMPLETE = - unreleasedFlag(278873737, "load_notifications_before_the_user_switch_is_complete") + unreleasedFlag(278873737, "load_notifications_before_the_user_switch_is_complete", + teamfood = true) // TODO(b/277338665): Tracking Bug @JvmField @@ -116,7 +115,7 @@ object Flags { // TODO(b/275694445): Tracking Bug @JvmField - val LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING = releasedFlag(208, + val LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING = unreleasedFlag(208, "lockscreen_without_secure_lock_when_dreaming") /** @@ -679,8 +678,8 @@ object Flags { // TODO(b/272805037): Tracking Bug @JvmField - val ADVANCED_VPN_ENABLED = unreleasedFlag(2800, name = "AdvancedVpn__enable_feature", - namespace = "vpn", teamfood = true) + val ADVANCED_VPN_ENABLED = releasedFlag(2800, name = "AdvancedVpn__enable_feature", + namespace = "vpn") // TODO(b/278761837): Tracking Bug @JvmField diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java index 107e685c4482..8b6bd2486117 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java @@ -243,7 +243,7 @@ public class KeyguardService extends Service { Slog.e(TAG, "Called mergeAnimation, but finish callback is missing"); return; } - runner.onAnimationCancelled(false /* isKeyguardOccluded */); + runner.onAnimationCancelled(); currentFinishCB.onTransitionFinished(null /* wct */, null /* t */); } catch (RemoteException e) { // nothing, we'll just let it finish on its own I guess. @@ -418,7 +418,7 @@ public class KeyguardService extends Service { } @Override // Binder interface - public void onAnimationCancelled(boolean isKeyguardOccluded) { + public void onAnimationCancelled() { mKeyguardViewMediator.cancelKeyguardExitAnimation(); } }; diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 93ddfba5b6fc..1a126d72f9e9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -959,20 +959,15 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, @Nullable private ValueAnimator mOccludeByDreamAnimator; @Override - public void onAnimationCancelled(boolean isKeyguardOccluded) { + public void onAnimationCancelled() { mContext.getMainExecutor().execute(() -> { if (mOccludeByDreamAnimator != null) { mOccludeByDreamAnimator.cancel(); } }); - // The value of isKeyguardOccluded here may come from mergeAnimation, which - // isn't reliable. In all cases, after running or cancelling this animation, - // keyguard should be occluded. + + Log.d(TAG, "OccludeByDreamAnimator#onAnimationCancelled. Set occluded = true"); setOccluded(true /* isOccluded */, false /* animate */); - if (DEBUG) { - Log.d(TAG, "Occlude by Dream animation cancelled. Occluded state is now: " - + mOccluded); - } } @Override @@ -984,6 +979,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, // Usually we rely on animation completion to synchronize occluded status, // but there was no animation to play, so just update it now. setOccluded(true /* isOccluded */, false /* animate */); + finishedCallback.onAnimationFinished(); } } @@ -991,11 +987,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException { if (apps == null || apps.length == 0 || apps[0] == null) { - if (DEBUG) { - Log.d(TAG, "No apps provided to the OccludeByDream runner; " - + "skipping occluding animation."); - } - finishedCallback.onAnimationFinished(); + Log.d(TAG, "No apps provided to the OccludeByDream runner; " + + "skipping occluding animation."); return false; } @@ -1005,7 +998,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, if (!isDream) { Log.w(TAG, "The occluding app isn't Dream; " + "finishing up. Please check that the config is correct."); - finishedCallback.onAnimationFinished(); return false; } @@ -1071,17 +1063,14 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, private final Matrix mUnoccludeMatrix = new Matrix(); @Override - public void onAnimationCancelled(boolean isKeyguardOccluded) { + public void onAnimationCancelled() { mContext.getMainExecutor().execute(() -> { if (mUnoccludeAnimator != null) { mUnoccludeAnimator.cancel(); } }); - setOccluded(isKeyguardOccluded /* isOccluded */, false /* animate */); - Log.d(TAG, "Unocclude animation cancelled. Occluded state is now: " - + mOccluded); - + Log.d(TAG, "Unocclude animation cancelled."); mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_OCCLUSION); } @@ -3404,9 +3393,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, } @Override - public void onAnimationCancelled(boolean isKeyguardOccluded) throws RemoteException { + public void onAnimationCancelled() throws RemoteException { if (mRunner != null) { - mRunner.onAnimationCancelled(isKeyguardOccluded); + mRunner.onAnimationCancelled(); } } @@ -3452,13 +3441,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, } @Override - public void onAnimationCancelled(boolean isKeyguardOccluded) throws RemoteException { - super.onAnimationCancelled(isKeyguardOccluded); - - Log.d(TAG, "Occlude animation cancelled by WM. " - + "Setting occluded state to: " + isKeyguardOccluded); - setOccluded(isKeyguardOccluded /* occluded */, false /* animate */); - + public void onAnimationCancelled() throws RemoteException { + super.onAnimationCancelled(); + Log.d(TAG, "Occlude animation cancelled by WM."); mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_OCCLUSION); } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt index 9b94cdbfe8dc..148d4255636c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt @@ -41,17 +41,6 @@ constructor( var receivedDownTouch = false val isVisible: Flow<Boolean> = bouncerRepository.alternateBouncerVisible - private val keyguardStateControllerCallback: KeyguardStateController.Callback = - object : KeyguardStateController.Callback { - override fun onUnlockedChanged() { - maybeHide() - } - } - - init { - keyguardStateController.addCallback(keyguardStateControllerCallback) - } - /** * Sets the correct bouncer states to show the alternate bouncer if it can show. * @@ -102,11 +91,18 @@ constructor( return (systemClock.uptimeMillis() - bouncerRepository.lastAlternateBouncerVisibleTime) > MIN_VISIBILITY_DURATION_UNTIL_TOUCHES_DISMISS_ALTERNATE_BOUNCER_MS } - - private fun maybeHide() { + /** + * Should only be called through StatusBarKeyguardViewManager which propagates the source of + * truth to other concerned controllers. Will hide the alternate bouncer if it's no longer + * allowed to show. + * + * @return true if the alternate bouncer was newly hidden, else false. + */ + fun maybeHide(): Boolean { if (isVisibleState() && !canShowAlternateBouncerForFingerprint()) { - hide() + return hide() } + return false } companion object { diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/DreamLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/DreamLog.kt new file mode 100644 index 000000000000..cb9913abe99b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/DreamLog.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.log.dagger + +import javax.inject.Qualifier + +/** A [com.android.systemui.log.LogBuffer] for dream-related logging. */ +@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class DreamLog diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java index 077ee027d764..658f6a087854 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java @@ -440,4 +440,14 @@ public class LogModule { public static LogBuffer provideKeyguardLogBuffer(LogBufferFactory factory) { return factory.create("KeyguardLog", 250); } + + /** + * Provides a {@link LogBuffer} for dream-related logs. + */ + @Provides + @SysUISingleton + @DreamLog + public static LogBuffer provideDreamLogBuffer(LogBufferFactory factory) { + return factory.create("DreamLog", 250); + } } diff --git a/packages/SystemUI/src/com/android/systemui/log/table/LogProxy.kt b/packages/SystemUI/src/com/android/systemui/log/table/LogProxy.kt new file mode 100644 index 000000000000..53886aabfa72 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/log/table/LogProxy.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.log.table + +import android.util.Log +import javax.inject.Inject + +/** Dagger-friendly interface so we can inject a fake [android.util.Log] in tests */ +interface LogProxy { + /** verbose log */ + fun v(tag: String, message: String) + + /** debug log */ + fun d(tag: String, message: String) + + /** info log */ + fun i(tag: String, message: String) + + /** warning log */ + fun w(tag: String, message: String) + + /** error log */ + fun e(tag: String, message: String) + + /** wtf log */ + fun wtf(tag: String, message: String) +} + +class LogProxyDefault @Inject constructor() : LogProxy { + override fun v(tag: String, message: String) { + Log.v(tag, message) + } + + override fun d(tag: String, message: String) { + Log.d(tag, message) + } + + override fun i(tag: String, message: String) { + Log.i(tag, message) + } + + override fun w(tag: String, message: String) { + Log.w(tag, message) + } + + override fun e(tag: String, message: String) { + Log.e(tag, message) + } + + override fun wtf(tag: String, message: String) { + Log.wtf(tag, message) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt index faaa205b15c2..9d883cc10d6c 100644 --- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt +++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt @@ -19,10 +19,17 @@ package com.android.systemui.log.table import android.os.Trace import com.android.systemui.Dumpable import com.android.systemui.common.buffer.RingBuffer +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.plugins.log.LogLevel +import com.android.systemui.plugins.log.LogcatEchoTracker import com.android.systemui.util.time.SystemClock import java.io.PrintWriter import java.text.SimpleDateFormat import java.util.Locale +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.launch /** * A logger that logs changes in table format. @@ -73,12 +80,18 @@ class TableLogBuffer( maxSize: Int, private val name: String, private val systemClock: SystemClock, + private val logcatEchoTracker: LogcatEchoTracker, + @Background private val bgDispatcher: CoroutineDispatcher, + private val coroutineScope: CoroutineScope, + private val localLogcat: LogProxy = LogProxyDefault(), ) : Dumpable { init { if (maxSize <= 0) { throw IllegalArgumentException("maxSize must be > 0") } } + // For local logcat, send messages across this channel so the background job can process them + private val logMessageChannel = Channel<TableChange>(capacity = 10) private val buffer = RingBuffer(maxSize) { TableChange() } @@ -105,6 +118,16 @@ class TableLogBuffer( tableLogBuffer = this, ) + /** Start this log buffer logging in the background */ + internal fun init() { + coroutineScope.launch(bgDispatcher) { + while (!logMessageChannel.isClosedForReceive) { + val log = logMessageChannel.receive() + echoToDesiredEndpoints(log) + } + } + } + /** * Log the differences between [prevVal] and [newVal]. * @@ -189,6 +212,7 @@ class TableLogBuffer( Trace.beginSection("TableLogBuffer#logChange(string)") val change = obtain(timestamp, prefix, columnName, isInitial) change.set(value) + tryAddMessage(change) Trace.endSection() } @@ -202,6 +226,7 @@ class TableLogBuffer( Trace.beginSection("TableLogBuffer#logChange(boolean)") val change = obtain(timestamp, prefix, columnName, isInitial) change.set(value) + tryAddMessage(change) Trace.endSection() } @@ -215,9 +240,14 @@ class TableLogBuffer( Trace.beginSection("TableLogBuffer#logChange(int)") val change = obtain(timestamp, prefix, columnName, isInitial) change.set(value) + tryAddMessage(change) Trace.endSection() } + private fun tryAddMessage(change: TableChange) { + logMessageChannel.trySend(change) + } + // TODO(b/259454430): Add additional change types here. @Synchronized @@ -258,6 +288,17 @@ class TableLogBuffer( Trace.endSection() } + private fun echoToDesiredEndpoints(change: TableChange) { + if ( + logcatEchoTracker.isBufferLoggable(bufferName = name, LogLevel.DEBUG) || + logcatEchoTracker.isTagLoggable(change.columnName, LogLevel.DEBUG) + ) { + if (change.hasData()) { + localLogcat.d(name, change.logcatRepresentation()) + } + } + } + @Synchronized override fun dump(pw: PrintWriter, args: Array<out String>) { pw.println(HEADER_PREFIX + name) @@ -284,6 +325,12 @@ class TableLogBuffer( pw.println() } + /** Transforms an individual [TableChange] into a String for logcat */ + private fun TableChange.logcatRepresentation(): String { + val formattedTimestamp = TABLE_LOG_DATE_FORMAT.format(timestamp) + return "$formattedTimestamp$SEPARATOR${getName()}$SEPARATOR${getVal()}" + } + /** * A private implementation of [TableRowLogger]. * diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt index 06668d33408d..42e742db2842 100644 --- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt @@ -17,10 +17,15 @@ package com.android.systemui.log.table import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dump.DumpManager import com.android.systemui.log.LogBufferHelper.Companion.adjustMaxSize +import com.android.systemui.plugins.log.LogcatEchoTracker import com.android.systemui.util.time.SystemClock import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope @SysUISingleton class TableLogBufferFactory @@ -28,6 +33,9 @@ class TableLogBufferFactory constructor( private val dumpManager: DumpManager, private val systemClock: SystemClock, + private val logcatEchoTracker: LogcatEchoTracker, + @Background private val bgDispatcher: CoroutineDispatcher, + @Application private val coroutineScope: CoroutineScope, ) { private val existingBuffers = mutableMapOf<String, TableLogBuffer>() @@ -44,8 +52,17 @@ constructor( name: String, maxSize: Int, ): TableLogBuffer { - val tableBuffer = TableLogBuffer(adjustMaxSize(maxSize), name, systemClock) + val tableBuffer = + TableLogBuffer( + adjustMaxSize(maxSize), + name, + systemClock, + logcatEchoTracker, + bgDispatcher, + coroutineScope, + ) dumpManager.registerNormalDumpable(name, tableBuffer) + tableBuffer.init() return tableBuffer } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt index 0860c207ef20..aec7b5f7aa7a 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt @@ -259,7 +259,7 @@ class MediaProjectionAppSelectorActivity( putExtra(Intent.EXTRA_INTENT, queryIntent) // Update the title of the chooser - val title = resources.getString(R.string.media_projection_permission_app_selector_title) + val title = resources.getString(R.string.screen_share_permission_app_selector_title) putExtra(Intent.EXTRA_TITLE, title) // Select host app's profile tab by default diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java index e217e36d1051..28adfbba1103 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java @@ -157,8 +157,8 @@ public class MediaProjectionPermissionActivity extends Activity CharSequence dialogTitle = null; String appName = null; if (Utils.isHeadlessRemoteDisplayProvider(packageManager, mPackageName)) { - dialogText = getString(R.string.media_projection_dialog_service_text); - dialogTitle = getString(R.string.media_projection_dialog_service_title); + dialogText = getString(R.string.media_projection_sys_service_dialog_warning); + dialogTitle = getString(R.string.media_projection_sys_service_dialog_title); } else { String label = aInfo.loadLabel(packageManager).toString(); @@ -188,7 +188,7 @@ public class MediaProjectionPermissionActivity extends Activity paint, MAX_APP_NAME_SIZE_PX, TextUtils.TruncateAt.END).toString(); appName = BidiFormatter.getInstance().unicodeWrap(unsanitizedAppName); - String actionText = getString(R.string.media_projection_dialog_text, appName); + String actionText = getString(R.string.media_projection_dialog_warning, appName); SpannableString message = new SpannableString(actionText); int appNameIndex = actionText.indexOf(appName); diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java index 2a8168b0cb36..05e04a11d7ba 100644 --- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java +++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java @@ -88,18 +88,9 @@ public class RingtonePlayer implements CoreStartable { private final IBinder mToken; private final Ringtone mRingtone; - public Client(IBinder token, Uri uri, UserHandle user, AudioAttributes aa) { - this(token, uri, user, aa, null); - } - - Client(IBinder token, Uri uri, UserHandle user, AudioAttributes aa, - @Nullable VolumeShaper.Configuration volumeShaperConfig) { + Client(IBinder token, Ringtone ringtone) { mToken = token; - - mRingtone = new Ringtone(getContextForUser(user), false); - mRingtone.setAudioAttributesField(aa); - mRingtone.setUri(uri, volumeShaperConfig); - mRingtone.createLocalMediaPlayer(); + mRingtone = ringtone; } @Override @@ -129,11 +120,28 @@ public class RingtonePlayer implements CoreStartable { Client client; synchronized (mClients) { client = mClients.get(token); - if (client == null) { - final UserHandle user = Binder.getCallingUserHandle(); - client = new Client(token, uri, user, aa, volumeShaperConfig); - token.linkToDeath(client, 0); - mClients.put(token, client); + } + // Don't hold the lock while constructing the ringtone, since it can be slow. The caller + // shouldn't call play on the same ringtone from 2 threads, so this shouldn't race and + // waste the build. + if (client == null) { + final UserHandle user = Binder.getCallingUserHandle(); + Ringtone ringtone = new Ringtone(getContextForUser(user), false); + ringtone.setAudioAttributesField(aa); + ringtone.setUri(uri, volumeShaperConfig); + ringtone.createLocalMediaPlayer(); + synchronized (mClients) { + client = mClients.get(token); + if (client == null) { + client = new Client(token, ringtone); + token.linkToDeath(client, 0); + mClients.put(token, client); + ringtone = null; // "owned" by the client now. + } + } + // Clean up ringtone if it was abandoned (a client already existed). + if (ringtone != null) { + ringtone.stop(); } } client.mRingtone.setLooping(looping); diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt index 120704c0582a..3fc3ad682bc7 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt @@ -154,6 +154,7 @@ constructor( get() = controller?.sessionToken private var started = false private var playbackType = PLAYBACK_TYPE_UNKNOWN + private var playbackVolumeControlId: String? = null private var current: MediaDeviceData? = null set(value) { val sameWithoutIcon = value != null && value.equalsWithoutIcon(field) @@ -181,6 +182,7 @@ constructor( localMediaManager.startScan() muteAwaitConnectionManager?.startListening() playbackType = controller?.playbackInfo?.playbackType ?: PLAYBACK_TYPE_UNKNOWN + playbackVolumeControlId = controller?.playbackInfo?.volumeControlId controller?.registerCallback(this) updateCurrent() started = true @@ -209,6 +211,8 @@ constructor( println(" current device is ${current?.name}") val type = controller?.playbackInfo?.playbackType println(" PlaybackType=$type (1 for local, 2 for remote) cached=$playbackType") + val volumeControlId = controller?.playbackInfo?.volumeControlId + println(" volumeControlId=$volumeControlId cached= $playbackVolumeControlId") println(" routingSession=$routingSession") println(" selectedRoutes=$selectedRoutes") } @@ -217,10 +221,15 @@ constructor( @WorkerThread override fun onAudioInfoChanged(info: MediaController.PlaybackInfo?) { val newPlaybackType = info?.playbackType ?: PLAYBACK_TYPE_UNKNOWN - if (newPlaybackType == playbackType) { + val newPlaybackVolumeControlId = info?.volumeControlId + if ( + newPlaybackType == playbackType && + newPlaybackVolumeControlId == playbackVolumeControlId + ) { return } playbackType = newPlaybackType + playbackVolumeControlId = newPlaybackVolumeControlId updateCurrent() } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt index 0aa434976ce7..1e9a466ccdce 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt @@ -67,6 +67,7 @@ import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.time.SystemClock import com.android.systemui.util.traceSection import java.io.PrintWriter +import java.util.Locale import java.util.TreeMap import javax.inject.Inject import javax.inject.Provider @@ -166,6 +167,8 @@ constructor( } } + private var carouselLocale: Locale? = null + /** Whether the media card currently has the "expanded" layout */ @VisibleForTesting var currentlyExpanded = true @@ -218,6 +221,15 @@ constructor( updatePlayers(recreateMedia = false) inflateSettingsButton() } + + override fun onLocaleListChanged() { + // Update players only if system primary language changes. + if (carouselLocale != context.resources.configuration.locales.get(0)) { + carouselLocale = context.resources.configuration.locales.get(0) + updatePlayers(recreateMedia = true) + inflateSettingsButton() + } + } } private val keyguardUpdateMonitorCallback = @@ -262,6 +274,7 @@ constructor( this::logSmartspaceImpression, logger ) + carouselLocale = context.resources.configuration.locales.get(0) isRtl = context.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL inflateSettingsButton() mediaContent = mediaCarousel.requireViewById(R.id.media_carousel) diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java index 9ebc8e410013..8e014c61c641 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java @@ -126,10 +126,11 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, private final LocalBluetoothManager mLocalBluetoothManager; private final ActivityStarter mActivityStarter; private final DialogLaunchAnimator mDialogLaunchAnimator; - private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>(); private final CommonNotifCollection mNotifCollection; private final Object mMediaDevicesLock = new Object(); @VisibleForTesting + final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>(); + @VisibleForTesting final List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>(); final List<MediaDevice> mCachedMediaDevices = new CopyOnWriteArrayList<>(); private final List<MediaItem> mMediaItemList = new CopyOnWriteArrayList<>(); @@ -713,7 +714,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, dividerItems.forEach((key, item) -> { finalMediaItems.add(key, item); }); - finalMediaItems.add(new MediaItem()); + attachConnectNewDeviceItemIfNeeded(finalMediaItems); mMediaItemList.clear(); mMediaItemList.addAll(finalMediaItems); } @@ -749,7 +750,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, finalMediaItems.add(new MediaItem(device)); } } - finalMediaItems.add(new MediaItem()); + attachConnectNewDeviceItemIfNeeded(finalMediaItems); mMediaItemList.clear(); mMediaItemList.addAll(finalMediaItems); } @@ -760,6 +761,13 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, new MediaItem(title, MediaItem.MediaItemType.TYPE_GROUP_DIVIDER)); } + private void attachConnectNewDeviceItemIfNeeded(List<MediaItem> mediaItems) { + // Attach "Connect a device" item only when current output is not remote and not a group + if (!isCurrentConnectedDeviceRemote() && getSelectedMediaDevice().size() == 1) { + mediaItems.add(new MediaItem()); + } + } + private void attachRangeInfo(List<MediaDevice> devices) { for (MediaDevice mediaDevice : devices) { if (mNearbyDeviceInfoMap.containsKey(mediaDevice.getId())) { @@ -1251,7 +1259,8 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, return null; } - private final MediaController.Callback mCb = new MediaController.Callback() { + @VisibleForTesting + final MediaController.Callback mCb = new MediaController.Callback() { @Override public void onMetadataChanged(MediaMetadata metadata) { mCallback.onMediaChanged(); diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt index 8aec0c61c75c..d4052f54b3da 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt @@ -42,7 +42,6 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.devicepolicy.areKeyguardShortcutsDisabled import com.android.systemui.notetask.NoteTaskRoleManagerExt.createNoteShortcutInfoAsUser import com.android.systemui.notetask.NoteTaskRoleManagerExt.getDefaultRoleHolderAsUser -import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity import com.android.systemui.notetask.shortcut.LaunchNoteTaskManagedProfileProxyActivity import com.android.systemui.settings.UserTracker import com.android.systemui.shared.system.ActivityManagerKt.isInForeground @@ -231,8 +230,6 @@ constructor( * Widget Picker to all users. */ fun setNoteTaskShortcutEnabled(value: Boolean, user: UserHandle) { - val componentName = ComponentName(context, CreateNoteTaskShortcutActivity::class.java) - val enabledState = if (value) { PackageManager.COMPONENT_ENABLED_STATE_ENABLED @@ -249,8 +246,9 @@ constructor( } else { context.createContextAsUser(user, /* flags= */ 0) } + userContext.packageManager.setComponentEnabledSetting( - componentName, + SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT, enabledState, PackageManager.DONT_KILL_APP, ) @@ -298,6 +296,19 @@ constructor( companion object { val TAG = NoteTaskController::class.simpleName.orEmpty() + /** + * IMPORTANT! The shortcut package name and class should be synchronized with Settings: + * [com.android.settings.notetask.shortcut.CreateNoteTaskShortcutActivity]. + * + * Changing the package name or class is a breaking change. + */ + @VisibleForTesting + val SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT = + ComponentName( + "com.android.settings", + "com.android.settings.notetask.shortcut.CreateNoteTaskShortcutActivity", + ) + const val SHORTCUT_ID = "note_task_shortcut_id" /** diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt index a166393ec29c..2c62ffd4841f 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt @@ -24,7 +24,6 @@ import android.app.role.RoleManager import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.notetask.quickaffordance.NoteTaskQuickAffordanceModule -import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity import com.android.systemui.notetask.shortcut.LaunchNoteTaskActivity import com.android.systemui.notetask.shortcut.LaunchNoteTaskManagedProfileProxyActivity import dagger.Binds @@ -46,9 +45,6 @@ interface NoteTaskModule { @[Binds IntoMap ClassKey(LaunchNoteTaskManagedProfileProxyActivity::class)] fun LaunchNoteTaskManagedProfileProxyActivity.bindNoteTaskLauncherProxyActivity(): Activity - @[Binds IntoMap ClassKey(CreateNoteTaskShortcutActivity::class)] - fun CreateNoteTaskShortcutActivity.bindNoteTaskShortcutActivity(): Activity - companion object { @[Provides NoteTaskEnabledKey] diff --git a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt deleted file mode 100644 index 0cfb0a521820..000000000000 --- a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@file:OptIn(InternalNoteTaskApi::class) - -package com.android.systemui.notetask.shortcut - -import android.app.Activity -import android.app.role.RoleManager -import android.content.pm.ShortcutManager -import android.os.Bundle -import androidx.activity.ComponentActivity -import com.android.systemui.notetask.InternalNoteTaskApi -import com.android.systemui.notetask.NoteTaskRoleManagerExt.createNoteShortcutInfoAsUser -import javax.inject.Inject - -/** - * Activity responsible for create a shortcut for notes action. If the shortcut is enabled, a new - * shortcut will appear in the widget picker. If the shortcut is selected, the Activity here will be - * launched, creating a new shortcut for [CreateNoteTaskShortcutActivity], and will finish. - * - * @see <a - * href="https://developer.android.com/develop/ui/views/launch/shortcuts/creating-shortcuts#custom-pinned">Creating - * a custom shortcut activity</a> - */ -class CreateNoteTaskShortcutActivity -@Inject -constructor( - private val roleManager: RoleManager, - private val shortcutManager: ShortcutManager, -) : ComponentActivity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - val shortcutInfo = roleManager.createNoteShortcutInfoAsUser(context = this, user) - val shortcutIntent = shortcutManager.createShortcutResultIntent(shortcutInfo) - setResult(Activity.RESULT_OK, shortcutIntent) - - finish() - } -} diff --git a/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt b/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt index 6f645b562008..995c6a476f0d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt @@ -26,7 +26,9 @@ import java.util.concurrent.Executor import javax.inject.Inject import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.shade.ShadeModule.Companion.SHADE_HEADER import com.android.systemui.statusbar.policy.DeviceProvisionedController +import javax.inject.Named interface ChipVisibilityListener { fun onChipVisibilityRefreshed(visible: Boolean) @@ -45,10 +47,10 @@ interface ChipVisibilityListener { class HeaderPrivacyIconsController @Inject constructor( private val privacyItemController: PrivacyItemController, private val uiEventLogger: UiEventLogger, - private val privacyChip: OngoingPrivacyChip, + @Named(SHADE_HEADER) private val privacyChip: OngoingPrivacyChip, private val privacyDialogController: PrivacyDialogController, private val privacyLogger: PrivacyLogger, - private val iconContainer: StatusIconContainer, + @Named(SHADE_HEADER) private val iconContainer: StatusIconContainer, private val permissionManager: PermissionManager, @Background private val backgroundExecutor: Executor, @Main private val uiExecutor: Executor, diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt index 201557c03e48..f4f5f66dfb09 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt @@ -28,12 +28,14 @@ class MediaProjectionPermissionDialog( ) : BaseScreenSharePermissionDialog(context, createOptionList(appName), appName) { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + // TODO(b/270018943): Handle the case of System sharing (not recording nor casting) if (appName == null) { - setDialogTitle(R.string.media_projection_permission_dialog_system_service_title) + setDialogTitle(R.string.media_projection_entry_cast_permission_dialog_title) + setStartButtonText(R.string.media_projection_entry_cast_permission_dialog_continue) } else { - setDialogTitle(R.string.media_projection_permission_dialog_title) + setDialogTitle(R.string.media_projection_entry_app_permission_dialog_title) + setStartButtonText(R.string.media_projection_entry_app_permission_dialog_continue) } - setStartButtonText(R.string.media_projection_permission_dialog_continue) setStartButtonOnClickListener { // Note that it is important to run this callback before dismissing, so that the // callback can disable the dialog exit animation if it wants to. @@ -50,26 +52,26 @@ class MediaProjectionPermissionDialog( private fun createOptionList(appName: String?): List<ScreenShareOption> { val singleAppWarningText = if (appName == null) { - R.string.media_projection_permission_dialog_system_service_warning_single_app + R.string.media_projection_entry_cast_permission_dialog_warning_single_app } else { - R.string.media_projection_permission_dialog_warning_single_app + R.string.media_projection_entry_app_permission_dialog_warning_single_app } val entireScreenWarningText = if (appName == null) { - R.string.media_projection_permission_dialog_system_service_warning_entire_screen + R.string.media_projection_entry_cast_permission_dialog_warning_entire_screen } else { - R.string.media_projection_permission_dialog_warning_entire_screen + R.string.media_projection_entry_app_permission_dialog_warning_entire_screen } return listOf( ScreenShareOption( mode = ENTIRE_SCREEN, - spinnerText = R.string.media_projection_permission_dialog_option_entire_screen, + spinnerText = R.string.screen_share_permission_dialog_option_entire_screen, warningText = entireScreenWarningText ), ScreenShareOption( mode = SINGLE_APP, - spinnerText = R.string.media_projection_permission_dialog_option_single_app, + spinnerText = R.string.screen_share_permission_dialog_option_single_app, warningText = singleAppWarningText ) ) diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java index 4349bd71f670..69008cca6fe3 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java @@ -262,7 +262,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList Resources res = getResources(); NotificationChannel channel = new NotificationChannel( CHANNEL_ID, - getString(R.string.screenrecord_name), + getString(R.string.screenrecord_title), NotificationManager.IMPORTANCE_DEFAULT); channel.setDescription(getString(R.string.screenrecord_channel_description)); channel.enableVibration(true); @@ -270,7 +270,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList Bundle extras = new Bundle(); extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, - res.getString(R.string.screenrecord_name)); + res.getString(R.string.screenrecord_title)); String notificationTitle = res.getString(R.string.screenrecord_start_error); Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID) @@ -290,7 +290,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList Resources res = getResources(); NotificationChannel channel = new NotificationChannel( CHANNEL_ID, - getString(R.string.screenrecord_name), + getString(R.string.screenrecord_title), NotificationManager.IMPORTANCE_DEFAULT); channel.setDescription(getString(R.string.screenrecord_channel_description)); channel.enableVibration(true); @@ -298,7 +298,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList Bundle extras = new Bundle(); extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, - res.getString(R.string.screenrecord_name)); + res.getString(R.string.screenrecord_title)); String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE ? res.getString(R.string.screenrecord_ongoing_screen_only) @@ -335,7 +335,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList Bundle extras = new Bundle(); extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, - res.getString(R.string.screenrecord_name)); + res.getString(R.string.screenrecord_title)); Notification.Builder builder = new Notification.Builder(getApplicationContext(), CHANNEL_ID) .setContentTitle(notificationTitle) @@ -365,7 +365,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList Bundle extras = new Bundle(); extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, - getResources().getString(R.string.screenrecord_name)); + getResources().getString(R.string.screenrecord_title)); Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.ic_screenrecord) diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java index efa45a4c4723..2a21aaa81404 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java @@ -100,7 +100,7 @@ public class ScreenRecordDialog extends SystemUIDialog { window.addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS); window.setGravity(Gravity.CENTER); - setTitle(R.string.screenrecord_name); + setTitle(R.string.screenrecord_title); setContentView(R.layout.screen_record_dialog); diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt index 30509e23d186..bfaf3d0d2ec5 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt @@ -62,8 +62,8 @@ class ScreenRecordPermissionDialog( private lateinit var options: Spinner override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setDialogTitle(R.string.screenrecord_start_label) - setStartButtonText(R.string.screenrecord_start_recording) + setDialogTitle(R.string.screenrecord_permission_dialog_title) + setStartButtonText(R.string.screenrecord_permission_dialog_continue) setStartButtonOnClickListener { v: View? -> onStartRecordingClicked?.run() if (selectedScreenShareOption.mode == ENTIRE_SCREEN) { @@ -186,13 +186,13 @@ class ScreenRecordPermissionDialog( return listOf( ScreenShareOption( ENTIRE_SCREEN, - R.string.screenrecord_option_entire_screen, - R.string.screenrecord_warning_entire_screen + R.string.screen_share_permission_dialog_option_entire_screen, + R.string.screenrecord_permission_dialog_warning_entire_screen ), ScreenShareOption( SINGLE_APP, - R.string.screenrecord_option_single_app, - R.string.screenrecord_warning_single_app + R.string.screen_share_permission_dialog_option_single_app, + R.string.screenrecord_permission_dialog_warning_single_app ) ) } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt index aa8e2c039684..187019a4851d 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt @@ -154,5 +154,5 @@ private val SCREENSHOT_REMOTE_RUNNER: IRemoteAnimationRunner.Stub = } } - override fun onAnimationCancelled(isKeyguardOccluded: Boolean) {} + override fun onAnimationCancelled() {} } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index c9d1da38b196..77a65b22a7f4 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -150,7 +150,7 @@ public class ScreenshotController { } @Override - public void onAnimationCancelled(boolean isKeyguardOccluded) { + public void onAnimationCancelled() { } }; diff --git a/packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt index b3d31f2986d1..7e0f50400299 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt @@ -19,12 +19,12 @@ package com.android.systemui.shade import android.view.ViewGroup import androidx.constraintlayout.widget.ConstraintSet import com.android.systemui.R -import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent +import com.android.systemui.dagger.SysUISingleton /** * Standard implementation of [CombinedShadeHeadersConstraintManager]. */ -@CentralSurfacesComponent.CentralSurfacesScope +@SysUISingleton object CombinedShadeHeadersConstraintManagerImpl : CombinedShadeHeadersConstraintManager { override fun privacyChipVisibilityConstraints(visible: Boolean): ConstraintsChanges { diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java index ef14d1cb7f63..4012736b8beb 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java @@ -70,6 +70,7 @@ import com.android.systemui.media.controls.ui.MediaHierarchyManager; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QS; import com.android.systemui.screenrecord.RecordingController; +import com.android.systemui.shade.data.repository.ShadeRepository; import com.android.systemui.shade.transition.ShadeTransitionController; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.LockscreenShadeTransitionController; @@ -136,6 +137,7 @@ public class QuickSettingsController { private final KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor; private final FeatureFlags mFeatureFlags; private final InteractionJankMonitor mInteractionJankMonitor; + private final ShadeRepository mShadeRepository; private final FalsingManager mFalsingManager; private final AccessibilityManager mAccessibilityManager; private final MetricsLogger mMetricsLogger; @@ -321,7 +323,8 @@ public class QuickSettingsController { FeatureFlags featureFlags, InteractionJankMonitor interactionJankMonitor, ShadeLogger shadeLog, - KeyguardFaceAuthInteractor keyguardFaceAuthInteractor + KeyguardFaceAuthInteractor keyguardFaceAuthInteractor, + ShadeRepository shadeRepository ) { mPanelViewControllerLazy = panelViewControllerLazy; mPanelView = panelView; @@ -363,6 +366,7 @@ public class QuickSettingsController { mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor; mFeatureFlags = featureFlags; mInteractionJankMonitor = interactionJankMonitor; + mShadeRepository = shadeRepository; mLockscreenShadeTransitionController.addCallback(new LockscreenShadeTransitionCallback()); } @@ -1001,6 +1005,7 @@ public class QuickSettingsController { mDepthController.setQsPanelExpansion(qsExpansionFraction); mStatusBarKeyguardViewManager.setQsExpansion(qsExpansionFraction); + mShadeRepository.setQsExpansion(qsExpansionFraction); // TODO (b/265193930): remove dependency on NPVC float shadeExpandedFraction = mBarState == KEYGUARD diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt index f0815e93dccd..86ae4ecf6e70 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt @@ -41,6 +41,7 @@ import com.android.systemui.animation.Interpolators import com.android.systemui.animation.ShadeInterpolation import com.android.systemui.battery.BatteryMeterView import com.android.systemui.battery.BatteryMeterViewController +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.demomode.DemoMode import com.android.systemui.demomode.DemoModeController import com.android.systemui.dump.DumpManager @@ -52,14 +53,13 @@ import com.android.systemui.shade.ShadeHeaderController.Companion.LARGE_SCREEN_H import com.android.systemui.shade.ShadeHeaderController.Companion.LARGE_SCREEN_HEADER_TRANSITION_ID import com.android.systemui.shade.ShadeHeaderController.Companion.QQS_HEADER_CONSTRAINT import com.android.systemui.shade.ShadeHeaderController.Companion.QS_HEADER_CONSTRAINT +import com.android.systemui.shade.ShadeModule.Companion.SHADE_HEADER import com.android.systemui.shade.carrier.ShadeCarrierGroup import com.android.systemui.shade.carrier.ShadeCarrierGroupController import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider import com.android.systemui.statusbar.phone.StatusBarIconController import com.android.systemui.statusbar.phone.StatusBarLocation import com.android.systemui.statusbar.phone.StatusIconContainer -import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope -import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.SHADE_HEADER import com.android.systemui.statusbar.policy.Clock import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.NextAlarmController @@ -79,7 +79,7 @@ import javax.inject.Named * * [LARGE_SCREEN_HEADER_TRANSITION_ID]: [LARGE_SCREEN_HEADER_CONSTRAINT] for all other * configurations */ -@CentralSurfacesScope +@SysUISingleton class ShadeHeaderController @Inject constructor( diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt index 9cd8c547d1c1..b7551cf3408e 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt @@ -16,21 +16,36 @@ package com.android.systemui.shade +import android.content.ContentResolver +import android.os.Handler import android.view.LayoutInflater +import android.view.ViewStub +import androidx.constraintlayout.motion.widget.MotionLayout import com.android.keyguard.LockIconView import com.android.systemui.CoreStartable import com.android.systemui.R +import com.android.systemui.battery.BatteryMeterView +import com.android.systemui.battery.BatteryMeterViewController import com.android.systemui.biometrics.AuthRippleController import com.android.systemui.biometrics.AuthRippleView import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.privacy.OngoingPrivacyChip +import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout +import com.android.systemui.statusbar.phone.StatusIconContainer import com.android.systemui.statusbar.phone.TapAgainView +import com.android.systemui.statusbar.policy.BatteryController +import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.tuner.TunerService import dagger.Binds import dagger.Module import dagger.Provides import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap +import javax.inject.Named /** Module for classes related to the notification shade. */ @Module @@ -42,6 +57,8 @@ abstract class ShadeModule { abstract fun bindAuthRippleController(controller: AuthRippleController): CoreStartable companion object { + const val SHADE_HEADER = "large_screen_shade_header" + @Provides @SysUISingleton // TODO(b/277762009): Do something similar to @@ -109,5 +126,75 @@ abstract class ShadeModule { ): TapAgainView { return notificationPanelView.findViewById(R.id.shade_falsing_tap_again) } + + // TODO(b/277762009): Only allow this view's controller to inject the view. See above. + @Provides + @SysUISingleton + @Named(SHADE_HEADER) + fun providesShadeHeaderView( + notificationShadeWindowView: NotificationShadeWindowView, + ): MotionLayout { + val stub = notificationShadeWindowView.findViewById<ViewStub>(R.id.qs_header_stub) + val layoutId = R.layout.combined_qs_header + stub.layoutResource = layoutId + return stub.inflate() as MotionLayout + } + + @Provides + @SysUISingleton + fun providesCombinedShadeHeadersConstraintManager(): CombinedShadeHeadersConstraintManager { + return CombinedShadeHeadersConstraintManagerImpl + } + + // TODO(b/277762009): Only allow this view's controller to inject the view. See above. + @Provides + @SysUISingleton + @Named(SHADE_HEADER) + fun providesBatteryMeterView(@Named(SHADE_HEADER) view: MotionLayout): BatteryMeterView { + return view.findViewById(R.id.batteryRemainingIcon) + } + + @Provides + @SysUISingleton + @Named(SHADE_HEADER) + fun providesBatteryMeterViewController( + @Named(SHADE_HEADER) batteryMeterView: BatteryMeterView, + userTracker: UserTracker, + configurationController: ConfigurationController, + tunerService: TunerService, + @Main mainHandler: Handler, + contentResolver: ContentResolver, + featureFlags: FeatureFlags, + batteryController: BatteryController, + ): BatteryMeterViewController { + return BatteryMeterViewController( + batteryMeterView, + userTracker, + configurationController, + tunerService, + mainHandler, + contentResolver, + featureFlags, + batteryController, + ) + } + + @Provides + @SysUISingleton + @Named(SHADE_HEADER) + fun providesOngoingPrivacyChip( + @Named(SHADE_HEADER) header: MotionLayout, + ): OngoingPrivacyChip { + return header.findViewById(R.id.privacy_chip) + } + + @Provides + @SysUISingleton + @Named(SHADE_HEADER) + fun providesStatusIconContainer( + @Named(SHADE_HEADER) header: MotionLayout, + ): StatusIconContainer { + return header.findViewById(R.id.statusIcons) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt index bf7a2be2e4ca..44c8e48c65d4 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt @@ -25,11 +25,23 @@ import com.android.systemui.shade.domain.model.ShadeModel import javax.inject.Inject import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.distinctUntilChanged interface ShadeRepository { /** ShadeModel information regarding shade expansion events */ val shadeModel: Flow<ShadeModel> + + /** Amount qs has expanded. Quick Settings can be expanded without the full shade expansion. */ + val qsExpansion: StateFlow<Float> + + /** Amount shade has expanded with regard to the UDFPS location */ + val udfpsTransitionToFullShadeProgress: StateFlow<Float> + + fun setQsExpansion(qsExpansion: Float) + fun setUdfpsTransitionToFullShadeProgress(progress: Float) } /** Business logic for shade interactions */ @@ -62,6 +74,20 @@ constructor(shadeExpansionStateManager: ShadeExpansionStateManager) : ShadeRepos } .distinctUntilChanged() + private val _qsExpansion = MutableStateFlow(0f) + override val qsExpansion: StateFlow<Float> = _qsExpansion.asStateFlow() + + private var _udfpsTransitionToFullShadeProgress = MutableStateFlow(0f) + override val udfpsTransitionToFullShadeProgress: StateFlow<Float> = + _udfpsTransitionToFullShadeProgress.asStateFlow() + override fun setQsExpansion(qsExpansion: Float) { + _qsExpansion.value = qsExpansion + } + + override fun setUdfpsTransitionToFullShadeProgress(progress: Float) { + _udfpsTransitionToFullShadeProgress.value = progress + } + companion object { private const val TAG = "ShadeRepository" } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java index 4ef20633ac21..505f45d021b8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java @@ -52,7 +52,7 @@ public class LegacyNotificationShelfControllerImpl implements NotificationShelfC mActivatableNotificationViewController = activatableNotificationViewController; mKeyguardBypassController = keyguardBypassController; mStatusBarStateController = statusBarStateController; - mView.useRoundnessSourceTypes(featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES)); + mView.useRoundnessSourceTypes(true); mView.setSensitiveRevealAnimEndabled(featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM)); mOnAttachStateChangeListener = new View.OnAttachStateChangeListener() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt index c5f64b0a2306..7f016f304e05 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt @@ -32,6 +32,7 @@ import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.qs.QS import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.shade.ShadeViewController +import com.android.systemui.shade.data.repository.ShadeRepository import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableView @@ -74,6 +75,7 @@ class LockscreenShadeTransitionController @Inject constructor( falsingManager: FalsingManager, dumpManager: DumpManager, qsTransitionControllerFactory: LockscreenShadeQsTransitionController.Factory, + private val shadeRepository: ShadeRepository, ) : Dumpable { private var pulseHeight: Float = 0f @get:VisibleForTesting @@ -449,6 +451,7 @@ class LockscreenShadeTransitionController @Inject constructor( } val udfpsProgress = MathUtils.saturate(dragDownAmount / udfpsTransitionDistance) + shadeRepository.setUdfpsTransitionToFullShadeProgress(udfpsProgress) udfpsKeyguardViewController?.setTransitionToFullShadeProgress(udfpsProgress) val statusBarProgress = MathUtils.saturate(dragDownAmount / statusBarTransitionDistance) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java index 9bf05cb47f04..19c612ed21ff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java @@ -261,8 +261,7 @@ public class ExpandableNotificationRowController implements NotifViewController mStatusBarStateController.removeCallback(mStatusBarStateListener); } }); - mView.useRoundnessSourceTypes( - mFeatureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES)); + mView.useRoundnessSourceTypes(true); } private final StatusBarStateController.StateListener mStatusBarStateListener = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt index 99c6ddb8cfaa..81067157ca5b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt @@ -81,7 +81,7 @@ object NotificationShelfViewBinder { ActivatableNotificationViewBinder.bind(viewModel, shelf, falsingManager) shelf.apply { setRefactorFlagEnabled(true) - useRoundnessSourceTypes(featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES)) + useRoundnessSourceTypes(true) setSensitiveRevealAnimEndabled(featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM)) // TODO(278765923): Replace with eventual NotificationIconContainerViewBinder#bind() notificationIconAreaController.setShelfIcons(shelfIcons) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java index fde8c4d453ce..b6aec83ae600 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java @@ -25,8 +25,6 @@ import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dump.DumpManager; -import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.flags.Flags; import com.android.systemui.statusbar.notification.LegacySourceType; import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; import com.android.systemui.statusbar.notification.Roundable; @@ -73,8 +71,7 @@ public class NotificationRoundnessManager implements Dumpable { NotificationRoundnessManager( NotificationSectionsFeatureManager sectionsFeatureManager, NotificationRoundnessLogger notifLogger, - DumpManager dumpManager, - FeatureFlags featureFlags) { + DumpManager dumpManager) { int numberOfSections = sectionsFeatureManager.getNumberOfBuckets(); mFirstInSectionViews = new ExpandableView[numberOfSections]; mLastInSectionViews = new ExpandableView[numberOfSections]; @@ -82,7 +79,7 @@ public class NotificationRoundnessManager implements Dumpable { mTmpLastInSectionViews = new ExpandableView[numberOfSections]; mNotifLogger = notifLogger; mDumpManager = dumpManager; - mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES); + mUseRoundnessSourceTypes = true; mDumpManager.registerDumpable(TAG, this); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt index 070b4394291f..57b6dbce5398 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt @@ -19,8 +19,6 @@ import android.annotation.ColorInt import android.util.Log import android.view.View import com.android.internal.annotations.VisibleForTesting -import com.android.systemui.flags.FeatureFlags -import com.android.systemui.flags.Flags import com.android.systemui.media.controls.ui.KeyguardMediaController import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager import com.android.systemui.statusbar.notification.SourceType @@ -51,11 +49,10 @@ class NotificationSectionsManager @Inject internal constructor( @IncomingHeader private val incomingHeaderController: SectionHeaderController, @PeopleHeader private val peopleHeaderController: SectionHeaderController, @AlertingHeader private val alertingHeaderController: SectionHeaderController, - @SilentHeader private val silentHeaderController: SectionHeaderController, - featureFlags: FeatureFlags + @SilentHeader private val silentHeaderController: SectionHeaderController ) : SectionProvider { - private val useRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES) + private val useRoundnessSourceTypes = true private val configurationListener = object : ConfigurationController.ConfigurationListener { override fun onLocaleListChanged() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 3bc2066d4410..abcb825c3e18 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -625,7 +625,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mDebugLines = featureFlags.isEnabled(Flags.NSSL_DEBUG_LINES); mDebugRemoveAnimation = featureFlags.isEnabled(Flags.NSSL_DEBUG_REMOVE_ANIMATION); mSimplifiedAppearFraction = featureFlags.isEnabled(Flags.SIMPLIFIED_APPEAR_FRACTION); - mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES); + mUseRoundnessSourceTypes = true; mSensitiveRevealAnimEndabled = featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM); setAnimatedInsetsEnabled(featureFlags.isEnabled(Flags.ANIMATED_NOTIFICATION_SHADE_INSETS)); mSectionsManager = Dependency.get(NotificationSectionsManager.class); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 4751fb68697b..d96a2cd4f760 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -61,7 +61,6 @@ import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.flags.Flags; import com.android.systemui.media.controls.ui.KeyguardMediaController; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.FalsingManager; @@ -126,8 +125,6 @@ import com.android.systemui.tuner.TunerService; import com.android.systemui.util.Compile; import com.android.systemui.util.settings.SecureSettings; -import kotlin.Unit; - import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -723,7 +720,7 @@ public class NotificationStackScrollLayoutController { mShadeController = shadeController; mNotifIconAreaController = notifIconAreaController; mFeatureFlags = featureFlags; - mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES); + mUseRoundnessSourceTypes = true; mNotificationTargetsHelper = notificationTargetsHelper; mSecureSettings = secureSettings; mDismissibilityProvider = dismissibilityProvider; @@ -822,7 +819,7 @@ public class NotificationStackScrollLayoutController { mView.generateRemoveAnimation(mKeyguardMediaController.getSinglePaneContainer()); } mView.requestChildrenUpdate(); - return Unit.INSTANCE; + return kotlin.Unit.INSTANCE; }); // attach callback, and then call it to update mView immediately diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java index 91f53b630c73..2d0a6cf8e5a7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java @@ -35,7 +35,6 @@ import com.android.internal.jank.InteractionJankMonitor; import com.android.systemui.SwipeHelper; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.flags.Flags; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; @@ -81,7 +80,7 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc NotificationRoundnessManager notificationRoundnessManager) { super(callback, resources, viewConfiguration, falsingManager, featureFlags); mNotificationRoundnessManager = notificationRoundnessManager; - mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES); + mUseRoundnessSourceTypes = true; mMenuListener = menuListener; mCallback = callback; mFalsingCheck = () -> resetExposedMenuView(true /* animate */, true /* force */); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt index 8b6d6a4f3170..cd0c1b153816 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt @@ -20,7 +20,7 @@ class NotificationTargetsHelper constructor( featureFlags: FeatureFlags, ) { - private val useRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES) + private val useRoundnessSourceTypes = true /** * This method looks for views that can be rounded (and implement [Roundable]) during a diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java index e705afc21c40..0c4821c003dd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java @@ -27,8 +27,6 @@ import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.widget.ViewClippingUtil; import com.android.systemui.R; -import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.flags.Flags; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shade.ShadeHeadsUpTracker; @@ -120,14 +118,13 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar NotificationStackScrollLayoutController stackScrollerController, ShadeViewController shadeViewController, NotificationRoundnessManager notificationRoundnessManager, - FeatureFlags featureFlags, HeadsUpStatusBarView headsUpStatusBarView, Clock clockView, @Named(OPERATOR_NAME_FRAME_VIEW) Optional<View> operatorNameViewOptional) { super(headsUpStatusBarView); mNotificationIconAreaController = notificationIconAreaController; mNotificationRoundnessManager = notificationRoundnessManager; - mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES); + mUseRoundnessSourceTypes = true; mHeadsUpManager = headsUpManager; // We may be mid-HUN-expansion when this controller is re-created (for example, if the user diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt index c17366ad242c..74ab47ff27a1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt @@ -115,7 +115,9 @@ class KeyguardLiftController @Inject constructor( val onKeyguard = keyguardUpdateMonitor.isKeyguardVisible && !statusBarStateController.isDozing - val shouldListen = (onKeyguard || bouncerVisible) && keyguardUpdateMonitor.isFaceEnrolled + val userId = KeyguardUpdateMonitor.getCurrentUser() + val isFaceEnabled = keyguardUpdateMonitor.isFaceAuthEnabledForUser(userId) + val shouldListen = (onKeyguard || bouncerVisible) && isFaceEnabled if (shouldListen != isListening) { isListening = shouldListen diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 89dddbf1f573..f2fbd7d52ac3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -136,7 +136,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private final DreamOverlayStateController mDreamOverlayStateController; @Nullable private final FoldAodAnimationController mFoldAodAnimationController; - private KeyguardMessageAreaController<AuthKeyguardMessageArea> mKeyguardMessageAreaController; + KeyguardMessageAreaController<AuthKeyguardMessageArea> mKeyguardMessageAreaController; private final PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor; private final PrimaryBouncerInteractor mPrimaryBouncerInteractor; private final AlternateBouncerInteractor mAlternateBouncerInteractor; @@ -430,6 +430,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mDockManager.addListener(mDockEventListener); mIsDocked = mDockManager.isDocked(); } + mKeyguardStateController.addCallback(mKeyguardStateControllerCallback); } /** Register a callback, to be invoked by the Predictive Back system. */ @@ -1564,6 +1565,14 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb || mode == KeyguardSecurityModel.SecurityMode.SimPuk; } + private KeyguardStateController.Callback mKeyguardStateControllerCallback = + new KeyguardStateController.Callback() { + @Override + public void onUnlockedChanged() { + updateAlternateBouncerShowing(mAlternateBouncerInteractor.maybeHide()); + } + }; + /** * Delegate used to send show and hide events to an alternate authentication method instead of * the regular pin/pattern/password bouncer. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java index 2c57a268f6b8..67243b6aed00 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java @@ -16,26 +16,15 @@ package com.android.systemui.statusbar.phone.dagger; -import android.content.ContentResolver; -import android.os.Handler; import android.view.LayoutInflater; -import android.view.ViewStub; - -import androidx.constraintlayout.motion.widget.MotionLayout; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.R; -import com.android.systemui.battery.BatteryMeterView; -import com.android.systemui.battery.BatteryMeterViewController; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.privacy.OngoingPrivacyChip; -import com.android.systemui.settings.UserTracker; -import com.android.systemui.shade.CombinedShadeHeadersConstraintManager; -import com.android.systemui.shade.CombinedShadeHeadersConstraintManagerImpl; import com.android.systemui.shade.NotificationPanelView; import com.android.systemui.shade.NotificationPanelViewController; import com.android.systemui.shade.NotificationShadeWindowView; @@ -59,17 +48,13 @@ import com.android.systemui.statusbar.phone.StatusBarBoundsProvider; import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.phone.StatusBarLocationPublisher; -import com.android.systemui.statusbar.phone.StatusIconContainer; import com.android.systemui.statusbar.phone.SystemBarAttributesListener; import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment; import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragmentLogger; import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent; import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController; -import com.android.systemui.statusbar.policy.BatteryController; -import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.window.StatusBarWindowStateController; -import com.android.systemui.tuner.TunerService; import com.android.systemui.util.CarrierConfigTracker; import com.android.systemui.util.settings.SecureSettings; @@ -90,7 +75,6 @@ import javax.inject.Provider; }) public abstract class StatusBarViewModule { - public static final String SHADE_HEADER = "large_screen_shade_header"; public static final String STATUS_BAR_FRAGMENT = "status_bar_fragment"; /** */ @@ -136,76 +120,6 @@ public abstract class StatusBarViewModule { abstract ShadeViewController bindsShadeViewController( NotificationPanelViewController notificationPanelViewController); - @Provides - @Named(SHADE_HEADER) - @CentralSurfacesComponent.CentralSurfacesScope - public static MotionLayout getLargeScreenShadeHeaderBarView( - NotificationShadeWindowView notificationShadeWindowView, - FeatureFlags featureFlags) { - ViewStub stub = notificationShadeWindowView.findViewById(R.id.qs_header_stub); - int layoutId = R.layout.combined_qs_header; - stub.setLayoutResource(layoutId); - MotionLayout v = (MotionLayout) stub.inflate(); - return v; - } - - /** */ - @Provides - @CentralSurfacesComponent.CentralSurfacesScope - public static CombinedShadeHeadersConstraintManager - provideCombinedShadeHeadersConstraintManager() { - return CombinedShadeHeadersConstraintManagerImpl.INSTANCE; - } - - /** */ - @Provides - @CentralSurfacesComponent.CentralSurfacesScope - public static OngoingPrivacyChip getSplitShadeOngoingPrivacyChip( - @Named(SHADE_HEADER) MotionLayout header) { - return header.findViewById(R.id.privacy_chip); - } - - /** */ - @Provides - @CentralSurfacesComponent.CentralSurfacesScope - static StatusIconContainer providesStatusIconContainer( - @Named(SHADE_HEADER) MotionLayout header) { - return header.findViewById(R.id.statusIcons); - } - - /** */ - @Provides - @CentralSurfacesComponent.CentralSurfacesScope - @Named(SHADE_HEADER) - static BatteryMeterView getBatteryMeterView(@Named(SHADE_HEADER) MotionLayout view) { - return view.findViewById(R.id.batteryRemainingIcon); - } - - @Provides - @CentralSurfacesComponent.CentralSurfacesScope - @Named(SHADE_HEADER) - static BatteryMeterViewController getBatteryMeterViewController( - @Named(SHADE_HEADER) BatteryMeterView batteryMeterView, - UserTracker userTracker, - ConfigurationController configurationController, - TunerService tunerService, - @Main Handler mainHandler, - ContentResolver contentResolver, - FeatureFlags featureFlags, - BatteryController batteryController - ) { - return new BatteryMeterViewController( - batteryMeterView, - userTracker, - configurationController, - tunerService, - mainHandler, - contentResolver, - featureFlags, - batteryController); - - } - /** */ @Provides @CentralSurfacesComponent.CentralSurfacesScope diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java index 3d811cfc901d..673819b20e4b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java @@ -240,7 +240,7 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum || (Build.IS_DEBUGGABLE && DEBUG_AUTH_WITH_ADB && mDebugUnlocked); boolean trustManaged = mKeyguardUpdateMonitor.getUserTrustIsManaged(user); boolean trusted = mKeyguardUpdateMonitor.getUserHasTrust(user); - boolean faceAuthEnabled = mKeyguardUpdateMonitor.isFaceEnrolled(); + boolean faceAuthEnabled = mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(user); boolean changed = secure != mSecure || canDismissLockScreen != mCanDismissLockScreen || trustManaged != mTrustManaged || mTrusted != trusted || mFaceAuthEnabled != faceAuthEnabled; diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 71246c994bfa..2962c14b813a 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -383,7 +383,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } private void setupFingerprintAuth(boolean isClass3) throws RemoteException { - when(mAuthController.isFingerprintEnrolled(anyInt())).thenReturn(true); when(mFingerprintManager.isHardwareDetected()).thenReturn(true); when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true); mFingerprintSensorProperties = List.of( @@ -2693,42 +2692,33 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test public void testFingerprintSensorProperties() throws RemoteException { - // GIVEN no fingerprint sensor properties - when(mAuthController.isFingerprintEnrolled(anyInt())).thenReturn(true); mFingerprintAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered( new ArrayList<>()); - // THEN fingerprint is not possible assertThat(mKeyguardUpdateMonitor.isUnlockWithFingerprintPossible( KeyguardUpdateMonitor.getCurrentUser())).isFalse(); - // WHEN there are fingerprint sensor properties mFingerprintAuthenticatorsRegisteredCallback .onAllAuthenticatorsRegistered(mFingerprintSensorProperties); - // THEN unlock with fp is possible & fingerprint starts listening + verifyFingerprintAuthenticateCall(); assertThat(mKeyguardUpdateMonitor.isUnlockWithFingerprintPossible( KeyguardUpdateMonitor.getCurrentUser())).isTrue(); - verifyFingerprintAuthenticateCall(); } @Test public void testFaceSensorProperties() throws RemoteException { - // GIVEN no face sensor properties - when(mAuthController.isFaceAuthEnrolled(anyInt())).thenReturn(true); mFaceAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered(new ArrayList<>()); - // THEN face is not possible - assertThat(mKeyguardUpdateMonitor.isUnlockWithFacePossible( + assertThat(mKeyguardUpdateMonitor.isFaceAuthEnabledForUser( KeyguardUpdateMonitor.getCurrentUser())).isFalse(); - // WHEN there are face sensor properties mFaceAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered(mFaceSensorProperties); + biometricsEnabledForCurrentUser(); - // THEN face is possible but face does NOT start listening immediately - assertThat(mKeyguardUpdateMonitor.isUnlockWithFacePossible( - KeyguardUpdateMonitor.getCurrentUser())).isTrue(); verifyFaceAuthenticateNeverCalled(); verifyFaceDetectNeverCalled(); + assertThat(mKeyguardUpdateMonitor.isFaceAuthEnabledForUser( + KeyguardUpdateMonitor.getCurrentUser())).isTrue(); } @Test @@ -2801,6 +2791,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } private void mockCanBypassLockscreen(boolean canBypass) { + // force update the isFaceEnrolled cache: + mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(getCurrentUser()); + mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController); when(mKeyguardBypassController.canBypass()).thenReturn(canBypass); } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/SplitShadeTransitionAdapterTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/SplitShadeTransitionAdapterTest.kt index dea2082a2c22..6fe889270d65 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/SplitShadeTransitionAdapterTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/SplitShadeTransitionAdapterTest.kt @@ -18,6 +18,7 @@ package com.android.keyguard import android.animation.Animator import android.testing.AndroidTestingRunner import android.transition.TransitionValues +import android.view.View import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardStatusViewController.SplitShadeTransitionAdapter import com.android.systemui.SysuiTestCase @@ -44,14 +45,16 @@ class SplitShadeTransitionAdapterTest : SysuiTestCase() { @Test fun createAnimator_nullStartValues_returnsNull() { - val animator = adapter.createAnimator(startValues = null, endValues = TransitionValues()) + val endValues = createEndValues() + + val animator = adapter.createAnimator(startValues = null, endValues = endValues) assertThat(animator).isNull() } @Test fun createAnimator_nullEndValues_returnsNull() { - val animator = adapter.createAnimator(startValues = TransitionValues(), endValues = null) + val animator = adapter.createAnimator(startValues = createStartValues(), endValues = null) assertThat(animator).isNull() } @@ -59,10 +62,22 @@ class SplitShadeTransitionAdapterTest : SysuiTestCase() { @Test fun createAnimator_nonNullStartAndEndValues_returnsAnimator() { val animator = - adapter.createAnimator(startValues = TransitionValues(), endValues = TransitionValues()) + adapter.createAnimator(startValues = createStartValues(), endValues = createEndValues()) assertThat(animator).isNotNull() } + + private fun createStartValues() = + TransitionValues().also { values -> + values.view = View(context) + adapter.captureStartValues(values) + } + + private fun createEndValues() = + TransitionValues().also { values -> + values.view = View(context) + adapter.captureEndValues(values) + } } private fun SplitShadeTransitionAdapter.createAnimator( diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/accessibility/OWNERS new file mode 100644 index 000000000000..a2001e66e55b --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/OWNERS @@ -0,0 +1 @@ +include /core/java/android/view/accessibility/OWNERS
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java new file mode 100644 index 000000000000..025c88c36203 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.accessibility; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.hardware.input.InputManager; +import android.os.RemoteException; +import android.telecom.TelecomManager; +import android.telephony.TelephonyManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.view.KeyEvent; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.recents.Recents; +import com.android.systemui.settings.FakeDisplayTracker; +import com.android.systemui.settings.UserTracker; +import com.android.systemui.shade.ShadeController; +import com.android.systemui.statusbar.NotificationShadeWindowController; +import com.android.systemui.statusbar.phone.CentralSurfaces; + +import dagger.Lazy; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@TestableLooper.RunWithLooper +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class SystemActionsTest extends SysuiTestCase { + @Mock + private UserTracker mUserTracker; + @Mock + private NotificationShadeWindowController mNotificationShadeController; + @Mock + private ShadeController mShadeController; + @Mock + private Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; + @Mock + private Optional<Recents> mRecentsOptional; + @Mock + private TelecomManager mTelecomManager; + @Mock + private InputManager mInputManager; + private final FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext); + + private SystemActions mSystemActions; + + @Before + public void setUp() throws RemoteException { + MockitoAnnotations.initMocks(this); + mContext.addMockSystemService(TelecomManager.class, mTelecomManager); + mContext.addMockSystemService(InputManager.class, mInputManager); + mSystemActions = new SystemActions(mContext, mUserTracker, mNotificationShadeController, + mShadeController, mCentralSurfacesOptionalLazy, mRecentsOptional, mDisplayTracker); + } + + @Test + public void handleHeadsetHook_callStateIdle_injectsKeyEvents() { + when(mTelecomManager.getCallState()).thenReturn(TelephonyManager.CALL_STATE_IDLE); + // Use a custom doAnswer captor that copies the KeyEvent before storing it, because the + // method under test modifies the event object after injecting it which prevents + // reliably asserting on the event properties. + final List<KeyEvent> keyEvents = new ArrayList<>(); + doAnswer(invocation -> { + keyEvents.add(new KeyEvent(invocation.getArgument(0))); + return null; + }).when(mInputManager).injectInputEvent(any(), anyInt()); + + mSystemActions.handleHeadsetHook(); + + assertThat(keyEvents.size()).isEqualTo(2); + assertThat(keyEvents.get(0).getKeyCode()).isEqualTo(KeyEvent.KEYCODE_HEADSETHOOK); + assertThat(keyEvents.get(0).getAction()).isEqualTo(KeyEvent.ACTION_DOWN); + assertThat(keyEvents.get(1).getKeyCode()).isEqualTo(KeyEvent.KEYCODE_HEADSETHOOK); + assertThat(keyEvents.get(1).getAction()).isEqualTo(KeyEvent.ACTION_UP); + } + + @Test + public void handleHeadsetHook_callStateRinging_answersCall() { + when(mTelecomManager.getCallState()).thenReturn(TelephonyManager.CALL_STATE_RINGING); + + mSystemActions.handleHeadsetHook(); + + verify(mTelecomManager).acceptRingingCall(); + } + + @Test + public void handleHeadsetHook_callStateOffhook_endsCall() { + when(mTelecomManager.getCallState()).thenReturn(TelephonyManager.CALL_STATE_OFFHOOK); + + mSystemActions.handleHeadsetHook(); + + verify(mTelecomManager).endCall(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt index 578e1d4d02ce..cc004363a049 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt @@ -159,22 +159,11 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() { @Test fun doesNotStartIfAnimationIsCancelled() { val runner = activityLaunchAnimator.createRunner(controller) - runner.onAnimationCancelled(false /* isKeyguardOccluded */) + runner.onAnimationCancelled() runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback) waitForIdleSync() - verify(controller).onLaunchAnimationCancelled(false /* newKeyguardOccludedState */) - verify(controller, never()).onLaunchAnimationStart(anyBoolean()) - } - - @Test - fun passesOccludedStateToLaunchAnimationCancelled_ifTrue() { - val runner = activityLaunchAnimator.createRunner(controller) - runner.onAnimationCancelled(true /* isKeyguardOccluded */) - runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback) - - waitForIdleSync() - verify(controller).onLaunchAnimationCancelled(true /* newKeyguardOccludedState */) + verify(controller).onLaunchAnimationCancelled() verify(controller, never()).onLaunchAnimationStart(anyBoolean()) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt index ebbe096b0da3..26cbd7703075 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt @@ -41,11 +41,11 @@ import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito -import org.mockito.Mockito.`when` import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.times import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @SmallTest @@ -378,7 +378,13 @@ class TestableControlsBindingControllerImpl( executor: DelayableExecutor, lazyController: Lazy<ControlsController>, userTracker: UserTracker -) : ControlsBindingControllerImpl(context, executor, lazyController, userTracker) { +) : ControlsBindingControllerImpl( + context, + executor, + lazyController, + mock(PackageUpdateMonitor.Factory::class.java), + userTracker +) { companion object { val providers = mutableListOf<ControlsProviderLifecycleManager>() diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt index da548f7ccef2..b5d34768dc9f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt @@ -30,6 +30,10 @@ import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.argumentCaptor +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.mock import com.android.systemui.util.time.FakeSystemClock import org.junit.After import org.junit.Assert.assertEquals @@ -39,17 +43,17 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor -import org.mockito.ArgumentMatchers -import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.anyString -import org.mockito.ArgumentMatchers.eq import org.mockito.Captor import org.mockito.Mock -import org.mockito.Mockito.`when` import org.mockito.Mockito.anyInt -import org.mockito.Mockito.mock +import org.mockito.Mockito.clearInvocations +import org.mockito.Mockito.inOrder import org.mockito.Mockito.never +import org.mockito.Mockito.times import org.mockito.Mockito.verify +import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @SmallTest @@ -62,16 +66,21 @@ class ControlsProviderLifecycleManagerTest : SysuiTestCase() { private lateinit var subscriberService: IControlsSubscriber.Stub @Mock private lateinit var service: IControlsProvider.Stub - + @Mock + private lateinit var packageUpdateMonitor: PackageUpdateMonitor @Captor private lateinit var wrapperCaptor: ArgumentCaptor<ControlActionWrapper> + private lateinit var packageUpdateMonitorFactory: FakePackageUpdateMonitorFactory + private val componentName = ComponentName("test.pkg", "test.cls") private lateinit var manager: ControlsProviderLifecycleManager private lateinit var executor: FakeExecutor + private lateinit var fakeSystemClock: FakeSystemClock companion object { fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture() + private val USER = UserHandle.of(0) } @Before @@ -79,16 +88,20 @@ class ControlsProviderLifecycleManagerTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) context.addMockService(componentName, service) - executor = FakeExecutor(FakeSystemClock()) + fakeSystemClock = FakeSystemClock() + executor = FakeExecutor(fakeSystemClock) `when`(service.asBinder()).thenCallRealMethod() - `when`(service.queryLocalInterface(ArgumentMatchers.anyString())).thenReturn(service) + `when`(service.queryLocalInterface(anyString())).thenReturn(service) + + packageUpdateMonitorFactory = FakePackageUpdateMonitorFactory(packageUpdateMonitor) manager = ControlsProviderLifecycleManager( context, executor, actionCallbackService, - UserHandle.of(0), - componentName + USER, + componentName, + packageUpdateMonitorFactory, ) } @@ -122,7 +135,7 @@ class ControlsProviderLifecycleManagerTest : SysuiTestCase() { @Test fun testNullBinding() { - val mockContext = mock(Context::class.java) + val mockContext = mock<Context>() lateinit var serviceConnection: ServiceConnection `when`(mockContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer { val component = (it.arguments[0] as Intent).component @@ -139,8 +152,9 @@ class ControlsProviderLifecycleManagerTest : SysuiTestCase() { mockContext, executor, actionCallbackService, - UserHandle.of(0), - componentName + USER, + componentName, + packageUpdateMonitorFactory, ) nullManager.bindService() @@ -229,14 +243,15 @@ class ControlsProviderLifecycleManagerTest : SysuiTestCase() { @Test fun testFalseBindCallsUnbind() { - val falseContext = mock(Context::class.java) + val falseContext = mock<Context>() `when`(falseContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(false) val manager = ControlsProviderLifecycleManager( falseContext, executor, actionCallbackService, - UserHandle.of(0), - componentName + USER, + componentName, + packageUpdateMonitorFactory, ) manager.bindService() executor.runAllReady() @@ -247,4 +262,150 @@ class ControlsProviderLifecycleManagerTest : SysuiTestCase() { verify(falseContext).bindServiceAsUser(any(), captor.capture(), anyInt(), any()) verify(falseContext).unbindService(captor.value) } + + @Test + fun testPackageUpdateMonitor_createdWithCorrectValues() { + assertEquals(USER, packageUpdateMonitorFactory.lastUser) + assertEquals(componentName.packageName, packageUpdateMonitorFactory.lastPackage) + } + + @Test + fun testBound_packageMonitorStartsMonitoring() { + manager.bindService() + executor.runAllReady() + + // Service will connect and monitoring should start + verify(packageUpdateMonitor).startMonitoring() + } + + @Test + fun testOnPackageUpdateWhileBound_unbound_thenBindAgain() { + val mockContext = mock<Context> { + `when`(bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(true) + } + + val manager = ControlsProviderLifecycleManager( + mockContext, + executor, + actionCallbackService, + USER, + componentName, + packageUpdateMonitorFactory, + ) + + manager.bindService() + executor.runAllReady() + clearInvocations(mockContext) + + packageUpdateMonitorFactory.lastCallback?.run() + executor.runAllReady() + + val inOrder = inOrder(mockContext) + inOrder.verify(mockContext).unbindService(any()) + inOrder.verify(mockContext).bindServiceAsUser(any(), any(), anyInt(), any()) + } + + @Test + fun testOnPackageUpdateWhenNotBound_nothingHappens() { + val mockContext = mock<Context> { + `when`(bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(true) + } + + ControlsProviderLifecycleManager( + mockContext, + executor, + actionCallbackService, + USER, + componentName, + packageUpdateMonitorFactory, + ) + + packageUpdateMonitorFactory.lastCallback?.run() + verifyNoMoreInteractions(mockContext) + } + + @Test + fun testUnbindService_stopsTracking() { + manager.bindService() + manager.unbindService() + executor.runAllReady() + + verify(packageUpdateMonitor).stopMonitoring() + } + + @Test + fun testRebindForPanelWithSameFlags() { + val mockContext = mock<Context> { + `when`(bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(true) + } + + val manager = ControlsProviderLifecycleManager( + mockContext, + executor, + actionCallbackService, + USER, + componentName, + packageUpdateMonitorFactory, + ) + + manager.bindServiceForPanel() + executor.runAllReady() + + val flagsCaptor = argumentCaptor<Int>() + verify(mockContext).bindServiceAsUser(any(), any(), capture(flagsCaptor), any()) + clearInvocations(mockContext) + + packageUpdateMonitorFactory.lastCallback?.run() + executor.runAllReady() + + verify(mockContext).bindServiceAsUser(any(), any(), eq(flagsCaptor.value), any()) + } + + @Test + fun testBindAfterSecurityExceptionWorks() { + val mockContext = mock<Context> { + `when`(bindServiceAsUser(any(), any(), anyInt(), any())) + .thenThrow(SecurityException("exception")) + } + + val manager = ControlsProviderLifecycleManager( + mockContext, + executor, + actionCallbackService, + USER, + componentName, + packageUpdateMonitorFactory, + ) + + manager.bindServiceForPanel() + executor.runAllReady() + + `when`(mockContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(true) + + manager.bindServiceForPanel() + executor.runAllReady() + + verify(mockContext, times(2)).bindServiceAsUser(any(), any(), anyInt(), any()) + } + + private class FakePackageUpdateMonitorFactory( + private val monitor: PackageUpdateMonitor + ) : PackageUpdateMonitor.Factory { + + var lastUser: UserHandle? = null + var lastPackage: String? = null + var lastCallback: Runnable? = null + + override fun create( + user: UserHandle, + packageName: String, + callback: Runnable + ): PackageUpdateMonitor { + lastUser = user + lastPackage = packageName + lastCallback = callback + return monitor + } + } } + diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/PackageUpdateMonitorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/PackageUpdateMonitorTest.kt new file mode 100644 index 000000000000..69547105d419 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/PackageUpdateMonitorTest.kt @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.controls.controller + +import android.content.Context +import android.os.Handler +import android.os.UserHandle +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.mock +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.clearInvocations +import org.mockito.Mockito.never +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class PackageUpdateMonitorTest : SysuiTestCase() { + + @Mock private lateinit var context: Context + @Mock private lateinit var bgHandler: Handler + + private lateinit var underTest: PackageUpdateMonitor + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + } + + @Test + fun startMonitoring_registerOnlyOnce() { + underTest = PackageUpdateMonitor(USER, PACKAGE, {}, bgHandler, context) + + underTest.startMonitoring() + // There are two receivers registered + verify(context, times(2)) + .registerReceiverAsUser(any(), eq(USER), any(), eq(null), eq(bgHandler)) + + underTest.startMonitoring() + verifyNoMoreInteractions(context) + } + + @Test + fun stopMonitoring_unregistersOnlyOnce() { + underTest = PackageUpdateMonitor(USER, PACKAGE, {}, bgHandler, context) + + underTest.startMonitoring() + clearInvocations(context) + + underTest.stopMonitoring() + verify(context).unregisterReceiver(any()) + + underTest.stopMonitoring() + verifyNoMoreInteractions(context) + } + + @Test + fun onPackageUpdated_correctPackageAndUser_callbackRuns() { + val callback = mock<Runnable>() + + underTest = PackageUpdateMonitor(USER, PACKAGE, callback, bgHandler, context) + + underTest.onPackageUpdateFinished(PACKAGE, UserHandle.getUid(USER.identifier, 10000)) + verify(callback).run() + } + + @Test + fun onPackageUpdated_correctPackage_wrongUser_callbackDoesntRun() { + val callback = mock<Runnable>() + + underTest = PackageUpdateMonitor(USER, PACKAGE, callback, bgHandler, context) + + underTest.onPackageUpdateFinished(PACKAGE, UserHandle.getUid(USER.identifier + 1, 10000)) + verify(callback, never()).run() + } + + @Test + fun onPackageUpdated_wrongPackage_correctUser_callbackDoesntRun() { + val callback = mock<Runnable>() + + underTest = PackageUpdateMonitor(USER, PACKAGE, callback, bgHandler, context) + + underTest.onPackageUpdateFinished("bad", UserHandle.getUid(USER.identifier + 1, 10000)) + verify(callback, never()).run() + } + + companion object { + private val USER = UserHandle.of(0) + private val PACKAGE = "pkg" + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt index b7c62463899f..039682c88498 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt @@ -24,6 +24,7 @@ import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Mock import org.mockito.Mockito.anyLong +import org.mockito.Mockito.atLeastOnce import org.mockito.Mockito.eq import org.mockito.Mockito.never import org.mockito.Mockito.times @@ -49,6 +50,7 @@ class DreamOverlayAnimationsControllerTest : SysuiTestCase() { @Mock private lateinit var stateController: DreamOverlayStateController @Mock private lateinit var configController: ConfigurationController @Mock private lateinit var transitionViewModel: DreamingToLockscreenTransitionViewModel + @Mock private lateinit var logger: DreamLogger private lateinit var controller: DreamOverlayAnimationsController @Before @@ -67,6 +69,7 @@ class DreamOverlayAnimationsControllerTest : SysuiTestCase() { DREAM_IN_COMPLICATIONS_ANIMATION_DURATION, DREAM_IN_TRANSLATION_Y_DISTANCE, DREAM_IN_TRANSLATION_Y_DURATION, + logger ) val mockView: View = mock() @@ -82,9 +85,9 @@ class DreamOverlayAnimationsControllerTest : SysuiTestCase() { verify(stateController).setExitAnimationsRunning(true) val captor = argumentCaptor<Animator.AnimatorListener>() - verify(mockAnimator).addListener(captor.capture()) + verify(mockAnimator, atLeastOnce()).addListener(captor.capture()) - captor.value.onAnimationEnd(mockAnimator) + captor.allValues.forEach { it.onAnimationEnd(mockAnimator) } verify(stateController).setExitAnimationsRunning(false) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt index 6f9dedf9dda8..fae637541028 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt @@ -18,9 +18,12 @@ package com.android.systemui.keyboard.data.repository import android.hardware.input.InputManager +import android.hardware.input.InputManager.KeyboardBacklightListener +import android.hardware.input.KeyboardBacklightState import android.view.InputDevice import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.FlowValue import com.android.systemui.coroutines.collectLastValue import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock @@ -29,9 +32,11 @@ import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first 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 @@ -50,6 +55,7 @@ class KeyboardRepositoryTest : SysuiTestCase() { @Captor private lateinit var deviceListenerCaptor: ArgumentCaptor<InputManager.InputDeviceListener> + @Captor private lateinit var backlightListenerCaptor: ArgumentCaptor<KeyboardBacklightListener> @Mock private lateinit var inputManager: InputManager private lateinit var underTest: KeyboardRepository @@ -174,7 +180,71 @@ class KeyboardRepositoryTest : SysuiTestCase() { @Test fun passesKeyboardBacklightValues_fromBacklightListener() { - // TODO(b/268645734): implement when implementing backlight listener + testScope.runTest { + // we want to capture backlight listener but this can only be done after Flow is + // subscribed to and listener is actually registered in inputManager + val backlight by collectLastValueImmediately(underTest.backlight) + + verify(inputManager) + .registerKeyboardBacklightListener(any(), backlightListenerCaptor.capture()) + + backlightListenerCaptor.value.onBacklightChanged(current = 1, max = 5) + + assertThat(backlight?.level).isEqualTo(1) + assertThat(backlight?.maxLevel).isEqualTo(5) + } + } + + private fun <T> TestScope.collectLastValueImmediately(flow: Flow<T>): FlowValue<T?> { + val lastValue = collectLastValue(flow) + // runCurrent() makes us wait for collect that happens in collectLastValue and ensures + // Flow is initialized + runCurrent() + return lastValue + } + + @Test + fun keyboardBacklightValuesNotPassed_fromBacklightListener_whenNotTriggeredByKeyPress() { + testScope.runTest() { + val backlight by collectLastValueImmediately(underTest.backlight) + verify(inputManager) + .registerKeyboardBacklightListener(any(), backlightListenerCaptor.capture()) + + backlightListenerCaptor.value.onBacklightChanged( + current = 1, + max = 5, + triggeredByKeyPress = false + ) + assertThat(backlight).isNull() + } + } + + @Test + fun passesKeyboardBacklightValues_fromBacklightListener_whenTriggeredByKeyPress() { + testScope.runTest() { + val backlight by collectLastValueImmediately(underTest.backlight) + verify(inputManager) + .registerKeyboardBacklightListener(any(), backlightListenerCaptor.capture()) + + backlightListenerCaptor.value.onBacklightChanged( + current = 1, + max = 5, + triggeredByKeyPress = true + ) + assertThat(backlight).isNotNull() + } + } + + private fun KeyboardBacklightListener.onBacklightChanged( + current: Int, + max: Int, + triggeredByKeyPress: Boolean = true + ) { + onKeyboardBacklightChanged( + /* deviceId= */ 0, + TestBacklightState(current, max), + triggeredByKeyPress + ) } private companion object { @@ -199,4 +269,12 @@ class KeyboardRepositoryTest : SysuiTestCase() { whenever(it.isFullKeyboard).thenReturn(fullKeyboard) } } + + private class TestBacklightState( + private val brightnessLevel: Int, + private val maxBrightnessLevel: Int + ) : KeyboardBacklightState() { + override fun getBrightnessLevel() = brightnessLevel + override fun getMaxBrightnessLevel() = maxBrightnessLevel + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt index b46d996ddfcd..f8cb40885d21 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.data.quickaffordance import androidx.test.filters.SmallTest import com.android.systemui.R -import com.android.systemui.RoboPilotTest import com.android.systemui.SysuiTestCase import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.controller.ControlsController @@ -46,7 +45,6 @@ import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @SmallTest -@RoboPilotTest @RunWith(Parameterized::class) class HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt index b50cf73b9ec7..1d0b58a8e0f4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt @@ -67,6 +67,7 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.util.mockito.KotlinArgumentCaptor import com.android.systemui.util.mockito.captureMany +import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock import com.android.systemui.util.time.SystemClock @@ -193,8 +194,24 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { bypassControllerOverride: KeyguardBypassController? = bypassController ): DeviceEntryFaceAuthRepositoryImpl { val systemClock = FakeSystemClock() - val faceAuthBuffer = TableLogBuffer(10, "face auth", systemClock) - val faceDetectBuffer = TableLogBuffer(10, "face detect", systemClock) + val faceAuthBuffer = + TableLogBuffer( + 10, + "face auth", + systemClock, + mock(), + testDispatcher, + testScope.backgroundScope + ) + val faceDetectBuffer = + TableLogBuffer( + 10, + "face detect", + systemClock, + mock(), + testDispatcher, + testScope.backgroundScope + ) keyguardTransitionRepository = FakeKeyguardTransitionRepository() val keyguardTransitionInteractor = KeyguardTransitionInteractor(keyguardTransitionRepository) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt index f4d28431a2e9..d0bfaa9bedc9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt @@ -23,7 +23,6 @@ import android.util.Log.TerribleFailureHandler import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.FlakyTest import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest import com.android.systemui.SysuiTestCase import com.android.systemui.animation.Interpolators import com.android.systemui.keyguard.shared.model.KeyguardState @@ -48,7 +47,6 @@ import org.junit.Test import org.junit.runner.RunWith @SmallTest -@RoboPilotTest @RunWith(AndroidJUnit4::class) @FlakyTest(bugId = 270760395) class KeyguardTransitionRepositoryTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/FakeLogProxy.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/FakeLogProxy.kt new file mode 100644 index 000000000000..471c4615ef0a --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/FakeLogProxy.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.log.table + +/** + * Fake [LogProxy] that collects all lines sent to it. Mimics the ADB logcat format without the + * timestamp. [FakeLogProxy.d] will write a log like so: + * ``` + * logger.d("TAG", "message here") + * // writes this to the [logs] field + * "D TAG: message here" + * ``` + * + * Logs sent to this class are collected as a list of strings for simple test assertions. + */ +class FakeLogProxy : LogProxy { + val logs: MutableList<String> = mutableListOf() + + override fun v(tag: String, message: String) { + logs.add("V $tag: $message") + } + + override fun d(tag: String, message: String) { + logs.add("D $tag: $message") + } + + override fun i(tag: String, message: String) { + logs.add("I $tag: $message") + } + + override fun w(tag: String, message: String) { + logs.add("W $tag: $message") + } + + override fun e(tag: String, message: String) { + logs.add("E $tag: $message") + } + + override fun wtf(tag: String, message: String) { + logs.add("WTF $tag: $message") + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt index c49337a53970..1d182cfec49c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt @@ -19,6 +19,7 @@ package com.android.systemui.log.table import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.log.table.TableChange.Companion.IS_INITIAL_PREFIX +import com.android.systemui.util.mockito.mock import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import java.io.PrintWriter @@ -39,7 +40,8 @@ import org.junit.Test @OptIn(ExperimentalCoroutinesApi::class) class LogDiffsForTableTest : SysuiTestCase() { - private val testScope = TestScope(UnconfinedTestDispatcher()) + private val testDispatcher = UnconfinedTestDispatcher() + private val testScope = TestScope(testDispatcher) private lateinit var systemClock: FakeSystemClock private lateinit var tableLogBuffer: TableLogBuffer @@ -47,7 +49,15 @@ class LogDiffsForTableTest : SysuiTestCase() { @Before fun setUp() { systemClock = FakeSystemClock() - tableLogBuffer = TableLogBuffer(MAX_SIZE, BUFFER_NAME, systemClock) + tableLogBuffer = + TableLogBuffer( + MAX_SIZE, + BUFFER_NAME, + systemClock, + mock(), + testDispatcher, + testScope.backgroundScope, + ) } // ---- Flow<Boolean> tests ---- diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt index af83a560d7d0..8ba76437c725 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt @@ -22,13 +22,20 @@ import com.android.systemui.dump.DumpManager import com.android.systemui.util.mockito.mock import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.UnconfinedTestDispatcher import org.junit.Test +@OptIn(ExperimentalCoroutinesApi::class) @SmallTest class TableLogBufferFactoryTest : SysuiTestCase() { private val dumpManager: DumpManager = mock() private val systemClock = FakeSystemClock() - private val underTest = TableLogBufferFactory(dumpManager, systemClock) + private val testDispatcher = UnconfinedTestDispatcher() + private val testScope = TestScope(testDispatcher) + private val underTest = + TableLogBufferFactory(dumpManager, systemClock, mock(), testDispatcher, testScope) @Test fun create_alwaysCreatesNewInstance() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt index aed830ae0d53..a2b2322899b7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt @@ -19,31 +19,66 @@ package com.android.systemui.log.table import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.log.table.TableChange.Companion.IS_INITIAL_PREFIX +import com.android.systemui.plugins.log.LogLevel +import com.android.systemui.plugins.log.LogcatEchoTracker +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import java.io.PrintWriter import java.io.StringWriter +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.UnconfinedTestDispatcher import org.junit.Before import org.junit.Test +@OptIn(ExperimentalCoroutinesApi::class) @SmallTest class TableLogBufferTest : SysuiTestCase() { private lateinit var underTest: TableLogBuffer private lateinit var systemClock: FakeSystemClock private lateinit var outputWriter: StringWriter + private lateinit var logcatEchoTracker: LogcatEchoTracker + private lateinit var localLogcat: FakeLogProxy + + private val testDispatcher = UnconfinedTestDispatcher() + private val testScope = TestScope(testDispatcher) @Before fun setup() { + localLogcat = FakeLogProxy() + logcatEchoTracker = mock() systemClock = FakeSystemClock() outputWriter = StringWriter() - underTest = TableLogBuffer(MAX_SIZE, NAME, systemClock) + underTest = + TableLogBuffer( + MAX_SIZE, + NAME, + systemClock, + logcatEchoTracker, + testDispatcher, + testScope.backgroundScope, + localLogcat = localLogcat, + ) + underTest.init() } @Test(expected = IllegalArgumentException::class) fun maxSizeZero_throwsException() { - TableLogBuffer(maxSize = 0, "name", systemClock) + TableLogBuffer( + maxSize = 0, + "name", + systemClock, + logcatEchoTracker, + testDispatcher, + testScope.backgroundScope, + localLogcat = localLogcat, + ) } @Test @@ -791,6 +826,112 @@ class TableLogBufferTest : SysuiTestCase() { assertThat(dumpedString).contains(evictedColumnLog3) } + @Test + fun logcat_bufferNotLoggable_tagNotLoggable_noEcho() { + whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), any())).thenReturn(false) + whenever(logcatEchoTracker.isTagLoggable(eq("columnName"), any())).thenReturn(false) + + underTest.logChange("prefix", "columnName", true) + + assertThat(localLogcat.logs).isEmpty() + } + + @Test + fun logcat_bufferIsLoggable_tagNotLoggable_echoes() { + whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), any())).thenReturn(true) + whenever(logcatEchoTracker.isTagLoggable(eq("columnName"), any())).thenReturn(false) + + underTest.logChange("prefix", "columnName", true) + + assertThat(localLogcat.logs).hasSize(1) + } + + @Test + fun logcat_bufferNotLoggable_tagIsLoggable_echoes() { + whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), any())).thenReturn(false) + whenever(logcatEchoTracker.isTagLoggable(eq("columnName"), any())).thenReturn(true) + + underTest.logChange("prefix", "columnName", true) + + assertThat(localLogcat.logs).hasSize(1) + } + + @Test + fun logcat_echoesDebugLogs_debugDisabled_noEcho() { + // Allow any log other than debug + whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), any())).thenAnswer { invocation -> + (invocation.getArgument(1) as LogLevel) != LogLevel.DEBUG + } + + underTest.logChange("prefix", "columnName", true) + + assertThat(localLogcat.logs).isEmpty() + } + + @Test + fun logcat_echoesDebugLogs_debugEnabled_echoes() { + // Only allow debug logs + whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), eq(LogLevel.DEBUG))).thenReturn(true) + + underTest.logChange("prefix", "columnName", true) + + assertThat(localLogcat.logs).hasSize(1) + } + + @Test + fun logcat_bufferNotLoggable_tagIsLoggable_usesColNameForTagCheck() { + systemClock.setCurrentTimeMillis(1000L) + + val nonLoggingTag = "nonLoggingColName" + val loggingTag = "loggingColName" + + whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), any())).thenReturn(false) + whenever(logcatEchoTracker.isTagLoggable(eq(loggingTag), eq(LogLevel.DEBUG))) + .thenReturn(true) + whenever(logcatEchoTracker.isTagLoggable(eq(nonLoggingTag), eq(LogLevel.DEBUG))) + .thenReturn(false) + + underTest.logChange("", nonLoggingTag, true) + underTest.logChange("", loggingTag, true) + + assertThat(localLogcat.logs).hasSize(1) + + val timestamp = TABLE_LOG_DATE_FORMAT.format(1000L) + val expectedMessage = "${timestamp}${SEPARATOR}${loggingTag}${SEPARATOR}true" + val expectedLine = "D $NAME: $expectedMessage" + + assertThat(localLogcat.logs[0]).isEqualTo(expectedLine) + } + + @Test + fun logcat_bufferLoggable_multipleMessagesAreEchoed() { + systemClock.setCurrentTimeMillis(1000L) + whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), any())).thenReturn(true) + + val col1 = "column1" + val col2 = "column2" + + // Log a couple of columns that flip bits + underTest.logChange("", col1, true) + underTest.logChange("", col2, false) + underTest.logChange("", col1, false) + underTest.logChange("", col2, true) + + assertThat(localLogcat.logs).hasSize(4) + + val timestamp = TABLE_LOG_DATE_FORMAT.format(1000L) + val msg1 = "${timestamp}${SEPARATOR}${col1}${SEPARATOR}true" + val msg2 = "${timestamp}${SEPARATOR}${col2}${SEPARATOR}false" + val msg3 = "${timestamp}${SEPARATOR}${col1}${SEPARATOR}false" + val msg4 = "${timestamp}${SEPARATOR}${col2}${SEPARATOR}true" + val expected = listOf(msg1, msg2, msg3, msg4).map { "D $NAME: $it" } + + // Logs use the same bg dispatcher for writing to logcat, they should be in order + for ((msg, logLine) in expected zip localLogcat.logs) { + assertThat(logLine).isEqualTo(msg) + } + } + private fun dumpChanges(): String { underTest.dump(PrintWriter(outputWriter), arrayOf()) return outputWriter.toString() diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDeviceManagerTest.kt index a45e9d9fcacf..0c57e7b82586 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDeviceManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDeviceManagerTest.kt @@ -468,7 +468,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { } @Test - fun audioInfoChanged() { + fun audioInfoPlaybackTypeChanged() { whenever(playbackInfo.getPlaybackType()).thenReturn(PlaybackInfo.PLAYBACK_TYPE_LOCAL) whenever(controller.getPlaybackInfo()).thenReturn(playbackInfo) // GIVEN a controller with local playback type @@ -486,6 +486,25 @@ public class MediaDeviceManagerTest : SysuiTestCase() { } @Test + fun audioInfoVolumeControlIdChanged() { + whenever(playbackInfo.getPlaybackType()).thenReturn(PlaybackInfo.PLAYBACK_TYPE_LOCAL) + whenever(playbackInfo.getVolumeControlId()).thenReturn(null) + whenever(controller.getPlaybackInfo()).thenReturn(playbackInfo) + // GIVEN a controller with local playback type + manager.onMediaDataLoaded(KEY, null, mediaData) + fakeBgExecutor.runAllReady() + fakeFgExecutor.runAllReady() + reset(mr2) + // WHEN onAudioInfoChanged fires with a volume control id change + whenever(playbackInfo.getVolumeControlId()).thenReturn("placeholder id") + val captor = ArgumentCaptor.forClass(MediaController.Callback::class.java) + verify(controller).registerCallback(captor.capture()) + captor.value.onAudioInfoChanged(playbackInfo) + // THEN the route is checked + verify(mr2).getRoutingSessionForMediaController(eq(controller)) + } + + @Test fun audioInfoHasntChanged() { whenever(playbackInfo.getPlaybackType()).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE) whenever(controller.getPlaybackInfo()).thenReturn(playbackInfo) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt index 745f094220f2..07f7c158fc4d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt @@ -19,6 +19,7 @@ package com.android.systemui.media.controls.ui import android.app.PendingIntent import android.content.res.ColorStateList import android.content.res.Configuration +import android.os.LocaleList import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.util.MathUtils.abs @@ -56,6 +57,7 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock +import java.util.Locale import javax.inject.Provider import junit.framework.Assert.assertEquals import junit.framework.Assert.assertFalse @@ -71,6 +73,7 @@ import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.floatThat import org.mockito.Mockito.mock +import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.times import org.mockito.Mockito.verify @@ -123,6 +126,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { @Before fun setup() { MockitoAnnotations.initMocks(this) + context.resources.configuration.locales = LocaleList(Locale.US, Locale.UK) transitionRepository = FakeKeyguardTransitionRepository() mediaCarouselController = MediaCarouselController( @@ -713,6 +717,23 @@ class MediaCarouselControllerTest : SysuiTestCase() { } @Test + fun testOnLocaleListChanged_playersAreAddedBack() { + context.resources.configuration.locales = LocaleList(Locale.US, Locale.UK, Locale.CANADA) + testConfigurationChange(configListener.value::onLocaleListChanged) + + verify(pageIndicator, never()).tintList = + ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator)) + + context.resources.configuration.locales = LocaleList(Locale.UK, Locale.US, Locale.CANADA) + testConfigurationChange(configListener.value::onLocaleListChanged) + + verify(pageIndicator).tintList = + ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator)) + // When recreateMedia is set to true, page indicator is updated on removal and addition. + verify(pageIndicator, times(4)).setNumPages(any()) + } + + @Test fun testRecommendation_persistentEnabled_newSmartspaceLoaded_updatesSort() { testRecommendation_persistentEnabled_inactiveSmartspaceDataLoaded_isAdded() diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java index 0bdcaf464cfd..299303d38f29 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java @@ -19,6 +19,7 @@ package com.android.systemui.media.dialog; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; @@ -33,7 +34,12 @@ import static org.mockito.Mockito.when; import android.app.KeyguardManager; import android.app.Notification; +import android.content.ComponentName; import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.media.AudioDeviceAttributes; import android.media.AudioManager; @@ -44,6 +50,7 @@ import android.media.NearbyDevice; import android.media.RoutingSessionInfo; import android.media.session.MediaController; import android.media.session.MediaSessionManager; +import android.media.session.PlaybackState; import android.os.PowerExemptionManager; import android.os.RemoteException; import android.service.notification.StatusBarNotification; @@ -74,6 +81,9 @@ import com.google.common.collect.ImmutableList; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.List; @@ -93,29 +103,54 @@ public class MediaOutputControllerTest extends SysuiTestCase { private static final String TEST_SONG = "test_song"; private static final String TEST_SESSION_ID = "test_session_id"; private static final String TEST_SESSION_NAME = "test_session_name"; - private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class); - private final ActivityLaunchAnimator.Controller mActivityLaunchAnimatorController = mock( - ActivityLaunchAnimator.Controller.class); - private final NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock( - NearbyMediaDevicesManager.class); + @Mock + private DialogLaunchAnimator mDialogLaunchAnimator; + @Mock + private ActivityLaunchAnimator.Controller mActivityLaunchAnimatorController; + @Mock + private NearbyMediaDevicesManager mNearbyMediaDevicesManager; // Mock - private MediaController mMediaController = mock(MediaController.class); - private MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class); - private CachedBluetoothDeviceManager mCachedBluetoothDeviceManager = - mock(CachedBluetoothDeviceManager.class); - private LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class); - private MediaOutputController.Callback mCb = mock(MediaOutputController.Callback.class); - private MediaDevice mMediaDevice1 = mock(MediaDevice.class); - private MediaDevice mMediaDevice2 = mock(MediaDevice.class); - private NearbyDevice mNearbyDevice1 = mock(NearbyDevice.class); - private NearbyDevice mNearbyDevice2 = mock(NearbyDevice.class); - private MediaMetadata mMediaMetadata = mock(MediaMetadata.class); - private RoutingSessionInfo mRemoteSessionInfo = mock(RoutingSessionInfo.class); - private ActivityStarter mStarter = mock(ActivityStarter.class); - private AudioManager mAudioManager = mock(AudioManager.class); - private KeyguardManager mKeyguardManager = mock(KeyguardManager.class); - private PowerExemptionManager mPowerExemptionManager = mock(PowerExemptionManager.class); - private CommonNotifCollection mNotifCollection = mock(CommonNotifCollection.class); + @Mock + private MediaController mMediaController; + @Mock + private MediaSessionManager mMediaSessionManager; + @Mock + private CachedBluetoothDeviceManager mCachedBluetoothDeviceManager; + @Mock + private LocalBluetoothManager mLocalBluetoothManager; + @Mock + private MediaOutputController.Callback mCb; + @Mock + private MediaDevice mMediaDevice1; + @Mock + private MediaDevice mMediaDevice2; + @Mock + private NearbyDevice mNearbyDevice1; + @Mock + private NearbyDevice mNearbyDevice2; + @Mock + private MediaMetadata mMediaMetadata; + @Mock + private RoutingSessionInfo mRemoteSessionInfo; + @Mock + private ActivityStarter mStarter; + @Mock + private AudioManager mAudioManager; + @Mock + private KeyguardManager mKeyguardManager; + @Mock + private ActivityLaunchAnimator.Controller mController; + @Mock + private PowerExemptionManager mPowerExemptionManager; + @Mock + private CommonNotifCollection mNotifCollection; + @Mock + private PackageManager mPackageManager; + @Mock + private Drawable mDrawable; + @Mock + private PlaybackState mPlaybackState; + private FeatureFlags mFlags = mock(FeatureFlags.class); private View mDialogLaunchView = mock(View.class); private MediaOutputController.Callback mCallback = mock(MediaOutputController.Callback.class); @@ -131,8 +166,11 @@ public class MediaOutputControllerTest extends SysuiTestCase { @Before public void setUp() { + MockitoAnnotations.initMocks(this); + mContext.setMockPackageManager(mPackageManager); mSpyContext = spy(mContext); when(mMediaController.getPackageName()).thenReturn(TEST_PACKAGE_NAME); + when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState); mMediaControllers.add(mMediaController); when(mMediaSessionManager.getActiveSessions(any())).thenReturn(mMediaControllers); doReturn(mMediaSessionManager).when(mSpyContext).getSystemService( @@ -258,6 +296,34 @@ public class MediaOutputControllerTest extends SysuiTestCase { } @Test + public void tryToLaunchMediaApplication_intentNotNull_startActivity() { + when(mDialogLaunchAnimator.createActivityLaunchController(any(View.class))).thenReturn( + mController); + Intent intent = new Intent(TEST_PACKAGE_NAME); + doReturn(intent).when(mPackageManager).getLaunchIntentForPackage(TEST_PACKAGE_NAME); + mMediaOutputController.start(mCallback); + + mMediaOutputController.tryToLaunchMediaApplication(mDialogLaunchView); + + verify(mStarter).startActivity(any(Intent.class), anyBoolean(), + Mockito.eq(mController)); + } + + @Test + public void tryToLaunchInAppRoutingIntent_componentNameNotNull_startActivity() { + when(mDialogLaunchAnimator.createActivityLaunchController(any(View.class))).thenReturn( + mController); + mMediaOutputController.start(mCallback); + when(mLocalMediaManager.getLinkedItemComponentName()).thenReturn( + new ComponentName(TEST_PACKAGE_NAME, "")); + + mMediaOutputController.tryToLaunchInAppRoutingIntent(TEST_DEVICE_1_ID, mDialogLaunchView); + + verify(mStarter).startActivity(any(Intent.class), anyBoolean(), + Mockito.eq(mController)); + } + + @Test public void onDevicesUpdated_unregistersNearbyDevicesCallback() throws RemoteException { mMediaOutputController.start(mCb); @@ -342,6 +408,30 @@ public class MediaOutputControllerTest extends SysuiTestCase { } @Test + public void advanced_onDeviceListUpdateWithConnectedDeviceRemote_verifyItemSize() { + when(mFlags.isEnabled(Flags.OUTPUT_SWITCHER_ADVANCED_LAYOUT)).thenReturn(true); + when(mMediaDevice1.getFeatures()).thenReturn( + ImmutableList.of(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK)); + when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice1); + mMediaOutputController.start(mCb); + reset(mCb); + + mMediaOutputController.onDeviceListUpdate(mMediaDevices); + final List<MediaDevice> devices = new ArrayList<>(); + for (MediaItem item : mMediaOutputController.getMediaItemList()) { + if (item.getMediaDevice().isPresent()) { + devices.add(item.getMediaDevice().get()); + } + } + + assertThat(devices.containsAll(mMediaDevices)).isTrue(); + assertThat(devices.size()).isEqualTo(mMediaDevices.size()); + assertThat(mMediaOutputController.getMediaItemList().size()).isEqualTo( + mMediaDevices.size() + 1); + verify(mCb).onDeviceListChanged(); + } + + @Test public void advanced_categorizeMediaItems_withSuggestedDevice_verifyDeviceListSize() { when(mFlags.isEnabled(Flags.OUTPUT_SWITCHER_ADVANCED_LAYOUT)).thenReturn(true); when(mMediaDevice1.isSuggestedDevice()).thenReturn(true); @@ -582,6 +672,17 @@ public class MediaOutputControllerTest extends SysuiTestCase { } @Test + public void isAnyDeviceTransferring_advancedLayoutSupport() { + when(mFlags.isEnabled(Flags.OUTPUT_SWITCHER_ADVANCED_LAYOUT)).thenReturn(true); + when(mMediaDevice1.getState()).thenReturn( + LocalMediaManager.MediaDeviceState.STATE_CONNECTING); + mMediaOutputController.start(mCb); + mMediaOutputController.onDeviceListUpdate(mMediaDevices); + + assertThat(mMediaOutputController.isAnyDeviceTransferring()).isTrue(); + } + + @Test public void isPlaying_stateIsNull() { when(mMediaController.getPlaybackState()).thenReturn(null); @@ -661,22 +762,6 @@ public class MediaOutputControllerTest extends SysuiTestCase { } @Test - public void connectDevice_verifyConnect() { - when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice2); - - mMediaOutputController.connectDevice(mMediaDevice1); - - // Wait for background thread execution - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - verify(mLocalMediaManager).connectDevice(mMediaDevice1); - } - - @Test public void getActiveRemoteMediaDevice_isSystemSession_returnSession() { when(mRemoteSessionInfo.getId()).thenReturn(TEST_SESSION_ID); when(mRemoteSessionInfo.getName()).thenReturn(TEST_SESSION_NAME); @@ -883,6 +968,56 @@ public class MediaOutputControllerTest extends SysuiTestCase { } @Test + public void getDeviceIconCompat_deviceIconIsNotNull_returnsIcon() { + when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice2); + when(mMediaDevice1.getIcon()).thenReturn(mDrawable); + + assertThat(mMediaOutputController.getDeviceIconCompat(mMediaDevice1)).isInstanceOf( + IconCompat.class); + } + + @Test + public void getDeviceIconCompat_deviceIconIsNull_returnsIcon() { + when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice2); + when(mMediaDevice1.getIcon()).thenReturn(null); + + assertThat(mMediaOutputController.getDeviceIconCompat(mMediaDevice1)).isInstanceOf( + IconCompat.class); + } + + @Test + public void setColorFilter_setColorFilterToDrawable() { + mMediaOutputController.setColorFilter(mDrawable, true); + + verify(mDrawable).setColorFilter(any(PorterDuffColorFilter.class)); + } + + @Test + public void resetGroupMediaDevices_clearGroupDevices() { + final MediaDevice selectedMediaDevice1 = mock(MediaDevice.class); + final MediaDevice selectedMediaDevice2 = mock(MediaDevice.class); + final MediaDevice selectableMediaDevice1 = mock(MediaDevice.class); + final MediaDevice selectableMediaDevice2 = mock(MediaDevice.class); + final List<MediaDevice> selectedMediaDevices = new ArrayList<>(); + final List<MediaDevice> selectableMediaDevices = new ArrayList<>(); + when(selectedMediaDevice1.getId()).thenReturn(TEST_DEVICE_1_ID); + when(selectedMediaDevice2.getId()).thenReturn(TEST_DEVICE_2_ID); + when(selectableMediaDevice1.getId()).thenReturn(TEST_DEVICE_3_ID); + when(selectableMediaDevice2.getId()).thenReturn(TEST_DEVICE_4_ID); + selectedMediaDevices.add(selectedMediaDevice1); + selectedMediaDevices.add(selectedMediaDevice2); + selectableMediaDevices.add(selectableMediaDevice1); + selectableMediaDevices.add(selectableMediaDevice2); + doReturn(selectedMediaDevices).when(mLocalMediaManager).getSelectedMediaDevice(); + doReturn(selectableMediaDevices).when(mLocalMediaManager).getSelectableMediaDevice(); + assertThat(mMediaOutputController.getGroupMediaDevices().isEmpty()).isFalse(); + + mMediaOutputController.resetGroupMediaDevices(); + + assertThat(mMediaOutputController.mGroupMediaDevices.isEmpty()).isTrue(); + } + + @Test public void isVolumeControlEnabled_isCastWithVolumeFixed_returnsFalse() { when(mMediaDevice1.getDeviceType()).thenReturn( MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE); @@ -919,6 +1054,42 @@ public class MediaOutputControllerTest extends SysuiTestCase { } @Test + public void setTemporaryAllowListExceptionIfNeeded_packageNameIsNull_NoAction() { + MediaOutputController testMediaOutputController = new MediaOutputController(mSpyContext, + null, + mMediaSessionManager, mLocalBluetoothManager, mStarter, + mNotifCollection, mDialogLaunchAnimator, + Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager, + mKeyguardManager, mFlags); + + testMediaOutputController.setTemporaryAllowListExceptionIfNeeded(mMediaDevice2); + + verify(mPowerExemptionManager, never()).addToTemporaryAllowList(anyString(), anyInt(), + anyString(), + anyLong()); + } + + @Test + public void onMetadataChanged_triggersOnMetadataChanged() { + mMediaOutputController.mCallback = this.mCallback; + + mMediaOutputController.mCb.onMetadataChanged(mMediaMetadata); + + verify(mMediaOutputController.mCallback).onMediaChanged(); + } + + @Test + public void onPlaybackStateChanged_updateWithNullState_onMediaStoppedOrPaused() { + when(mPlaybackState.getState()).thenReturn(PlaybackState.STATE_PLAYING); + mMediaOutputController.mCallback = this.mCallback; + mMediaOutputController.start(mCb); + + mMediaOutputController.mCb.onPlaybackStateChanged(null); + + verify(mMediaOutputController.mCallback).onMediaStoppedOrPaused(); + } + + @Test public void launchBluetoothPairing_isKeyguardLocked_dismissDialog() { when(mDialogLaunchAnimator.createActivityLaunchController(mDialogLaunchView)).thenReturn( mActivityLaunchAnimatorController); diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt index 55f221df1f0a..5dbcd33ab0e6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt @@ -45,8 +45,8 @@ import androidx.test.runner.AndroidJUnit4 import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.notetask.NoteTaskController.Companion.EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE +import com.android.systemui.notetask.NoteTaskController.Companion.SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT import com.android.systemui.notetask.NoteTaskController.Companion.SHORTCUT_ID -import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity import com.android.systemui.notetask.shortcut.LaunchNoteTaskActivity import com.android.systemui.notetask.shortcut.LaunchNoteTaskManagedProfileProxyActivity import com.android.systemui.settings.FakeUserTracker @@ -423,8 +423,8 @@ internal class NoteTaskControllerTest : SysuiTestCase() { eq(COMPONENT_ENABLED_STATE_ENABLED), eq(PackageManager.DONT_KILL_APP), ) - assertThat(argument.value.className) - .isEqualTo(CreateNoteTaskShortcutActivity::class.java.name) + + assertThat(argument.value).isEqualTo(SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT) } @Test @@ -438,8 +438,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { eq(COMPONENT_ENABLED_STATE_DISABLED), eq(PackageManager.DONT_KILL_APP), ) - assertThat(argument.value.className) - .isEqualTo(CreateNoteTaskShortcutActivity::class.java.name) + assertThat(argument.value).isEqualTo(SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT) } @Test @@ -458,8 +457,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { eq(COMPONENT_ENABLED_STATE_ENABLED), eq(PackageManager.DONT_KILL_APP), ) - assertThat(argument.value.className) - .isEqualTo(CreateNoteTaskShortcutActivity::class.java.name) + assertThat(argument.value).isEqualTo(SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT) } @Test @@ -479,8 +477,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { eq(COMPONENT_ENABLED_STATE_DISABLED), eq(PackageManager.DONT_KILL_APP), ) - assertThat(argument.value.className) - .isEqualTo(CreateNoteTaskShortcutActivity::class.java.name) + assertThat(argument.value).isEqualTo(SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT) } // endregion @@ -664,8 +661,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { eq(COMPONENT_ENABLED_STATE_ENABLED), eq(PackageManager.DONT_KILL_APP), ) - assertThat(actualComponent.value.className) - .isEqualTo(CreateNoteTaskShortcutActivity::class.java.name) + assertThat(actualComponent.value).isEqualTo(SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT) verify(shortcutManager, never()).disableShortcuts(any()) verify(shortcutManager).enableShortcuts(listOf(SHORTCUT_ID)) val actualShortcuts = argumentCaptor<List<ShortcutInfo>>() @@ -696,8 +692,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { eq(COMPONENT_ENABLED_STATE_DISABLED), eq(PackageManager.DONT_KILL_APP), ) - assertThat(argument.value.className) - .isEqualTo(CreateNoteTaskShortcutActivity::class.java.name) + assertThat(argument.value).isEqualTo(SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT) verify(shortcutManager).disableShortcuts(listOf(SHORTCUT_ID)) verify(shortcutManager, never()).enableShortcuts(any()) verify(shortcutManager, never()).updateShortcuts(any()) @@ -714,8 +709,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { eq(COMPONENT_ENABLED_STATE_DISABLED), eq(PackageManager.DONT_KILL_APP), ) - assertThat(argument.value.className) - .isEqualTo(CreateNoteTaskShortcutActivity::class.java.name) + assertThat(argument.value).isEqualTo(SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT) verify(shortcutManager).disableShortcuts(listOf(SHORTCUT_ID)) verify(shortcutManager, never()).enableShortcuts(any()) verify(shortcutManager, never()).updateShortcuts(any()) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java index f870631bd72b..1edc63c4417e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -115,6 +115,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QS; import com.android.systemui.qs.QSFragment; import com.android.systemui.screenrecord.RecordingController; +import com.android.systemui.shade.data.repository.ShadeRepository; import com.android.systemui.shade.transition.ShadeTransitionController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.KeyguardIndicationController; @@ -304,6 +305,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { mEmptySpaceClickListenerCaptor; @Mock protected ActivityStarter mActivityStarter; @Mock protected KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor; + @Mock protected ShadeRepository mShadeRepository; protected final int mMaxUdfpsBurnInOffsetY = 5; protected KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor; @@ -672,7 +674,8 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { mFeatureFlags, mInteractionJankMonitor, mShadeLog, - mKeyguardFaceAuthInteractor + mKeyguardFaceAuthInteractor, + mShadeRepository ); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java index 908f7cbf4801..8a9161e6d46d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java @@ -69,6 +69,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QS; import com.android.systemui.qs.QSFragment; import com.android.systemui.screenrecord.RecordingController; +import com.android.systemui.shade.data.repository.ShadeRepository; import com.android.systemui.shade.transition.ShadeTransitionController; import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.NotificationRemoteInputManager; @@ -88,6 +89,8 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager; import com.android.systemui.statusbar.policy.KeyguardStateController; +import dagger.Lazy; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -98,8 +101,6 @@ import org.mockito.MockitoAnnotations; import java.util.List; -import dagger.Lazy; - @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @@ -241,7 +242,8 @@ public class QuickSettingsControllerTest extends SysuiTestCase { mFeatureFlags, mInteractionJankMonitor, mShadeLogger, - mock(KeyguardFaceAuthInteractor.class) + mock(KeyguardFaceAuthInteractor.class), + mock(ShadeRepository.class) ); mFragmentListener = mQsController.getQsFragmentListener(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt new file mode 100644 index 000000000000..8f2c93b3bf43 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.shade.data.repository + +import 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.shade.ShadeExpansionChangeEvent +import com.android.systemui.shade.ShadeExpansionStateManager +import com.android.systemui.shade.domain.model.ShadeModel +import com.android.systemui.util.mockito.withArgCaptor +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.test.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 +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RoboPilotTest +@RunWith(AndroidJUnit4::class) +class ShadeRepositoryImplTest : SysuiTestCase() { + + @Mock private lateinit var shadeExpansionStateManager: ShadeExpansionStateManager + private val testDispatcher = StandardTestDispatcher() + private val testScope = TestScope(testDispatcher) + + private lateinit var underTest: ShadeRepositoryImpl + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + underTest = ShadeRepositoryImpl(shadeExpansionStateManager) + } + + @Test + fun shadeExpansionChangeEvent() = + testScope.runTest { + var latest: ShadeModel? = null + val job = underTest.shadeModel.onEach { latest = it }.launchIn(this) + runCurrent() + assertThat(latest?.expansionAmount).isEqualTo(0f) + assertThat(latest?.isExpanded).isEqualTo(false) + assertThat(latest?.isUserDragging).isEqualTo(false) + + val captor = withArgCaptor { + verify(shadeExpansionStateManager).addExpansionListener(capture()) + } + + captor.onPanelExpansionChanged( + ShadeExpansionChangeEvent( + fraction = 1f, + expanded = true, + tracking = false, + dragDownPxAmount = 0f, + ) + ) + runCurrent() + assertThat(latest?.expansionAmount).isEqualTo(1f) + assertThat(latest?.isExpanded).isEqualTo(true) + assertThat(latest?.isUserDragging).isEqualTo(false) + + captor.onPanelExpansionChanged( + ShadeExpansionChangeEvent( + fraction = .67f, + expanded = false, + tracking = true, + dragDownPxAmount = 0f, + ) + ) + runCurrent() + assertThat(latest?.expansionAmount).isEqualTo(.67f) + assertThat(latest?.isExpanded).isEqualTo(false) + assertThat(latest?.isUserDragging).isEqualTo(true) + + job.cancel() + } + + @Test + fun updateQsExpansion() = + testScope.runTest { + assertThat(underTest.qsExpansion.value).isEqualTo(0f) + + underTest.setQsExpansion(.5f) + assertThat(underTest.qsExpansion.value).isEqualTo(.5f) + + underTest.setQsExpansion(.82f) + assertThat(underTest.qsExpansion.value).isEqualTo(.82f) + + underTest.setQsExpansion(1f) + assertThat(underTest.qsExpansion.value).isEqualTo(1f) + } + + @Test + fun updateUdfpsTransitionToFullShadeProgress() = + testScope.runTest { + assertThat(underTest.udfpsTransitionToFullShadeProgress.value).isEqualTo(0f) + + underTest.setUdfpsTransitionToFullShadeProgress(.5f) + assertThat(underTest.udfpsTransitionToFullShadeProgress.value).isEqualTo(.5f) + + underTest.setUdfpsTransitionToFullShadeProgress(.82f) + assertThat(underTest.udfpsTransitionToFullShadeProgress.value).isEqualTo(.82f) + + underTest.setUdfpsTransitionToFullShadeProgress(1f) + assertThat(underTest.udfpsTransitionToFullShadeProgress.value).isEqualTo(1f) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt index 78f5bf20e6f9..eef4470c48cd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt @@ -43,6 +43,8 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito.never +import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever import org.mockito.junit.MockitoJUnit @@ -172,7 +174,7 @@ class ClockRegistryTest : SysuiTestCase() { } @Test - fun clockIdConflict_ErrorWithoutCrash() { + fun clockIdConflict_ErrorWithoutCrash_unloadDuplicate() { val mockPluginLifecycle1 = mock<PluginLifecycleManager<ClockProviderPlugin>>() val plugin1 = FakeClockPlugin() .addClock("clock_1", "clock 1", { mockClock }, { mockThumbnail }) @@ -199,6 +201,8 @@ class ClockRegistryTest : SysuiTestCase() { assertEquals(registry.createExampleClock("clock_2"), mockClock) assertEquals(registry.getClockThumbnail("clock_1"), mockThumbnail) assertEquals(registry.getClockThumbnail("clock_2"), mockThumbnail) + verify(mockPluginLifecycle1, never()).unloadPlugin() + verify(mockPluginLifecycle2, times(2)).unloadPlugin() } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt index 2106da887b44..2351f7600c65 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt @@ -15,6 +15,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.qs.QS import com.android.systemui.shade.ShadeViewController +import com.android.systemui.shade.data.repository.FakeShadeRepository import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.NotificationTestHelper import com.android.systemui.statusbar.notification.stack.AmbientState @@ -127,6 +128,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { }, qsTransitionControllerFactory = { qsTransitionController }, activityStarter = activityStarter, + shadeRepository = FakeShadeRepository(), ) transitionController.addCallback(transitionControllerCallback) whenever(nsslController.view).thenReturn(stackscroller) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java deleted file mode 100644 index bd0a556ac670..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.systemui.statusbar.notification.stack; - -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.atLeast; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.res.Resources; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; -import android.testing.TestableLooper.RunWithLooper; - -import androidx.test.filters.SmallTest; - -import com.android.systemui.R; -import com.android.systemui.SysuiTestCase; -import com.android.systemui.dump.DumpManager; -import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; -import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.logging.NotificationRoundnessLogger; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.ExpandableView; -import com.android.systemui.statusbar.notification.row.NotificationTestHelper; -import com.android.systemui.util.DeviceConfigProxy; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.MockitoAnnotations; - -import java.util.HashSet; - -@SmallTest -@RunWith(AndroidTestingRunner.class) -@RunWithLooper -public class NotificationRoundnessManagerTest extends SysuiTestCase { - - private NotificationRoundnessManager mRoundnessManager; - private HashSet<ExpandableView> mAnimatedChildren = new HashSet<>(); - private Runnable mRoundnessCallback = mock(Runnable.class); - private ExpandableNotificationRow mFirst; - private ExpandableNotificationRow mSecond; - private NotificationRoundnessLogger mLogger = mock(NotificationRoundnessLogger.class); - private float mSmallRadiusRatio; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - final Resources resources = mContext.getResources(); - mSmallRadiusRatio = resources.getDimension(R.dimen.notification_corner_radius_small) - / resources.getDimension(R.dimen.notification_corner_radius); - mRoundnessManager = new NotificationRoundnessManager( - new NotificationSectionsFeatureManager(new DeviceConfigProxy(), mContext), - mLogger, - mock(DumpManager.class), - mock(FeatureFlags.class)); - allowTestableLooperAsMainThread(); - NotificationTestHelper testHelper = new NotificationTestHelper( - mContext, - mDependency, - TestableLooper.get(this)); - mFirst = testHelper.createRow(); - mFirst.setHeadsUpAnimatingAwayListener(animatingAway - -> mRoundnessManager.updateView(mFirst, false)); - mSecond = testHelper.createRow(); - mSecond.setHeadsUpAnimatingAwayListener(animatingAway - -> mRoundnessManager.updateView(mSecond, false)); - mRoundnessManager.setOnRoundingChangedCallback(mRoundnessCallback); - mRoundnessManager.setAnimatedChildren(mAnimatedChildren); - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mFirst, mFirst), - createSection(null, null) - }); - mRoundnessManager.setExpanded(1.0f, 1.0f); - mRoundnessManager.setShouldRoundPulsingViews(true); - reset(mRoundnessCallback); - } - - @Test - public void testCallbackCalledWhenSecondChanged() { - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mFirst, mSecond), - createSection(null, null) - }); - verify(mRoundnessCallback, atLeast(1)).run(); - } - - @Test - public void testCallbackCalledWhenFirstChanged() { - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mSecond, mFirst), - createSection(null, null) - }); - verify(mRoundnessCallback, atLeast(1)).run(); - } - - @Test - public void testCallbackCalledWhenSecondSectionFirstChanged() { - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mFirst, mFirst), - createSection(mSecond, null) - }); - verify(mRoundnessCallback, atLeast(1)).run(); - } - - @Test - public void testCallbackCalledWhenSecondSectionLastChanged() { - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mFirst, mFirst), - createSection(null, mSecond) - }); - verify(mRoundnessCallback, atLeast(1)).run(); - } - - @Test - public void testCallbackNotCalledWhenFirstChangesSections() { - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(null, mFirst), - createSection(mFirst, null) - }); - verify(mRoundnessCallback, never()).run(); - } - - @Test - public void testRoundnessSetOnLast() { - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mFirst, mSecond), - createSection(null, null) - }); - Assert.assertEquals(1.0f, mSecond.getBottomRoundness(), 0.0f); - Assert.assertEquals(mSmallRadiusRatio, mSecond.getTopRoundness(), 0.0f); - } - - @Test - public void testRoundnessPulsing() throws Exception { - // Let's create a notification that's neither the first or last item of the stack, - // this way we'll ensure that it won't have any rounded corners by default. - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mFirst, mSecond), - createSection(null, null) - }); - NotificationTestHelper testHelper = new NotificationTestHelper( - mContext, - mDependency, - TestableLooper.get(this)); - ExpandableNotificationRow row = testHelper.createRow(); - NotificationEntry entry = mock(NotificationEntry.class); - when(entry.getRow()).thenReturn(row); - - when(testHelper.getStatusBarStateController().isDozing()).thenReturn(true); - row.setHeadsUp(true); - mRoundnessManager.updateView(entry.getRow(), false); - Assert.assertEquals(1f, row.getBottomRoundness(), 0.0f); - Assert.assertEquals(1f, row.getTopRoundness(), 0.0f); - - row.setHeadsUp(false); - mRoundnessManager.updateView(entry.getRow(), false); - Assert.assertEquals(mSmallRadiusRatio, row.getBottomRoundness(), 0.0f); - Assert.assertEquals(mSmallRadiusRatio, row.getTopRoundness(), 0.0f); - } - - @Test - public void testRoundnessSetOnSecondSectionLast() { - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mFirst, mFirst), - createSection(null, mSecond) - }); - Assert.assertEquals(1.0f, mSecond.getBottomRoundness(), 0.0f); - Assert.assertEquals(mSmallRadiusRatio, mSecond.getTopRoundness(), 0.0f); - } - - @Test - public void testRoundnessSetOnSecondSectionFirst() { - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mFirst, mFirst), - createSection(mSecond, null) - }); - Assert.assertEquals(mSmallRadiusRatio, mSecond.getBottomRoundness(), 0.0f); - Assert.assertEquals(1.0f, mSecond.getTopRoundness(), 0.0f); - } - - @Test - public void testRoundnessSetOnNew() { - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mFirst, null), - createSection(null, null) - }); - Assert.assertEquals(mSmallRadiusRatio, mFirst.getBottomRoundness(), 0.0f); - Assert.assertEquals(1.0f, mFirst.getTopRoundness(), 0.0f); - } - - @Test - public void testCompleteReplacement() { - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mSecond, mSecond), - createSection(null, null) - }); - Assert.assertEquals(mSmallRadiusRatio, mFirst.getBottomRoundness(), 0.0f); - Assert.assertEquals(mSmallRadiusRatio, mFirst.getTopRoundness(), 0.0f); - } - - @Test - public void testNotCalledWhenRemoved() { - mFirst.setRemoved(); - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mSecond, mSecond), - createSection(null, null) - }); - Assert.assertEquals(1.0f, mFirst.getBottomRoundness(), 0.0f); - Assert.assertEquals(1.0f, mFirst.getTopRoundness(), 0.0f); - } - - @Test - public void testRoundedWhenPinnedAndCollapsed() { - mFirst.setPinned(true); - mRoundnessManager.setExpanded(0.0f /* expandedHeight */, 0.0f /* appearFraction */); - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mSecond, mSecond), - createSection(null, null) - }); - Assert.assertEquals(1.0f, mFirst.getBottomRoundness(), 0.0f); - Assert.assertEquals(1.0f, mFirst.getTopRoundness(), 0.0f); - } - - @Test - public void testRoundedWhenGoingAwayAndCollapsed() { - mFirst.setHeadsUpAnimatingAway(true); - mRoundnessManager.setExpanded(0.0f /* expandedHeight */, 0.0f /* appearFraction */); - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mSecond, mSecond), - createSection(null, null) - }); - Assert.assertEquals(1.0f, mFirst.getBottomRoundness(), 0.0f); - Assert.assertEquals(1.0f, mFirst.getTopRoundness(), 0.0f); - } - - @Test - public void testRoundedNormalRoundingWhenExpanded() { - mFirst.setHeadsUpAnimatingAway(true); - mRoundnessManager.setExpanded(1.0f /* expandedHeight */, 0.0f /* appearFraction */); - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mSecond, mSecond), - createSection(null, null) - }); - Assert.assertEquals(mSmallRadiusRatio, mFirst.getBottomRoundness(), 0.0f); - Assert.assertEquals(mSmallRadiusRatio, mFirst.getTopRoundness(), 0.0f); - } - - @Test - public void testTrackingHeadsUpRoundedIfPushingUp() { - mRoundnessManager.setExpanded(1.0f /* expandedHeight */, -0.5f /* appearFraction */); - mRoundnessManager.setTrackingHeadsUp(mFirst); - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mSecond, mSecond), - createSection(null, null) - }); - Assert.assertEquals(1.0f, mFirst.getBottomRoundness(), 0.0f); - Assert.assertEquals(1.0f, mFirst.getTopRoundness(), 0.0f); - } - - @Test - public void testTrackingHeadsUpPartiallyRoundedIfPushingDown() { - mRoundnessManager.setExpanded(1.0f /* expandedHeight */, 0.5f /* appearFraction */); - mRoundnessManager.setTrackingHeadsUp(mFirst); - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mSecond, mSecond), - createSection(null, null) - }); - Assert.assertEquals(0.5f, mFirst.getBottomRoundness(), 0.0f); - Assert.assertEquals(0.5f, mFirst.getTopRoundness(), 0.0f); - } - - @Test - public void testRoundingUpdatedWhenAnimatingAwayTrue() { - mRoundnessManager.setExpanded(0.0f, 0.0f); - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mSecond, mSecond), - createSection(null, null) - }); - mFirst.setHeadsUpAnimatingAway(true); - Assert.assertEquals(1.0f, mFirst.getBottomRoundness(), 0.0f); - Assert.assertEquals(1.0f, mFirst.getTopRoundness(), 0.0f); - } - - - @Test - public void testRoundingUpdatedWhenAnimatingAwayFalse() { - mRoundnessManager.setExpanded(0.0f, 0.0f); - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mSecond, mSecond), - createSection(null, null) - }); - mFirst.setHeadsUpAnimatingAway(true); - mFirst.setHeadsUpAnimatingAway(false); - Assert.assertEquals(mSmallRadiusRatio, mFirst.getBottomRoundness(), 0.0f); - Assert.assertEquals(mSmallRadiusRatio, mFirst.getTopRoundness(), 0.0f); - } - - @Test - public void testNoViewsFirstOrLastInSectionWhenSecondSectionEmpty() { - Assert.assertTrue(mFirst.isFirstInSection()); - Assert.assertTrue(mFirst.isLastInSection()); - } - - @Test - public void testNoViewsFirstOrLastInSectionWhenFirstSectionEmpty() { - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(null, null), - createSection(mSecond, mSecond) - }); - Assert.assertTrue(mSecond.isFirstInSection()); - Assert.assertTrue(mSecond.isLastInSection()); - } - - @Test - public void testFirstAndLastViewsInSectionSetWhenBothSectionsNonEmpty() { - mRoundnessManager.updateRoundedChildren(new NotificationSection[]{ - createSection(mFirst, mFirst), - createSection(mSecond, mSecond) - }); - Assert.assertTrue(mFirst.isFirstInSection()); - Assert.assertTrue(mFirst.isLastInSection()); - Assert.assertTrue(mSecond.isFirstInSection()); - Assert.assertTrue(mSecond.isLastInSection()); - } - - @Test - public void testLoggingOnRoundingUpdate() { - NotificationSection[] sections = new NotificationSection[]{ - createSection(mFirst, mSecond), - createSection(null, null) - }; - mRoundnessManager.updateRoundedChildren(sections); - verify(mLogger).onSectionCornersUpdated(sections, /*anyChanged=*/ true); - verify(mLogger, atLeast(1)).onCornersUpdated(eq(mFirst), anyBoolean(), - anyBoolean(), anyBoolean(), anyBoolean()); - verify(mLogger, atLeast(1)).onCornersUpdated(eq(mSecond), anyBoolean(), - anyBoolean(), anyBoolean(), anyBoolean()); - } - - private NotificationSection createSection(ExpandableNotificationRow first, - ExpandableNotificationRow last) { - NotificationSection section = mock(NotificationSection.class); - when(section.getFirstVisibleChild()).thenReturn(first); - when(section.getLastVisibleChild()).thenReturn(last); - return section; - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java index 30da08ebfe7d..f38881c5b521 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java @@ -96,8 +96,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { mIncomingHeaderController, mPeopleHeaderController, mAlertingHeaderController, - mSilentHeaderController, - mFeatureFlag + mSilentHeaderController ); // Required in order for the header inflation to work properly when(mNssl.generateLayoutParams(any(AttributeSet.class))) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt index 81a3f1245efe..45725ced521c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt @@ -6,7 +6,6 @@ import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FakeFeatureFlags -import com.android.systemui.flags.Flags import com.android.systemui.statusbar.notification.row.NotificationTestHelper import com.android.systemui.util.mockito.mock import junit.framework.Assert.assertEquals @@ -30,14 +29,7 @@ class NotificationTargetsHelperTest : SysuiTestCase() { NotificationTestHelper(mContext, mDependency, TestableLooper.get(this)) } - private fun notificationTargetsHelper( - notificationGroupCorner: Boolean = true, - ) = - NotificationTargetsHelper( - FakeFeatureFlags().apply { - set(Flags.USE_ROUNDNESS_SOURCETYPES, notificationGroupCorner) - } - ) + private fun notificationTargetsHelper() = NotificationTargetsHelper(FakeFeatureFlags()) @Test fun targetsForFirstNotificationInGroup() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java index 205cebdefa49..2f1e372eb33d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java @@ -34,8 +34,6 @@ import android.widget.TextView; 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.plugins.DarkIconDispatcher; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shade.ShadeHeadsUpTracker; @@ -82,7 +80,6 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase { private KeyguardStateController mKeyguardStateController; private CommandQueue mCommandQueue; private NotificationRoundnessManager mNotificationRoundnessManager; - private FeatureFlags mFeatureFlag; @Before public void setUp() throws Exception { @@ -103,9 +100,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase { mKeyguardStateController = mock(KeyguardStateController.class); mCommandQueue = mock(CommandQueue.class); mNotificationRoundnessManager = mock(NotificationRoundnessManager.class); - mFeatureFlag = mock(FeatureFlags.class); when(mShadeViewController.getShadeHeadsUpTracker()).thenReturn(mShadeHeadsUpTracker); - when(mFeatureFlag.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES)).thenReturn(true); mHeadsUpAppearanceController = new HeadsUpAppearanceController( mock(NotificationIconAreaController.class), mHeadsUpManager, @@ -118,7 +113,6 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase { mStackScrollerController, mShadeViewController, mNotificationRoundnessManager, - mFeatureFlag, mHeadsUpStatusBarView, new Clock(mContext, null), Optional.of(mOperatorNameView)); @@ -202,7 +196,6 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase { mStackScrollerController, mShadeViewController, mNotificationRoundnessManager, - mFeatureFlag, mHeadsUpStatusBarView, new Clock(mContext, null), Optional.empty()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 6be0e2deaf35..e56f0d6b3b0f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -84,6 +84,7 @@ import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.unfold.SysUIUnfoldComponent; import com.google.common.truth.Truth; @@ -151,13 +152,15 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher; @Captor private ArgumentCaptor<OnBackInvokedCallback> mBackCallbackCaptor; + @Captor + private ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateControllerCallback; @Before public void setUp() { MockitoAnnotations.initMocks(this); when(mContainer.findViewById(anyInt())).thenReturn(mKeyguardMessageArea); - when(mKeyguardMessageAreaFactory.create(any(KeyguardMessageArea.class))) + when(mKeyguardMessageAreaFactory.create(any())) .thenReturn(mKeyguardMessageAreaController); when(mBouncerView.getDelegate()).thenReturn(mBouncerViewDelegate); when(mBouncerViewDelegate.getBackCallback()).thenReturn(mBouncerViewDelegateBackCallback); @@ -909,4 +912,26 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { // THEN the alternateBouncer doesn't hide verify(mAlternateBouncerInteractor, never()).hide(); } + + @Test + public void onDeviceUnlocked_hideAlternateBouncerAndClearMessageArea() { + reset(mKeyguardUpdateMonitor); + reset(mKeyguardMessageAreaController); + + // GIVEN keyguard state controller callback is registered + verify(mKeyguardStateController).addCallback(mKeyguardStateControllerCallback.capture()); + + // GIVEN alternate bouncer state = not visible + when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(false); + + // WHEN the device is unlocked + mKeyguardStateControllerCallback.getValue().onUnlockedChanged(); + + // THEN the false visibility state is propagated to the keyguardUpdateMonitor + verify(mKeyguardUpdateMonitor).setAlternateBouncerShowing(eq(false)); + + // THEN message area visibility updated to FALSE with empty message + verify(mKeyguardMessageAreaController).setIsVisible(eq(false)); + verify(mKeyguardMessageAreaController).setMessage(eq("")); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt index 3ec96908dac8..bde05b9f499e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt @@ -53,6 +53,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.UnconfinedTestDispatcher import org.junit.After import org.junit.Before import org.junit.Test @@ -92,13 +93,15 @@ class MobileRepositorySwitcherTest : SysuiTestCase() { private val mobileMappings = FakeMobileMappingsProxy() private val subscriptionManagerProxy = FakeSubscriptionManagerProxy() + private val testDispatcher = UnconfinedTestDispatcher() private val scope = CoroutineScope(IMMEDIATE) @Before fun setUp() { MockitoAnnotations.initMocks(this) - logFactory = TableLogBufferFactory(dumpManager, FakeSystemClock()) + logFactory = + TableLogBufferFactory(dumpManager, FakeSystemClock(), mock(), testDispatcher, scope) // Never start in demo mode whenever(demoModeController.isInDemoMode).thenReturn(false) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt index 37fac3458c83..7573b28c8a7f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt @@ -61,11 +61,18 @@ import org.junit.runners.Parameterized.Parameters internal class DemoMobileConnectionParameterizedTest(private val testCase: TestCase) : SysuiTestCase() { - private val logFactory = TableLogBufferFactory(mock(), FakeSystemClock()) - private val testDispatcher = UnconfinedTestDispatcher() private val testScope = TestScope(testDispatcher) + private val logFactory = + TableLogBufferFactory( + mock(), + FakeSystemClock(), + mock(), + testDispatcher, + testScope.backgroundScope, + ) + private val fakeNetworkEventFlow = MutableStateFlow<FakeNetworkEventModel?>(null) private val fakeWifiEventFlow = MutableStateFlow<FakeWifiEventModel?>(null) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt index 1251dfacddfc..efaf15235b46 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt @@ -54,13 +54,20 @@ import org.junit.Test @SmallTest class DemoMobileConnectionsRepositoryTest : SysuiTestCase() { private val dumpManager: DumpManager = mock() - private val logFactory = TableLogBufferFactory(dumpManager, FakeSystemClock()) private val testDispatcher = UnconfinedTestDispatcher() private val testScope = TestScope(testDispatcher) private val fakeNetworkEventFlow = MutableStateFlow<FakeNetworkEventModel?>(null) private val fakeWifiEventFlow = MutableStateFlow<FakeWifiEventModel?>(null) + private val logFactory = + TableLogBufferFactory( + dumpManager, + FakeSystemClock(), + mock(), + testDispatcher, + testScope.backgroundScope, + ) private lateinit var underTest: DemoMobileConnectionsRepository private lateinit var mobileDataSource: DemoModeMobileConnectionDataSource diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt index 9f77744e1fec..b701fbd66937 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt @@ -66,7 +66,15 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() { private val systemClock = FakeSystemClock() private val testDispatcher = UnconfinedTestDispatcher() private val testScope = TestScope(testDispatcher) - private val tableLogBuffer = TableLogBuffer(maxSize = 100, name = "TestName", systemClock) + private val tableLogBuffer = + TableLogBuffer( + maxSize = 100, + name = "TestName", + systemClock, + mock(), + testDispatcher, + testScope.backgroundScope, + ) private val mobileFactory = mock<MobileConnectionRepositoryImpl.Factory>() private val carrierMergedFactory = mock<CarrierMergedConnectionRepository.Factory>() @@ -294,7 +302,14 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() { @Test fun factory_reusesLogBuffersForSameConnection() = testScope.runTest { - val realLoggerFactory = TableLogBufferFactory(mock(), FakeSystemClock()) + val realLoggerFactory = + TableLogBufferFactory( + mock(), + FakeSystemClock(), + mock(), + testDispatcher, + testScope.backgroundScope, + ) val factory = FullMobileConnectionRepository.Factory( @@ -329,7 +344,14 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() { @Test fun factory_reusesLogBuffersForSameSubIDevenIfCarrierMerged() = testScope.runTest { - val realLoggerFactory = TableLogBufferFactory(mock(), FakeSystemClock()) + val realLoggerFactory = + TableLogBufferFactory( + mock(), + FakeSystemClock(), + mock(), + testDispatcher, + testScope.backgroundScope, + ) val factory = FullMobileConnectionRepository.Factory( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt index c84c9c032225..6e1ab58db56d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt @@ -61,6 +61,16 @@ class MobileIconsInteractorTest : SysuiTestCase() { private val testDispatcher = UnconfinedTestDispatcher() private val testScope = TestScope(testDispatcher) + private val tableLogBuffer = + TableLogBuffer( + 8, + "MobileIconsInteractorTest", + FakeSystemClock(), + mock(), + testDispatcher, + testScope.backgroundScope, + ) + @Mock private lateinit var carrierConfigTracker: CarrierConfigTracker @Before @@ -687,16 +697,14 @@ class MobileIconsInteractorTest : SysuiTestCase() { } companion object { - private val tableLogBuffer = - TableLogBuffer(8, "MobileIconsInteractorTest", FakeSystemClock()) private const val SUB_1_ID = 1 private val SUB_1 = SubscriptionModel(subscriptionId = SUB_1_ID) - private val CONNECTION_1 = FakeMobileConnectionRepository(SUB_1_ID, tableLogBuffer) + private val CONNECTION_1 = FakeMobileConnectionRepository(SUB_1_ID, mock()) private const val SUB_2_ID = 2 private val SUB_2 = SubscriptionModel(subscriptionId = SUB_2_ID) - private val CONNECTION_2 = FakeMobileConnectionRepository(SUB_2_ID, tableLogBuffer) + private val CONNECTION_2 = FakeMobileConnectionRepository(SUB_2_ID, mock()) private const val SUB_3_ID = 3 private val SUB_3_OPP = @@ -705,7 +713,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { isOpportunistic = true, groupUuid = ParcelUuid(UUID.randomUUID()), ) - private val CONNECTION_3 = FakeMobileConnectionRepository(SUB_3_ID, tableLogBuffer) + private val CONNECTION_3 = FakeMobileConnectionRepository(SUB_3_ID, mock()) private const val SUB_4_ID = 4 private val SUB_4_OPP = @@ -714,6 +722,6 @@ class MobileIconsInteractorTest : SysuiTestCase() { isOpportunistic = true, groupUuid = ParcelUuid(UUID.randomUUID()), ) - private val CONNECTION_4 = FakeMobileConnectionRepository(SUB_4_ID, tableLogBuffer) + private val CONNECTION_4 = FakeMobileConnectionRepository(SUB_4_ID, mock()) } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt index 2c0a8fde0d77..492e5421b010 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt @@ -21,13 +21,27 @@ import com.android.systemui.shade.domain.model.ShadeModel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow -/** Fake implementation of [KeyguardRepository] */ +/** Fake implementation of [ShadeRepository] */ class FakeShadeRepository : ShadeRepository { private val _shadeModel = MutableStateFlow(ShadeModel()) override val shadeModel: Flow<ShadeModel> = _shadeModel + private val _qsExpansion = MutableStateFlow(0f) + override val qsExpansion = _qsExpansion + + private val _udfpsTransitionToFullShadeProgress = MutableStateFlow(0f) + override val udfpsTransitionToFullShadeProgress = _udfpsTransitionToFullShadeProgress + fun setShadeModel(model: ShadeModel) { _shadeModel.value = model } + + override fun setQsExpansion(qsExpansion: Float) { + _qsExpansion.value = qsExpansion + } + + override fun setUdfpsTransitionToFullShadeProgress(progress: Float) { + _udfpsTransitionToFullShadeProgress.value = progress + } } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index a3b4a0f51c75..e894f1c2879e 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -490,7 +490,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mMainHandler, context, new PolicyWarningUIController.NotificationController(context)); mSecurityPolicy = new AccessibilitySecurityPolicy(policyWarningUIController, mContext, - this); + this, LocalServices.getService(PackageManagerInternal.class)); mA11yWindowManager = new AccessibilityWindowManager(mLock, mMainHandler, mWindowManagerService, this, mSecurityPolicy, this, mTraceManager); mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler); @@ -1012,8 +1012,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub + Binder.getCallingPid() + " for device id " + deviceId + " with package names " + Arrays.toString(client.mPackageNames)); } - return IntPair.of(mProxyManager.getStateLocked(deviceId, - mUiAutomationManager.isUiAutomationRunningLocked()), + return IntPair.of(mProxyManager.getStateLocked(deviceId), client.mLastSentRelevantEventTypes); } mGlobalClients.register(callback, client); @@ -1028,8 +1027,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub + Binder.getCallingPid() + " for device id " + deviceId + " with package names " + Arrays.toString(client.mPackageNames)); } - return IntPair.of(mProxyManager.getStateLocked(deviceId, - mUiAutomationManager.isUiAutomationRunningLocked()), + return IntPair.of(mProxyManager.getStateLocked(deviceId), client.mLastSentRelevantEventTypes); } userState.mUserClients.register(callback, client); @@ -4024,9 +4022,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub final long identity = Binder.clearCallingIdentity(); try { - mProxyManager.registerProxy(client, displayId, mContext, - sIdCounter++, mMainHandler, mSecurityPolicy, this, getTraceManager(), - mWindowManagerService); + mProxyManager.registerProxy(client, displayId, sIdCounter++, mSecurityPolicy, + this, getTraceManager(), mWindowManagerService); synchronized (mLock) { notifyClearAccessibilityCacheLocked(); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java index 88656239e59b..65c1873498a1 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java @@ -29,6 +29,7 @@ import android.appwidget.AppWidgetManagerInternal; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; @@ -99,6 +100,7 @@ public class AccessibilitySecurityPolicy { private final Context mContext; private final PackageManager mPackageManager; + private final PackageManagerInternal mPackageManagerInternal; private final UserManager mUserManager; private final AppOpsManager mAppOpsManager; private final AccessibilityUserManager mAccessibilityUserManager; @@ -116,10 +118,12 @@ public class AccessibilitySecurityPolicy { */ public AccessibilitySecurityPolicy(PolicyWarningUIController policyWarningUIController, @NonNull Context context, - @NonNull AccessibilityUserManager a11yUserManager) { + @NonNull AccessibilityUserManager a11yUserManager, + @NonNull PackageManagerInternal packageManagerInternal) { mContext = context; mAccessibilityUserManager = a11yUserManager; mPackageManager = mContext.getPackageManager(); + mPackageManagerInternal = packageManagerInternal; mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); mPolicyWarningUIController = policyWarningUIController; @@ -513,12 +517,7 @@ public class AccessibilitySecurityPolicy { private boolean isValidPackageForUid(String packageName, int uid) { final long token = Binder.clearCallingIdentity(); try { - // Since we treat calls from a profile as if made by its parent, using - // MATCH_ANY_USER to query the uid of the given package name. - return uid == mPackageManager.getPackageUidAsUser( - packageName, PackageManager.MATCH_ANY_USER, UserHandle.getUserId(uid)); - } catch (PackageManager.NameNotFoundException e) { - return false; + return mPackageManagerInternal.isSameApp(packageName, uid, UserHandle.getUserId(uid)); } finally { Binder.restoreCallingIdentity(token); } diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java index d417197e1419..6dc8fb347904 100644 --- a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java +++ b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java @@ -61,7 +61,6 @@ import java.util.function.Consumer; * proxy connection will belong to a separate user state. * * TODO(241117292): Remove or cut down during simultaneous user refactoring. - * TODO(262244375): Add unit tests. */ public class ProxyManager { private static final boolean DEBUG = false; @@ -128,7 +127,7 @@ public class ProxyManager { RemoteCallbackList<IAccessibilityManagerClient> getCurrentUserClientsLocked(); } - ProxyManager(Object lock, AccessibilityWindowManager awm, + public ProxyManager(Object lock, AccessibilityWindowManager awm, Context context, Handler mainHandler, UiAutomationManager uiAutomationManager, SystemSupport systemSupport) { mLock = lock; @@ -144,9 +143,7 @@ public class ProxyManager { * Creates the service connection. */ public void registerProxy(IAccessibilityServiceClient client, int displayId, - Context context, - int id, Handler mainHandler, - AccessibilitySecurityPolicy securityPolicy, + int id, AccessibilitySecurityPolicy securityPolicy, AbstractAccessibilityServiceConnection.SystemSupport systemSupport, AccessibilityTrace trace, WindowManagerInternal windowManagerInternal) throws RemoteException { @@ -169,8 +166,8 @@ public class ProxyManager { info.setComponentName(new ComponentName(PROXY_COMPONENT_PACKAGE_NAME, componentClassDisplayName)); ProxyAccessibilityServiceConnection connection = - new ProxyAccessibilityServiceConnection(context, info.getComponentName(), info, - id, mainHandler, mLock, securityPolicy, systemSupport, trace, + new ProxyAccessibilityServiceConnection(mContext, info.getComponentName(), info, + id, mMainHandler, mLock, securityPolicy, systemSupport, trace, windowManagerInternal, mA11yWindowManager, displayId, deviceId); @@ -263,7 +260,7 @@ public class ProxyManager { * When the connection is removed from tracking in ProxyManager, propagate changes to other a11y * system components like the input filter and IAccessibilityManagerClients. */ - public void updateStateForRemovedDisplay(int displayId, int deviceId) { + private void updateStateForRemovedDisplay(int displayId, int deviceId) { mA11yWindowManager.stopTrackingDisplayProxy(displayId); // A11yInputFilter isn't thread-safe, so post on the system thread. mMainHandler.post( @@ -360,8 +357,9 @@ public class ProxyManager { /** * If there is at least one proxy, accessibility is enabled. */ - public int getStateLocked(int deviceId, boolean automationRunning) { + public int getStateLocked(int deviceId) { int clientState = 0; + final boolean automationRunning = mUiAutomationManager.isUiAutomationRunningLocked(); if (automationRunning) { clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED; } @@ -387,7 +385,7 @@ public class ProxyManager { /** * If there is at least one proxy, accessibility is enabled. */ - public int getStateForDisplayIdLocked(ProxyAccessibilityServiceConnection proxy) { + private int getStateForDisplayIdLocked(ProxyAccessibilityServiceConnection proxy) { int clientState = 0; if (proxy != null) { clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED; @@ -409,14 +407,14 @@ public class ProxyManager { /** * Gets the last state for a device. */ - public int getLastSentStateLocked(int deviceId) { + private int getLastSentStateLocked(int deviceId) { return mLastStates.get(deviceId, 0); } /** * Sets the last state for a device. */ - public void setLastStateLocked(int deviceId, int proxyState) { + private void setLastStateLocked(int deviceId, int proxyState) { mLastStates.put(deviceId, proxyState); } @@ -429,7 +427,7 @@ public class ProxyManager { * Virtual Device, the app clients will get the aggregated event types for all proxy-ed displays * belonging to a VirtualDevice. */ - public void updateRelevantEventTypesLocked(int deviceId) { + private void updateRelevantEventTypesLocked(int deviceId) { if (!isProxyedDeviceId(deviceId)) { return; } @@ -452,7 +450,7 @@ public class ProxyManager { /** * Returns the relevant event types for a Client. */ - int computeRelevantEventTypesLocked(AccessibilityManagerService.Client client) { + public int computeRelevantEventTypesLocked(AccessibilityManagerService.Client client) { int relevantEventTypes = 0; for (int i = 0; i < mProxyA11yServiceConnections.size(); i++) { final ProxyAccessibilityServiceConnection proxy = @@ -578,9 +576,8 @@ public class ProxyManager { /** * Updates the states of the app AccessibilityManagers. */ - public void scheduleUpdateProxyClientsIfNeededLocked(int deviceId) { - final int proxyState = getStateLocked(deviceId, - mUiAutomationManager.isUiAutomationRunningLocked()); + private void scheduleUpdateProxyClientsIfNeededLocked(int deviceId) { + final int proxyState = getStateLocked(deviceId); if (DEBUG) { Slog.v(LOG_TAG, "State for device id " + deviceId + " is " + proxyState); Slog.v(LOG_TAG, "Last state for device id " + deviceId + " is " @@ -606,7 +603,7 @@ public class ProxyManager { * * @see AccessibilityManager.AccessibilityServicesStateChangeListener */ - public void scheduleNotifyProxyClientsOfServicesStateChangeLocked(int deviceId) { + private void scheduleNotifyProxyClientsOfServicesStateChangeLocked(int deviceId) { if (DEBUG) { Slog.v(LOG_TAG, "Notify services state change at device id " + deviceId); } @@ -625,7 +622,7 @@ public class ProxyManager { /** * Updates the focus appearance of AccessibilityManagerClients. */ - public void updateFocusAppearanceLocked(int deviceId) { + private void updateFocusAppearanceLocked(int deviceId) { if (DEBUG) { Slog.v(LOG_TAG, "Update proxy focus appearance at device id " + deviceId); } @@ -764,7 +761,7 @@ public class ProxyManager { /** * Sets a Client device id if the app uid belongs to the virtual device. */ - public void updateDeviceIdsIfNeededLocked(int deviceId) { + private void updateDeviceIdsIfNeededLocked(int deviceId) { final RemoteCallbackList<IAccessibilityManagerClient> userClients = mSystemSupport.getCurrentUserClientsLocked(); final RemoteCallbackList<IAccessibilityManagerClient> globalClients = @@ -777,7 +774,7 @@ public class ProxyManager { /** * Updates the device ids of IAccessibilityManagerClients if needed. */ - public void updateDeviceIdsIfNeededLocked(int deviceId, + private void updateDeviceIdsIfNeededLocked(int deviceId, @NonNull RemoteCallbackList<IAccessibilityManagerClient> clients) { final VirtualDeviceManagerInternal localVdm = getLocalVdm(); if (localVdm == null) { @@ -809,14 +806,17 @@ public class ProxyManager { } } - void setAccessibilityInputFilter(AccessibilityInputFilter filter) { + /** + * Sets the input filter for enabling and disabling features for proxy displays. + */ + public void setAccessibilityInputFilter(AccessibilityInputFilter filter) { if (DEBUG) { Slog.v(LOG_TAG, "Set proxy input filter to " + filter); } mA11yInputFilter = filter; } - VirtualDeviceManagerInternal getLocalVdm() { + private VirtualDeviceManagerInternal getLocalVdm() { if (mLocalVdm == null) { mLocalVdm = LocalServices.getService(VirtualDeviceManagerInternal.class); } diff --git a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java index a13df475d25d..9747579fa231 100644 --- a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java +++ b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java @@ -36,6 +36,7 @@ import android.view.WindowManager; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import com.android.internal.R; +import com.android.internal.accessibility.util.AccessibilityUtils; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ScreenshotHelper; @@ -302,8 +303,10 @@ public class SystemActionPerformer { case AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT: return takeScreenshot(); case AccessibilityService.GLOBAL_ACTION_KEYCODE_HEADSETHOOK: - sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HEADSETHOOK, - InputDevice.SOURCE_KEYBOARD); + if (!AccessibilityUtils.interceptHeadsetHookForActiveCall(mContext)) { + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HEADSETHOOK, + InputDevice.SOURCE_KEYBOARD); + } return true; case AccessibilityService.GLOBAL_ACTION_DPAD_UP: sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_UP, diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java index bc5d6457c945..ac770439a524 100644 --- a/services/autofill/java/com/android/server/autofill/Helper.java +++ b/services/autofill/java/com/android/server/autofill/Helper.java @@ -16,13 +16,18 @@ package com.android.server.autofill; +import static com.android.server.autofill.Helper.sDebug; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.assist.AssistStructure; import android.app.assist.AssistStructure.ViewNode; import android.app.assist.AssistStructure.WindowNode; import android.content.ComponentName; +import android.content.Context; +import android.hardware.display.DisplayManager; import android.metrics.LogMaker; +import android.os.UserManager; import android.service.autofill.Dataset; import android.service.autofill.InternalSanitizer; import android.service.autofill.SaveInfo; @@ -30,6 +35,7 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; +import android.view.Display; import android.view.View; import android.view.WindowManager; import android.view.autofill.AutofillId; @@ -37,6 +43,7 @@ import android.view.autofill.AutofillValue; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.ArrayUtils; +import com.android.server.utils.Slogf; import java.io.PrintWriter; import java.util.ArrayDeque; @@ -281,6 +288,38 @@ public final class Helper { return true; } + /** + * Gets a context with the proper display id. + * + * <p>For most cases it will return the provided context, but on devices that + * {@link UserManager#isVisibleBackgroundUsersEnabled() support visible background users}, it + * will return a context with the display pased as parameter. + */ + static Context getDisplayContext(Context context, int displayId) { + if (!UserManager.isVisibleBackgroundUsersEnabled()) { + return context; + } + if (context.getDisplayId() == displayId) { + if (sDebug) { + Slogf.d(TAG, "getDisplayContext(): context %s already has displayId %d", context, + displayId); + } + return context; + } + if (sDebug) { + Slogf.d(TAG, "Creating context for display %d", displayId); + } + Display display = context.getSystemService(DisplayManager.class).getDisplay(displayId); + if (display == null) { + Slogf.wtf(TAG, "Could not get context with displayId %d, Autofill operations will " + + "probably fail)", displayId); + return context; + } + + return context.createDisplayContext(display); + } + + private interface ViewNodeFilter { boolean matches(ViewNode node); } diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 3ab5bca215dc..f83d7342b6e3 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -164,10 +164,12 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.ArrayUtils; +import com.android.server.LocalServices; import com.android.server.autofill.ui.AutoFillUI; import com.android.server.autofill.ui.InlineFillUi; import com.android.server.autofill.ui.PendingUi; import com.android.server.inputmethod.InputMethodManagerInternal; +import com.android.server.wm.ActivityTaskManagerInternal; import java.io.PrintWriter; import java.lang.annotation.Retention; @@ -214,7 +216,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState private final AutofillManagerServiceImpl mService; private final Handler mHandler; private final AutoFillUI mUi; - @NonNull private final Context mContext; + + /** + * Context associated with the session, it has the same {@link Context#getDisplayId() displayId} + * of the activity being autofilled. + */ + private final Context mContext; private final MetricsLogger mMetricsLogger = new MetricsLogger(); @@ -1352,7 +1359,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mHasCallback = hasCallback; mUiLatencyHistory = uiLatencyHistory; mWtfHistory = wtfHistory; - mContext = context; + int displayId = LocalServices.getService(ActivityTaskManagerInternal.class) + .getDisplayId(activityToken); + mContext = Helper.getDisplayContext(context, displayId); mComponentName = componentName; mCompatMode = compatMode; mSessionState = STATE_ACTIVE; @@ -3401,7 +3410,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final long saveUiDisplayStartTimestamp = SystemClock.elapsedRealtime(); getUiForShowing().showSaveUi(serviceLabel, serviceIcon, mService.getServicePackageName(), saveInfo, this, - mComponentName, this, userId, mPendingSaveUi, isUpdate, mCompatMode, + mComponentName, this, mContext, mPendingSaveUi, isUpdate, mCompatMode, response.getShowSaveDialogIcon()); mSaveEventLogger.maybeSetLatencySaveUiDisplayMillis( SystemClock.elapsedRealtime()- saveUiDisplayStartTimestamp); @@ -4272,7 +4281,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState getUiForShowing().showFillUi(filledId, response, filterText, mService.getServicePackageName(), mComponentName, - targetLabel, targetIcon, this, userId, id, mCompatMode); + targetLabel, targetIcon, this, mContext, id, mCompatMode); synchronized (mLock) { mPresentationStatsEventLogger.maybeSetCountShown( @@ -5453,6 +5462,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState pw.print(prefix); pw.print("uid: "); pw.println(uid); pw.print(prefix); pw.print("taskId: "); pw.println(taskId); pw.print(prefix); pw.print("flags: "); pw.println(mFlags); + pw.print(prefix); pw.print("displayId: "); pw.println(mContext.getDisplayId()); pw.print(prefix); pw.print("state: "); pw.println(sessionStateAsString(mSessionState)); pw.print(prefix); pw.print("mComponentName: "); pw.println(mComponentName); pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken); diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java index cfd66f1e7351..b3cbe45ea4a7 100644 --- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java +++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java @@ -23,7 +23,6 @@ import static com.android.server.autofill.Helper.sVerbose; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UserIdInt; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -53,6 +52,7 @@ import com.android.server.LocalServices; import com.android.server.UiModeManagerInternal; import com.android.server.UiThread; import com.android.server.autofill.Helper; +import com.android.server.utils.Slogf; import java.io.PrintWriter; @@ -198,6 +198,7 @@ public final class AutoFillUI { * @param serviceIcon icon of autofill service * @param callback identifier for the caller * @param userId the user associated wit the session + * @param context context with the proper state (like display id) to show the UI * @param sessionId id of the autofill session * @param compatMode whether the app is being autofilled in compatibility mode. */ @@ -205,11 +206,11 @@ public final class AutoFillUI { @Nullable String filterText, @Nullable String servicePackageName, @NonNull ComponentName componentName, @NonNull CharSequence serviceLabel, @NonNull Drawable serviceIcon, @NonNull AutoFillUiCallback callback, - @UserIdInt int userId, int sessionId, boolean compatMode) { + @NonNull Context context, int sessionId, boolean compatMode) { if (sDebug) { final int size = filterText == null ? 0 : filterText.length(); - Slog.d(TAG, "showFillUi(): id=" + focusedId + ", filter=" + size + " chars, userId=" - + userId); + Slogf.d(TAG, "showFillUi(): id=%s, filter=%d chars, displayId=%d", focusedId, size, + context.getDisplayId()); } final LogMaker log = Helper .newLogMaker(MetricsEvent.AUTOFILL_FILL_UI, componentName, servicePackageName, @@ -224,10 +225,8 @@ public final class AutoFillUI { return; } hideAllUiThread(callback); - mFillUi = new FillUi(mContext, userId, response, focusedId, - filterText, mOverlayControl, serviceLabel, serviceIcon, - mUiModeMgr.isNightMode(), - new FillUi.Callback() { + mFillUi = new FillUi(context, response, focusedId, filterText, mOverlayControl, + serviceLabel, serviceIcon, mUiModeMgr.isNightMode(), new FillUi.Callback() { @Override public void onResponsePicked(FillResponse response) { log.setType(MetricsEvent.TYPE_DETAIL); @@ -325,12 +324,12 @@ public final class AutoFillUI { public void showSaveUi(@NonNull CharSequence serviceLabel, @NonNull Drawable serviceIcon, @Nullable String servicePackageName, @NonNull SaveInfo info, @NonNull ValueFinder valueFinder, @NonNull ComponentName componentName, - @NonNull AutoFillUiCallback callback, @UserIdInt int userId, + @NonNull AutoFillUiCallback callback, @NonNull Context context, @NonNull PendingUi pendingSaveUi, boolean isUpdate, boolean compatMode, boolean showServiceIcon) { if (sVerbose) { - Slog.v(TAG, "showSaveUi(update=" + isUpdate + ") for " + componentName.toShortString() - + " and user " + userId + ": " + info); + Slogf.v(TAG, "showSaveUi(update=%b) for %s and display %d: %s", isUpdate, + componentName.toShortString(), context.getDisplayId(), info); } int numIds = 0; numIds += info.getRequiredIds() == null ? 0 : info.getRequiredIds().length; @@ -350,7 +349,7 @@ public final class AutoFillUI { } hideAllUiThread(callback); mSaveUiCallback = callback; - mSaveUi = new SaveUi(mContext, userId, pendingSaveUi, serviceLabel, serviceIcon, + mSaveUi = new SaveUi(context, pendingSaveUi, serviceLabel, serviceIcon, servicePackageName, componentName, info, valueFinder, mOverlayControl, new SaveUi.OnSaveListener() { @Override diff --git a/services/autofill/java/com/android/server/autofill/ui/DisplayHelper.java b/services/autofill/java/com/android/server/autofill/ui/DisplayHelper.java deleted file mode 100644 index 53534809a1ae..000000000000 --- a/services/autofill/java/com/android/server/autofill/ui/DisplayHelper.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.server.autofill.ui; - -import static com.android.server.autofill.Helper.sDebug; - -import android.annotation.UserIdInt; -import android.content.Context; -import android.hardware.display.DisplayManager; -import android.os.UserManager; -import android.view.Display; - -import com.android.server.LocalServices; -import com.android.server.pm.UserManagerInternal; -import com.android.server.utils.Slogf; - -/** - * Helper for display-related needs. - */ -final class DisplayHelper { - - private static final String TAG = "AutofillDisplayHelper"; - - private static final UserManagerInternal sUmi = LocalServices - .getService(UserManagerInternal.class); - - /** - * Gets a context with the proper display id set for the given user. - * - * <p>For most cases it will return the provided context, but on devices that - * {@link UserManager#isVisibleBackgroundUsersEnabled() support visible background users}, it - * will return a context with the display the user started visible on. - */ - static Context getDisplayContext(Context context, @UserIdInt int userId) { - if (!UserManager.isVisibleBackgroundUsersEnabled()) { - return context; - } - int displayId = sUmi.getMainDisplayAssignedToUser(userId); - if (sDebug) { - Slogf.d(TAG, "Creating context for display %d for user %d", displayId, userId); - } - Display display = context.getSystemService(DisplayManager.class).getDisplay(displayId); - if (display == null) { - Slogf.wtf(TAG, "Could not get display with id %d (which is associated with user %d; " - + "FillUi operations will probably fail", displayId, userId); - return context; - } - - return context.createDisplayContext(display); - } - - private DisplayHelper() { - throw new UnsupportedOperationException("Contains only static methods"); - } -} diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java index b651ae592866..129ce72e037d 100644 --- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java @@ -22,7 +22,6 @@ import static com.android.server.autofill.Helper.sVerbose; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UserIdInt; import android.content.Context; import android.content.IntentSender; import android.content.pm.PackageManager; @@ -61,6 +60,7 @@ import com.android.internal.R; import com.android.server.UiThread; import com.android.server.autofill.AutofillManagerService; import com.android.server.autofill.Helper; +import com.android.server.utils.Slogf; import java.io.PrintWriter; import java.util.ArrayList; @@ -134,14 +134,15 @@ final class FillUi { return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK); } - FillUi(@NonNull Context systemContext, @UserIdInt int userId, @NonNull FillResponse response, + FillUi(@NonNull Context context, @NonNull FillResponse response, @NonNull AutofillId focusedViewId, @Nullable String filterText, @NonNull OverlayControl overlayControl, @NonNull CharSequence serviceLabel, @NonNull Drawable serviceIcon, boolean nightMode, @NonNull Callback callback) { - if (sVerbose) Slog.v(TAG, "nightMode: " + nightMode); + if (sVerbose) { + Slogf.v(TAG, "nightMode: %b displayId: %d", nightMode, context.getDisplayId()); + } mThemeId = nightMode ? THEME_ID_DARK : THEME_ID_LIGHT; mCallback = callback; - Context context = DisplayHelper.getDisplayContext(systemContext, userId); mFullScreen = isFullScreen(context); mContext = new ContextThemeWrapper(context, mThemeId); diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java index aec0bdfa3a76..12042594fefb 100644 --- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java @@ -21,7 +21,6 @@ import static com.android.server.autofill.Helper.sVerbose; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UserIdInt; import android.app.Dialog; import android.app.PendingIntent; import android.content.ComponentName; @@ -71,6 +70,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.ArrayUtils; import com.android.server.UiThread; import com.android.server.autofill.Helper; +import com.android.server.utils.Slogf; import java.io.PrintWriter; import java.util.ArrayList; @@ -173,14 +173,15 @@ final class SaveUi { private boolean mDestroyed; - SaveUi(@NonNull Context systemContext, @UserIdInt int userId, @NonNull PendingUi pendingUi, + SaveUi(@NonNull Context context, @NonNull PendingUi pendingUi, @NonNull CharSequence serviceLabel, @NonNull Drawable serviceIcon, @Nullable String servicePackageName, @NonNull ComponentName componentName, @NonNull SaveInfo info, @NonNull ValueFinder valueFinder, @NonNull OverlayControl overlayControl, @NonNull OnSaveListener listener, boolean nightMode, boolean isUpdate, boolean compatMode, boolean showServiceIcon) { - Context context = DisplayHelper.getDisplayContext(systemContext, userId); - if (sVerbose) Slog.v(TAG, "nightMode: " + nightMode); + if (sVerbose) { + Slogf.v(TAG, "nightMode: %b displayId: %d", nightMode, context.getDisplayId()); + } mThemeId = nightMode ? THEME_ID_DARK : THEME_ID_LIGHT; mPendingUi = pendingUi; mListener = new OneActionThenDestroyListener(listener); diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index df3c95bdfaf3..678d58232f15 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -3866,7 +3866,7 @@ public final class ActiveServices { if (UserHandle.isCore(callingUid)) { return; } - final int callingUserId = UserHandle.getCallingUserId(); + final int callingUserId = UserHandle.getUserId(callingUid); if (callingUserId == userId || !mAm.mUserController.isSameProfileGroup(callingUserId, userId)) { return; diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index d140403f77c3..6360e2a0d089 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -167,7 +167,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub .onMalformedInput(CodingErrorAction.REPLACE) .onUnmappableCharacter(CodingErrorAction.REPLACE) .replaceWith("?"); - private static final int MAX_LOW_POWER_STATS_SIZE = 16384; + private static final int MAX_LOW_POWER_STATS_SIZE = 32768; private static final int POWER_STATS_QUERY_TIMEOUT_MILLIS = 2000; private static final String EMPTY = "Empty"; diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java index 0767218ec065..5c68e6759083 100644 --- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java +++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java @@ -242,8 +242,7 @@ class BroadcastProcessQueue { */ @Nullable public BroadcastRecord enqueueOrReplaceBroadcast(@NonNull BroadcastRecord record, - int recordIndex, boolean wouldBeSkipped, - @NonNull BroadcastConsumer deferredStatesApplyConsumer) { + int recordIndex, @NonNull BroadcastConsumer deferredStatesApplyConsumer) { // When updateDeferredStates() has already applied a deferred state to // all pending items, apply to this new broadcast too if (mLastDeferredStates && record.deferUntilActive @@ -252,8 +251,7 @@ class BroadcastProcessQueue { } if (record.isReplacePending()) { - final BroadcastRecord replacedBroadcastRecord = replaceBroadcast(record, recordIndex, - wouldBeSkipped); + final BroadcastRecord replacedBroadcastRecord = replaceBroadcast(record, recordIndex); if (replacedBroadcastRecord != null) { return replacedBroadcastRecord; } @@ -264,14 +262,13 @@ class BroadcastProcessQueue { SomeArgs newBroadcastArgs = SomeArgs.obtain(); newBroadcastArgs.arg1 = record; newBroadcastArgs.argi1 = recordIndex; - newBroadcastArgs.argi2 = (wouldBeSkipped ? 1 : 0); // Cross-broadcast prioritization policy: some broadcasts might warrant being // issued ahead of others that are already pending, for example if this new // broadcast is in a different delivery class or is tied to a direct user interaction // with implicit responsiveness expectations. getQueueForBroadcast(record).addLast(newBroadcastArgs); - onBroadcastEnqueued(record, recordIndex, wouldBeSkipped); + onBroadcastEnqueued(record, recordIndex); return null; } @@ -285,10 +282,9 @@ class BroadcastProcessQueue { * wasn't any broadcast that was replaced. */ @Nullable - private BroadcastRecord replaceBroadcast(@NonNull BroadcastRecord record, int recordIndex, - boolean wouldBeSkipped) { + private BroadcastRecord replaceBroadcast(@NonNull BroadcastRecord record, int recordIndex) { final ArrayDeque<SomeArgs> queue = getQueueForBroadcast(record); - return replaceBroadcastInQueue(queue, record, recordIndex, wouldBeSkipped); + return replaceBroadcastInQueue(queue, record, recordIndex); } /** @@ -302,15 +298,13 @@ class BroadcastProcessQueue { */ @Nullable private BroadcastRecord replaceBroadcastInQueue(@NonNull ArrayDeque<SomeArgs> queue, - @NonNull BroadcastRecord record, int recordIndex, - boolean wouldBeSkipped) { + @NonNull BroadcastRecord record, int recordIndex) { final Iterator<SomeArgs> it = queue.descendingIterator(); final Object receiver = record.receivers.get(recordIndex); while (it.hasNext()) { final SomeArgs args = it.next(); final BroadcastRecord testRecord = (BroadcastRecord) args.arg1; final int testRecordIndex = args.argi1; - final boolean testWouldBeSkipped = (args.argi2 == 1); final Object testReceiver = testRecord.receivers.get(testRecordIndex); if ((record.callingUid == testRecord.callingUid) && (record.userId == testRecord.userId) @@ -320,10 +314,9 @@ class BroadcastProcessQueue { // Exact match found; perform in-place swap args.arg1 = record; args.argi1 = recordIndex; - args.argi2 = (wouldBeSkipped ? 1 : 0); record.copyEnqueueTimeFrom(testRecord); - onBroadcastDequeued(testRecord, testRecordIndex, testWouldBeSkipped); - onBroadcastEnqueued(record, recordIndex, wouldBeSkipped); + onBroadcastDequeued(testRecord, testRecordIndex); + onBroadcastEnqueued(record, recordIndex); return testRecord; } } @@ -383,13 +376,12 @@ class BroadcastProcessQueue { final SomeArgs args = it.next(); final BroadcastRecord record = (BroadcastRecord) args.arg1; final int recordIndex = args.argi1; - final boolean recordWouldBeSkipped = (args.argi2 == 1); if (predicate.test(record, recordIndex)) { consumer.accept(record, recordIndex); if (andRemove) { args.recycle(); it.remove(); - onBroadcastDequeued(record, recordIndex, recordWouldBeSkipped); + onBroadcastDequeued(record, recordIndex); } else { // Even if we're leaving broadcast in queue, it may have // been mutated in such a way to change our runnable time @@ -539,12 +531,11 @@ class BroadcastProcessQueue { final SomeArgs next = removeNextBroadcast(); mActive = (BroadcastRecord) next.arg1; mActiveIndex = next.argi1; - final boolean wouldBeSkipped = (next.argi2 == 1); mActiveCountSinceIdle++; mActiveViaColdStart = false; mActiveWasStopped = false; next.recycle(); - onBroadcastDequeued(mActive, mActiveIndex, wouldBeSkipped); + onBroadcastDequeued(mActive, mActiveIndex); } /** @@ -561,8 +552,7 @@ class BroadcastProcessQueue { /** * Update summary statistics when the given record has been enqueued. */ - private void onBroadcastEnqueued(@NonNull BroadcastRecord record, int recordIndex, - boolean wouldBeSkipped) { + private void onBroadcastEnqueued(@NonNull BroadcastRecord record, int recordIndex) { mCountEnqueued++; if (record.deferUntilActive) { mCountDeferred++; @@ -594,8 +584,7 @@ class BroadcastProcessQueue { if (record.callerInstrumented) { mCountInstrumented++; } - if (!wouldBeSkipped - && (record.receivers.get(recordIndex) instanceof ResolveInfo)) { + if (record.receivers.get(recordIndex) instanceof ResolveInfo) { mCountManifest++; } invalidateRunnableAt(); @@ -604,8 +593,7 @@ class BroadcastProcessQueue { /** * Update summary statistics when the given record has been dequeued. */ - private void onBroadcastDequeued(@NonNull BroadcastRecord record, int recordIndex, - boolean wouldBeSkipped) { + private void onBroadcastDequeued(@NonNull BroadcastRecord record, int recordIndex) { mCountEnqueued--; if (record.deferUntilActive) { mCountDeferred--; @@ -637,8 +625,7 @@ class BroadcastProcessQueue { if (record.callerInstrumented) { mCountInstrumented--; } - if (!wouldBeSkipped - && (record.receivers.get(recordIndex) instanceof ResolveInfo)) { + if (record.receivers.get(recordIndex) instanceof ResolveInfo) { mCountManifest--; } invalidateRunnableAt(); diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index 8735f8a37b8b..96e152320282 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -606,24 +606,18 @@ class BroadcastQueueModernImpl extends BroadcastQueue { final BroadcastProcessQueue queue = getOrCreateProcessQueue( getReceiverProcessName(receiver), getReceiverUid(receiver)); - boolean wouldBeSkipped = false; - if (receiver instanceof ResolveInfo) { - // If the app is running but would not have been started if the process weren't - // running, we're going to deliver the broadcast but mark that it's not a manifest - // broadcast that would have started the app. This allows BroadcastProcessQueue to - // defer the broadcast as though it were a normal runtime receiver. - wouldBeSkipped = (mSkipPolicy.shouldSkipMessage(r, receiver) != null); - if (wouldBeSkipped && queue.app == null && !queue.getActiveViaColdStart()) { - // Skip receiver if there's no running app, the app is not being started, and - // the app wouldn't be launched for this broadcast - setDeliveryState(null, null, r, i, receiver, BroadcastRecord.DELIVERY_SKIPPED, - "skipped by policy to avoid cold start"); - continue; - } + // If this receiver is going to be skipped, skip it now itself and don't even enqueue + // it. + final boolean wouldBeSkipped = (mSkipPolicy.shouldSkipMessage(r, receiver) != null); + if (wouldBeSkipped) { + setDeliveryState(null, null, r, i, receiver, BroadcastRecord.DELIVERY_SKIPPED, + "skipped by policy at enqueue"); + continue; } + enqueuedBroadcast = true; final BroadcastRecord replacedBroadcast = queue.enqueueOrReplaceBroadcast( - r, i, wouldBeSkipped, mBroadcastConsumerDeferApply); + r, i, mBroadcastConsumerDeferApply); if (replacedBroadcast != null) { replacedBroadcasts.add(replacedBroadcast); } diff --git a/services/core/java/com/android/server/broadcastradio/RadioServiceUserController.java b/services/core/java/com/android/server/broadcastradio/RadioServiceUserController.java index 38b323395329..4b847a27c4de 100644 --- a/services/core/java/com/android/server/broadcastradio/RadioServiceUserController.java +++ b/services/core/java/com/android/server/broadcastradio/RadioServiceUserController.java @@ -39,18 +39,24 @@ public final class RadioServiceUserController { */ public static boolean isCurrentOrSystemUser() { int callingUser = Binder.getCallingUserHandle().getIdentifier(); + return callingUser == getCurrentUser() || callingUser == UserHandle.USER_SYSTEM; + } + + /** + * Get current foreground user for Broadcast Radio Service + * + * @return foreground user id. + */ + public static int getCurrentUser() { final long identity = Binder.clearCallingIdentity(); + int userId = UserHandle.USER_NULL; try { - int currentUser = ActivityManager.getCurrentUser(); - if (callingUser != currentUser && callingUser != UserHandle.USER_SYSTEM) { - return false; - } - return true; + userId = ActivityManager.getCurrentUser(); } catch (RuntimeException e) { // Activity manager not running, nothing we can do assume user 0. } finally { Binder.restoreCallingIdentity(identity); } - return false; + return userId; } } diff --git a/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java b/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java index 132fb8ef8a95..7c87c6c55289 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java @@ -36,11 +36,13 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; +import android.os.UserHandle; import android.util.ArraySet; import android.util.IndentingPrintWriter; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.broadcastradio.RadioServiceUserController; import com.android.server.utils.Slogf; import java.util.ArrayList; @@ -419,8 +421,13 @@ final class RadioModule { @GuardedBy("mLock") private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) { + int currentUserId = RadioServiceUserController.getCurrentUser(); List<TunerSession> deadSessions = null; for (int i = 0; i < mAidlTunerSessions.size(); i++) { + if (mAidlTunerSessions.valueAt(i).mUserId != currentUserId + && mAidlTunerSessions.valueAt(i).mUserId != UserHandle.USER_SYSTEM) { + continue; + } try { runnable.run(mAidlTunerSessions.valueAt(i).mCallback, mAidlTunerSessions.valueAt(i).getUid()); diff --git a/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java b/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java index 0a3823f038fa..beff7bd3cffd 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java @@ -46,6 +46,7 @@ final class TunerSession extends ITuner.Stub { private final RadioLogger mLogger; private final RadioModule mModule; + final int mUserId; final android.hardware.radio.ITunerCallback mCallback; private final int mUid; private final IBroadcastRadio mService; @@ -65,6 +66,7 @@ final class TunerSession extends ITuner.Stub { android.hardware.radio.ITunerCallback callback) { mModule = Objects.requireNonNull(radioModule, "radioModule cannot be null"); mService = Objects.requireNonNull(service, "service cannot be null"); + mUserId = Binder.getCallingUserHandle().getIdentifier(); mCallback = Objects.requireNonNull(callback, "callback cannot be null"); mUid = Binder.getCallingUid(); mLogger = new RadioLogger(TAG, TUNER_EVENT_LOGGER_QUEUE_SIZE); diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java index 59a81544d8ef..7b5cb898b6b5 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java @@ -38,12 +38,14 @@ import android.os.DeadObjectException; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; +import android.os.UserHandle; import android.util.IndentingPrintWriter; import android.util.MutableInt; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.broadcastradio.RadioServiceUserController; import java.util.ArrayList; import java.util.HashSet; @@ -374,8 +376,13 @@ final class RadioModule { @GuardedBy("mLock") private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) { + int currentUserId = RadioServiceUserController.getCurrentUser(); List<TunerSession> deadSessions = null; for (TunerSession tunerSession : mAidlTunerSessions) { + if (tunerSession.mUserId != currentUserId && tunerSession.mUserId + != UserHandle.USER_SYSTEM) { + continue; + } try { runnable.run(tunerSession.mCallback); } catch (DeadObjectException ex) { diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java index 204b9649135e..1efc4a50aa08 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java @@ -26,6 +26,7 @@ import android.hardware.radio.ITuner; import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; +import android.os.Binder; import android.os.RemoteException; import android.util.ArrayMap; import android.util.IndentingPrintWriter; @@ -52,6 +53,7 @@ class TunerSession extends ITuner.Stub { private final RadioModule mModule; private final ITunerSession mHwSession; + final int mUserId; final android.hardware.radio.ITunerCallback mCallback; @GuardedBy("mLock") @@ -68,6 +70,7 @@ class TunerSession extends ITuner.Stub { @NonNull android.hardware.radio.ITunerCallback callback) { mModule = Objects.requireNonNull(module); mHwSession = Objects.requireNonNull(hwSession); + mUserId = Binder.getCallingUserHandle().getIdentifier(); mCallback = Objects.requireNonNull(callback); mEventLogger = new RadioEventLogger(TAG, TUNER_EVENT_LOGGER_QUEUE_SIZE); } diff --git a/services/core/java/com/android/server/cpu/CpuMonitorService.java b/services/core/java/com/android/server/cpu/CpuMonitorService.java index df8cfad4ab03..7ea2c1b02040 100644 --- a/services/core/java/com/android/server/cpu/CpuMonitorService.java +++ b/services/core/java/com/android/server/cpu/CpuMonitorService.java @@ -653,8 +653,17 @@ public final class CpuMonitorService extends SystemService { } public int getAverageAvailableCpuFreqPercent() { - return (int) ((totalNormalizedAvailableCpuFreqKHz * 100.0) + int percent = (int) ((totalNormalizedAvailableCpuFreqKHz * 100.0) / totalOnlineMaxCpuFreqKHz); + if (percent < 0) { + // TODO(b/279478586): This case should never happen. But this case happens + // rarely on certain hardware, which indicates a deeper issue. Once this + // issue is reproduced, use this log to debug the issue and fix it. + Slogf.wtf(TAG, "Computed negative CPU availability percent(%d) for %s ", + percent, toString()); + return 0; + } + return percent; } @Override diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java index a3f8c4d16cd1..7574de841440 100644 --- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java +++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java @@ -437,6 +437,7 @@ public final class DisplayBrightnessController { * persist the nit value, the nit value for the default display will be loaded. */ private void loadNitBasedBrightnessSetting() { + float currentBrightnessSetting = Float.NaN; if (mDisplayId == Display.DEFAULT_DISPLAY && mPersistBrightnessNitsForDefaultDisplay) { float brightnessNitsForDefaultDisplay = mBrightnessSetting.getBrightnessNitsForDefaultDisplay(); @@ -445,15 +446,17 @@ public final class DisplayBrightnessController { brightnessNitsForDefaultDisplay); if (BrightnessUtils.isValidBrightnessValue(brightnessForDefaultDisplay)) { mBrightnessSetting.setBrightness(brightnessForDefaultDisplay); - synchronized (mLock) { - mCurrentScreenBrightness = brightnessForDefaultDisplay; - } - return; + currentBrightnessSetting = brightnessForDefaultDisplay; } } } + + if (Float.isNaN(currentBrightnessSetting)) { + currentBrightnessSetting = getScreenBrightnessSetting(); + } + synchronized (mLock) { - mCurrentScreenBrightness = getScreenBrightnessSetting(); + mCurrentScreenBrightness = currentBrightnessSetting; } } } diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java index 7a51126eff2d..377b8cf1230e 100644 --- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java +++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java @@ -395,8 +395,8 @@ public final class MediaProjectionManagerService extends SystemService synchronized (mLock) { final boolean consentGranted = consentResult == RECORD_CONTENT_DISPLAY || consentResult == RECORD_CONTENT_TASK; - if (consentGranted && projection == null || !isCurrentProjection( - projection.asBinder())) { + if (consentGranted && !isCurrentProjection( + projection == null ? null : projection.asBinder())) { Slog.v(TAG, "Reusing token: Ignore consent result of " + consentResult + " for a " + "token that isn't current"); return; diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 402fb30437b0..9b1a80bed17b 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -1120,12 +1120,12 @@ public class LauncherAppsService extends SystemService { return shortcutOverridesInfo; } - List<String> packagesToOverride = + Map<String, String> packagesToOverride = DevicePolicyCache.getInstance().getLauncherShortcutOverrides(); - for (String packageName : packagesToOverride) { + for (Map.Entry<String, String> packageNames : packagesToOverride.entrySet()) { Intent intent = new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_LAUNCHER) - .setPackage(packageName); + .setPackage(packageNames.getValue()); List<LauncherActivityInfoInternal> possibleShortcutOverrides = queryIntentLauncherActivities( @@ -1135,7 +1135,8 @@ public class LauncherAppsService extends SystemService { ); if (!possibleShortcutOverrides.isEmpty()) { - shortcutOverridesInfo.put(packageName, possibleShortcutOverrides.get(0)); + shortcutOverridesInfo.put(packageNames.getKey(), + possibleShortcutOverrides.get(0)); } } return shortcutOverridesInfo; diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index b669ba238880..84a9888d2458 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -1716,6 +1716,11 @@ public class ShortcutService extends IShortcutService.Stub { if (si == null) { return; } + + if (isCallerSystem()) { + return; // no check + } + if (!Objects.equals(callerPackage, si.getPackage())) { android.util.EventLog.writeEvent(0x534e4554, "109824443", -1, ""); throw new SecurityException("Shortcut package name mismatch"); diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 51872b339c40..98d2d3d4b997 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -803,6 +803,20 @@ public class WallpaperManagerService extends IWallpaperManager.Stub protected WallpaperData mLastLockWallpaper; private IWallpaperManagerCallback mKeyguardListener; private boolean mWaitingForUnlock; + + /** + * Flag set to true after reboot if the home wallpaper is waiting for the device to be unlocked. + * This happens for wallpapers that are not direct-boot aware; they can only be rendered after + * the user unlocks the device for the first time after a reboot. In the meantime, the default + * wallpaper is shown instead. + */ + private boolean mHomeWallpaperWaitingForUnlock; + + /** + * Flag set to true after reboot if the lock wallpaper is waiting for the device to be unlocked. + */ + private boolean mLockWallpaperWaitingForUnlock; + private boolean mShuttingDown; /** @@ -1790,7 +1804,23 @@ public class WallpaperManagerService extends IWallpaperManager.Stub public void onUnlockUser(final int userId) { synchronized (mLock) { if (mCurrentUserId == userId) { - if (mWaitingForUnlock) { + if (mIsLockscreenLiveWallpaperEnabled) { + if (mHomeWallpaperWaitingForUnlock) { + final WallpaperData systemWallpaper = + getWallpaperSafeLocked(userId, FLAG_SYSTEM); + switchWallpaper(systemWallpaper, null); + // TODO(b/278261563): call notifyCallbacksLocked inside switchWallpaper + notifyCallbacksLocked(systemWallpaper); + } + if (mLockWallpaperWaitingForUnlock) { + final WallpaperData lockWallpaper = + getWallpaperSafeLocked(userId, FLAG_LOCK); + switchWallpaper(lockWallpaper, null); + notifyCallbacksLocked(lockWallpaper); + } + } + + if (mWaitingForUnlock && !mIsLockscreenLiveWallpaperEnabled) { // the desired wallpaper is not direct-boot aware, load it now final WallpaperData systemWallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM); @@ -1845,13 +1875,23 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } mCurrentUserId = userId; systemWallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM); - final WallpaperData tmpLockWallpaper = mLockWallpaperMap.get(userId); - lockWallpaper = tmpLockWallpaper == null ? systemWallpaper : tmpLockWallpaper; + + if (mIsLockscreenLiveWallpaperEnabled) { + lockWallpaper = systemWallpaper.mWhich == (FLAG_LOCK | FLAG_SYSTEM) + ? systemWallpaper : getWallpaperSafeLocked(userId, FLAG_LOCK); + } else { + final WallpaperData tmpLockWallpaper = mLockWallpaperMap.get(userId); + lockWallpaper = tmpLockWallpaper == null ? systemWallpaper : tmpLockWallpaper; + } + // Not started watching yet, in case wallpaper data was loaded for other reasons. if (systemWallpaper.wallpaperObserver == null) { systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper); systemWallpaper.wallpaperObserver.startWatching(); } + if (mIsLockscreenLiveWallpaperEnabled && lockWallpaper != systemWallpaper) { + switchWallpaper(lockWallpaper, null); + } switchWallpaper(systemWallpaper, reply); } @@ -1870,6 +1910,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub void switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply) { synchronized (mLock) { mWaitingForUnlock = false; + if (mIsLockscreenLiveWallpaperEnabled) { + if ((wallpaper.mWhich & FLAG_SYSTEM) != 0) mHomeWallpaperWaitingForUnlock = false; + if ((wallpaper.mWhich & FLAG_LOCK) != 0) mLockWallpaperWaitingForUnlock = false; + } + final ComponentName cname = wallpaper.wallpaperComponent != null ? wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent; if (!bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) { @@ -1882,6 +1927,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } catch (RemoteException ignored) { } + if (mIsLockscreenLiveWallpaperEnabled) { + onSwitchWallpaperFailLocked(wallpaper, reply, si); + return; + } + if (si == null) { Slog.w(TAG, "Failure starting previous wallpaper; clearing"); clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, reply); @@ -1899,6 +1949,43 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } + /** + * Fallback method if a wallpaper fails to load on boot or after a user switch. + * Only called if mIsLockscreenLiveWallpaperEnabled is true. + */ + private void onSwitchWallpaperFailLocked( + WallpaperData wallpaper, IRemoteCallback reply, ServiceInfo serviceInfo) { + + if (serviceInfo == null) { + Slog.w(TAG, "Failure starting previous wallpaper; clearing"); + + if (wallpaper.mWhich == (FLAG_LOCK | FLAG_SYSTEM)) { + clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null); + clearWallpaperLocked(false, FLAG_LOCK, wallpaper.userId, reply); + } else { + clearWallpaperLocked(false, wallpaper.mWhich, wallpaper.userId, reply); + } + return; + } + Slog.w(TAG, "Wallpaper isn't direct boot aware; using fallback until unlocked"); + // We might end up persisting the current wallpaper data + // while locked, so pretend like the component was actually + // bound into place + wallpaper.wallpaperComponent = wallpaper.nextWallpaperComponent; + final WallpaperData fallback = new WallpaperData(wallpaper.userId, wallpaper.mWhich); + + // files from the previous static wallpaper may still be stored in memory. + // delete them in order to show the default wallpaper. + if (wallpaper.wallpaperFile.exists()) { + wallpaper.wallpaperFile.delete(); + wallpaper.cropFile.delete(); + } + + bindWallpaperComponentLocked(mImageWallpaper, true, false, fallback, reply); + if ((wallpaper.mWhich & FLAG_SYSTEM) != 0) mHomeWallpaperWaitingForUnlock = true; + if ((wallpaper.mWhich & FLAG_LOCK) != 0) mLockWallpaperWaitingForUnlock = true; + } + @Override public void clearWallpaper(String callingPackage, int which, int userId) { if (DEBUG) Slog.v(TAG, "clearWallpaper"); diff --git a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java index 32f7b9682fb7..5c929a93bf12 100644 --- a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java +++ b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java @@ -239,7 +239,17 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, } return null; } - source.getBounds(mTmpRect); + mTmpRect.setEmpty(); + if (source.mTransitionController.inFinishingTransition(source)) { + final Transition.ChangeInfo changeInfo = source.mTransitionController + .mFinishingTransition.mChanges.get(source); + if (changeInfo != null) { + mTmpRect.set(changeInfo.mAbsoluteBounds); + } + } + if (mTmpRect.isEmpty()) { + source.getBounds(mTmpRect); + } mTmpRect.offsetTo(0, 0); SurfaceControl[] excludeLayers; final WindowState imeWindow = source.getDisplayContent().mInputMethodWindow; diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index f843b7c5e3ab..78c066bdc212 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -5296,6 +5296,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (isCollecting) { mTransitionController.collect(this); } else { + // Failsafe to make sure that we show any activities that were incorrectly hidden + // during a transition. If this vis-change is a result of finishing, ignore it. + // Finish should only ever commit visibility=false, so we can check full containment + // rather than just direct membership. inFinishingTransition = mTransitionController.inFinishingTransition(this); if (!inFinishingTransition && !mDisplayContent.isSleeping()) { Slog.e(TAG, "setVisibility=" + visible diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 4949ebc46b80..3f4a775bc37a 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -755,4 +755,10 @@ public abstract class ActivityTaskManagerInternal { /** Unregister a task stack listener so that it stops receiving callbacks. */; public abstract void unregisterTaskStackListener(ITaskStackListener listener); + + /** + * Gets the id of the display the activity was launched on. + * @param token The activity token. + */ + public abstract int getDisplayId(IBinder token); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index b37703204b7b..1f4606b09396 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -5816,6 +5816,18 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override + public int getDisplayId(IBinder token) { + synchronized (mGlobalLock) { + ActivityRecord r = ActivityRecord.forTokenLocked(token); + if (r == null) { + throw new IllegalArgumentException( + "setFocusedActivity: No activity record matching token=" + token); + } + return r.getDisplayId(); + } + } + + @Override public void registerScreenObserver(ScreenObserver observer) { mScreenObservers.add(observer); } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 747819e93ff2..ce4362853b23 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -1882,6 +1882,12 @@ public class DisplayPolicy { static final int DECOR_TYPES = Type.displayCutout() | Type.navigationBars(); + /** + * The types that may affect display configuration. This excludes cutout because it is + * known from display info. + */ + static final int CONFIG_TYPES = Type.statusBars() | Type.navigationBars(); + private final DisplayContent mDisplayContent; private final Info[] mInfoForRotation = new Info[4]; final Info mTmpInfo = new Info(); @@ -1921,7 +1927,7 @@ public class DisplayPolicy { final DecorInsets.Info newInfo = mDecorInsets.mTmpInfo; newInfo.update(mDisplayContent, rotation, dw, dh); final DecorInsets.Info currentInfo = getDecorInsetsInfo(rotation, dw, dh); - if (newInfo.mNonDecorFrame.equals(currentInfo.mNonDecorFrame)) { + if (newInfo.mConfigFrame.equals(currentInfo.mConfigFrame)) { return false; } mDecorInsets.invalidate(); diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index a5e652cce41e..a3d233df7b61 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -123,6 +123,7 @@ public class DisplayRotation { public final boolean isDefaultDisplay; private final boolean mSupportAutoRotation; + private final boolean mAllowRotationResolver; private final int mLidOpenRotation; private final int mCarDockRotation; private final int mDeskDockRotation; @@ -272,6 +273,8 @@ public class DisplayRotation { mSupportAutoRotation = mContext.getResources().getBoolean(R.bool.config_supportAutoRotation); + mAllowRotationResolver = + mContext.getResources().getBoolean(R.bool.config_allowRotationResolver); mLidOpenRotation = readRotation(R.integer.config_lidOpenRotation); mCarDockRotation = readRotation(R.integer.config_carDockRotation); mDeskDockRotation = readRotation(R.integer.config_deskDockRotation); @@ -2041,7 +2044,8 @@ public class DisplayRotation { @Override public boolean isRotationResolverEnabled() { - return mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE + return mAllowRotationResolver + && mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE && mCameraRotationMode == CAMERA_ROTATION_ENABLED && !mService.mPowerManager.isPowerSaveMode(); } diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index b879d1a8ec56..eb639b6f2033 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -362,15 +362,8 @@ class RemoteAnimationController implements DeathRecipient { private void invokeAnimationCancelled(String reason) { ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "cancelAnimation(): reason=%s", reason); - final boolean isKeyguardOccluded = mDisplayContent.isKeyguardOccluded(); - try { - EventLogTags.writeWmSetKeyguardOccluded( - isKeyguardOccluded ? 1 : 0, - 0 /* animate */, - 0 /* transit */, - "onAnimationCancelled"); - mRemoteAnimationAdapter.getRunner().onAnimationCancelled(isKeyguardOccluded); + mRemoteAnimationAdapter.getRunner().onAnimationCancelled(); } catch (RemoteException e) { Slog.e(TAG, "Failed to notify cancel", e); } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index abc9f8a48584..d531ad175f10 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -244,6 +244,16 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { private IContainerFreezer mContainerFreezer = null; private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction(); + /** + * {@code true} if some other operation may have caused the originally-recorded state (in + * mChanges) to be dirty. This is usually due to finishTransition being called mid-collect; + * and, the reason that finish can alter the "start" state of other transitions is because + * setVisible(false) is deferred until then. + * Instead of adding this conditional, we could re-check always; but, this situation isn't + * common so it'd be wasted work. + */ + boolean mPriorVisibilityMightBeDirty = false; + final TransitionController.Logger mLogger = new TransitionController.Logger(); /** Whether this transition was forced to play early (eg for a SLEEP signal). */ @@ -966,28 +976,30 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { mController.mFinishingTransition = this; if (mTransientHideTasks != null && !mTransientHideTasks.isEmpty()) { - // Record all the now-hiding activities so that they are committed after - // recalculating visibilities. We just use mParticipants because we can and it will - // ensure proper reporting of `isInFinishTransition`. + // The transient hide tasks could be occluded now, e.g. returning to home. So trigger + // the update to make the activities in the tasks invisible-requested, then the next + // step can continue to commit the visibility. + mController.mAtm.mRootWindowContainer.ensureActivitiesVisible(null /* starting */, + 0 /* configChanges */, true /* preserveWindows */); + // Record all the now-hiding activities so that they are committed. Just use + // mParticipants because we can avoid a new list this way. for (int i = 0; i < mTransientHideTasks.size(); ++i) { + // Only worry about tasks that were actually hidden. Otherwise, we could end-up + // committing visibility for activity-level changes that aren't part of this + // transition. + if (mTransientHideTasks.get(i).isVisibleRequested()) continue; mTransientHideTasks.get(i).forAllActivities(r -> { // Only check leaf-tasks that were collected if (!mParticipants.contains(r.getTask())) return; - // Only concern ourselves with anything that can become invisible - if (!r.isVisible()) return; mParticipants.add(r); }); } - // The transient hide tasks could be occluded now, e.g. returning to home. So trigger - // the update to make the activities in the tasks invisible-requested, then the next - // step can continue to commit the visibility. - mController.mAtm.mRootWindowContainer.ensureActivitiesVisible(null /* starting */, - 0 /* configChanges */, true /* preserveWindows */); } boolean hasParticipatedDisplay = false; boolean hasVisibleTransientLaunch = false; boolean enterAutoPip = false; + boolean committedSomeInvisible = false; // Commit all going-invisible containers for (int i = 0; i < mParticipants.size(); ++i) { final WindowContainer<?> participant = mParticipants.valueAt(i); @@ -1023,6 +1035,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } ar.commitVisibility(false /* visible */, false /* performLayout */, true /* fromTransition */); + committedSomeInvisible = true; } else { enterAutoPip = true; } @@ -1081,6 +1094,9 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } } } + if (committedSomeInvisible) { + mController.onCommittedInvisibles(); + } if (hasVisibleTransientLaunch) { // Notify the change about the transient-below task if entering auto-pip. @@ -1293,6 +1309,9 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { // leftover order changes. collectOrderChanges(mController.mWaitingTransitions.isEmpty()); + if (mPriorVisibilityMightBeDirty) { + updatePriorVisibility(); + } // Resolve the animating targets from the participants. mTargets = calculateTargets(mParticipants, mChanges); // Check whether the participants were animated from back navigation. @@ -1806,6 +1825,20 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } } + private void updatePriorVisibility() { + for (int i = 0; i < mChanges.size(); ++i) { + final ChangeInfo chg = mChanges.valueAt(i); + // For task/activity, recalculate the current "real" visibility. + if (chg.mContainer.asActivityRecord() == null && chg.mContainer.asTask() == null) { + continue; + } + // This ONLY works in the visible -> invisible case (and is only needed for this case) + // because commitVisible(false) is deferred until finish. + if (!chg.mVisible) continue; + chg.mVisible = chg.mContainer.isVisible(); + } + } + /** * Under some conditions (eg. all visible targets within a parent container are transitioning * the same way) the transition can be "promoted" to the parent container. This means an diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index b0feefe2a3b0..7950edaaa267 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -408,9 +408,9 @@ class TransitionController { return false; } - /** Returns {@code true} if the `wc` is a participant of the finishing transition. */ + /** Returns {@code true} if the finishing transition contains `wc`. */ boolean inFinishingTransition(WindowContainer<?> wc) { - return mFinishingTransition != null && mFinishingTransition.mParticipants.contains(wc); + return mFinishingTransition != null && mFinishingTransition.isInTransition(wc); } /** @return {@code true} if a transition is running */ @@ -827,6 +827,16 @@ class TransitionController { } } + /** Called by {@link Transition#finishTransition} if it committed invisible to any activities */ + void onCommittedInvisibles() { + if (mCollectingTransition != null) { + mCollectingTransition.mPriorVisibilityMightBeDirty = true; + } + for (int i = mWaitingTransitions.size() - 1; i >= 0; --i) { + mWaitingTransitions.get(i).mPriorVisibilityMightBeDirty = true; + } + } + private void validateStates() { for (int i = 0; i < mStateValidators.size(); ++i) { mStateValidators.get(i).run(); @@ -964,6 +974,7 @@ class TransitionController { if (sync) { info.setFlags(info.getFlags() | TransitionInfo.FLAG_SYNC); } + transition.mAnimationTrack = track; info.setTrack(track); mTrackCount = Math.max(mTrackCount, track + 1); } diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index f4a1765d4663..510e6756b8ef 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -3839,7 +3839,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< // This can still happen if WMCore starts a new transition when there is ongoing // sync transaction from Shell. Please file a bug if it happens. throw new IllegalStateException("Can't sync on 2 groups simultaneously" - + " currentSyncId=" + mSyncGroup.mSyncId + " newSyncId=" + group.mSyncId); + + " currentSyncId=" + mSyncGroup.mSyncId + " newSyncId=" + group.mSyncId + + " wc=" + this); } mSyncGroup = group; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 40b8274d4e51..6cb6d9d7bcea 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1831,7 +1831,7 @@ public class WindowManagerService extends IWindowManager.Stub boolean needToSendNewConfiguration = win.isVisibleRequestedOrAdding() && displayContent.updateOrientation(); - if (win.providesNonDecorInsets()) { + if (win.providesDisplayDecorInsets()) { needToSendNewConfiguration |= displayPolicy.updateDecorInsetsInfo(); } if (needToSendNewConfiguration) { @@ -2274,7 +2274,7 @@ public class WindowManagerService extends IWindowManager.Stub & WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED) != 0) { win.mLayoutNeeded = true; } - if (layoutChanged && win.providesNonDecorInsets()) { + if (layoutChanged && win.providesDisplayDecorInsets()) { configChanged = displayPolicy.updateDecorInsetsInfo(); } if (win.mActivityRecord != null && ((flagChanges & FLAG_SHOW_WHEN_LOCKED) != 0 diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 2920652674d3..6f07b7719be0 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1834,13 +1834,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return (mPolicyVisibility & POLICY_VISIBILITY_ALL) == POLICY_VISIBILITY_ALL; } - boolean providesNonDecorInsets() { + boolean providesDisplayDecorInsets() { if (mInsetsSourceProviders == null) { return false; } for (int i = mInsetsSourceProviders.size() - 1; i >= 0; i--) { final InsetsSource source = mInsetsSourceProviders.valueAt(i).getSource(); - if (source.getType() == WindowInsets.Type.navigationBars()) { + if ((source.getType() & DisplayPolicy.DecorInsets.CONFIG_TYPES) != 0) { return true; } } @@ -2507,13 +2507,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } // Check if window provides non decor insets before clearing its provided insets. - final boolean windowProvidesNonDecorInsets = providesNonDecorInsets(); + final boolean windowProvidesDisplayDecorInsets = providesDisplayDecorInsets(); removeImmediately(); // Removing a visible window may affect the display orientation so just update it if // needed. Also recompute configuration if it provides screen decor insets. boolean needToSendNewConfiguration = wasVisible && displayContent.updateOrientation(); - if (windowProvidesNonDecorInsets) { + if (windowProvidesDisplayDecorInsets) { needToSendNewConfiguration |= displayContent.getDisplayPolicy().updateDecorInsetsInfo(); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java index 80100a927e82..c681b884d2ed 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java @@ -19,13 +19,13 @@ import android.annotation.UserIdInt; import android.app.admin.DevicePolicyCache; import android.app.admin.DevicePolicyManager; import android.os.UserHandle; +import android.util.ArrayMap; import android.util.IndentingPrintWriter; import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; -import java.util.ArrayList; -import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -55,8 +55,7 @@ public class DevicePolicyCacheImpl extends DevicePolicyCache { private final SparseIntArray mPermissionPolicy = new SparseIntArray(); @GuardedBy("mLock") - private List<String> mLauncherShortcutOverrides = - new ArrayList<>(); + private ArrayMap<String, String> mLauncherShortcutOverrides = new ArrayMap<>(); /** Maps to {@code ActiveAdmin.mAdminCanGrantSensorsPermissions}. */ @@ -130,18 +129,20 @@ public class DevicePolicyCacheImpl extends DevicePolicyCache { } @Override - public List<String> getLauncherShortcutOverrides() { + public Map<String, String> getLauncherShortcutOverrides() { synchronized (mLock) { - return new ArrayList<>(mLauncherShortcutOverrides); + return new ArrayMap<>(mLauncherShortcutOverrides); } } /** - * Sets a list of packages for which shortcuts should be replaced by their badged version. + * Sets a map of packages names to package names, for which all launcher shortcuts which + * match a key package name should be modified to launch the corresponding value package + * name in the managed profile. The overridden shortcut should be badged accordingly. */ - public void setLauncherShortcutOverrides(List<String> launcherShortcutOverrides) { + public void setLauncherShortcutOverrides(ArrayMap<String, String> launcherShortcutOverrides) { synchronized (mLock) { - mLauncherShortcutOverrides = new ArrayList<>(launcherShortcutOverrides); + mLauncherShortcutOverrides = new ArrayMap<>(launcherShortcutOverrides); } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java index 415440b1f46d..cf49dcf8004e 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java @@ -130,12 +130,11 @@ final class DevicePolicyEngine { <V> void setLocalPolicy( @NonNull PolicyDefinition<V> policyDefinition, @NonNull EnforcingAdmin enforcingAdmin, - @NonNull PolicyValue<V> value, + @Nullable PolicyValue<V> value, int userId, boolean skipEnforcePolicy) { Objects.requireNonNull(policyDefinition); Objects.requireNonNull(enforcingAdmin); - Objects.requireNonNull(value); synchronized (mLock) { PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 22f684bea73d..a35f34dcde86 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -80,6 +80,7 @@ import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WIFI; import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WINDOWS; import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WIPE_DATA; import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS; +import static android.Manifest.permission.MASTER_CLEAR; import static android.Manifest.permission.QUERY_ADMIN_POLICY; import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY; import static android.Manifest.permission.SET_TIME; @@ -7552,9 +7553,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { boolean calledByProfileOwnerOnOrgOwnedDevice = isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId()); if (isPolicyEngineForFinanceFlagEnabled()) { - EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin( + EnforcingAdmin enforcingAdmin = enforcePermissionsAndGetEnforcingAdmin( /*admin=*/ null, - /*permission= */ MANAGE_DEVICE_POLICY_WIPE_DATA, + /*permission=*/ new String[]{MANAGE_DEVICE_POLICY_WIPE_DATA, MASTER_CLEAR}, USES_POLICY_WIPE_DATA, caller.getPackageName(), factoryReset ? UserHandle.USER_ALL : getAffectedUser(calledOnParentInstance)); @@ -7576,12 +7577,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { admin = getActiveAdminWithPolicyForUidLocked(/* who= */ null, DeviceAdminInfo.USES_POLICY_WIPE_DATA, caller.getUid()); } + Preconditions.checkCallAuthorization( + (admin != null) || hasCallingOrSelfPermission(permission.MASTER_CLEAR), + "No active admin for user %d and caller %d does not hold MASTER_CLEAR " + + "permission", + caller.getUserId(), caller.getUid()); } - Preconditions.checkCallAuthorization( - (admin != null) || hasCallingOrSelfPermission(permission.MASTER_CLEAR), - "No active admin for user %d and caller %d does not hold MASTER_CLEAR permission", - caller.getUserId(), caller.getUid()); checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_WIPE_DATA); if (TextUtils.isEmpty(wipeReasonForUser)) { @@ -7721,7 +7723,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private void clearLauncherShortcutOverrides() { - mPolicyCache.setLauncherShortcutOverrides(new ArrayList<>()); + mPolicyCache.setLauncherShortcutOverrides(new ArrayMap<>()); } private void updateTelephonyCrossProfileIntentFilters(int parentUserId, int profileUserId, @@ -7836,15 +7838,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else { // Explicit behaviour if (factoryReset) { - // TODO(b/254031494) Replace with new factory reset permission checks - if (!isPermissionCheckFlagEnabled()) { - boolean hasPermission = isDeviceOwnerUserId(userId) - || (isOrganizationOwnedDeviceWithManagedProfile() - && calledOnParentInstance); - Preconditions.checkCallAuthorization(hasPermission, - "Admin %s does not have permission to factory reset the device.", - userId); - } + EnforcingAdmin enforcingAdmin = enforcePermissionsAndGetEnforcingAdmin( + /*admin=*/ null, + /*permission=*/ new String[]{MANAGE_DEVICE_POLICY_WIPE_DATA, + MASTER_CLEAR}, + USES_POLICY_WIPE_DATA, + adminPackage, + factoryReset ? UserHandle.USER_ALL : + getAffectedUser(calledOnParentInstance)); wipeDevice = true; } else { Preconditions.checkCallAuthorization(!isSystemUser, @@ -12214,17 +12215,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } synchronized (getLockObject()) { - ActiveAdmin admin; - if (isPermissionCheckFlagEnabled()) { - admin = enforcePermissionAndGetEnforcingAdmin( - who, MANAGE_DEVICE_POLICY_INPUT_METHODS, - caller.getPackageName(), userId).getActiveAdmin(); + if (isPolicyEngineForFinanceFlagEnabled()) { + EnforcingAdmin admin = getEnforcingAdminForCaller(who, callerPackageName); + mDevicePolicyEngine.setLocalPolicy( + PolicyDefinition.PERMITTED_INPUT_METHODS, + admin, + packageList == null + ? null + : new StringSetPolicyValue(new HashSet<>(packageList)), + userId); } else { - admin = getParentOfAdminIfRequired( - getProfileOwnerOrDeviceOwnerLocked(caller.getUserId()), calledOnParentInstance); + ActiveAdmin admin = getParentOfAdminIfRequired( + getProfileOwnerOrDeviceOwnerLocked(caller.getUserId()), + calledOnParentInstance); + admin.permittedInputMethods = packageList; + saveSettingsLocked(caller.getUserId()); } - admin.permittedInputMethods = packageList; - saveSettingsLocked(caller.getUserId()); } DevicePolicyEventLogger @@ -12272,19 +12278,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } synchronized (getLockObject()) { - ActiveAdmin admin; - if (isPermissionCheckFlagEnabled()) { + if (isPolicyEngineForFinanceFlagEnabled()) { int affectedUser = calledOnParentInstance ? getProfileParentId( caller.getUserId()) : caller.getUserId(); - admin = enforcePermissionAndGetEnforcingAdmin( - who, MANAGE_DEVICE_POLICY_INPUT_METHODS, caller.getPackageName(), - affectedUser).getActiveAdmin(); + Set<String> policy = mDevicePolicyEngine.getResolvedPolicy( + PolicyDefinition.PERMITTED_INPUT_METHODS, affectedUser); + return policy == null ? null : new ArrayList<>(policy); } else { - admin = getParentOfAdminIfRequired( + ActiveAdmin admin = getParentOfAdminIfRequired( getProfileOwnerOrDeviceOwnerLocked( caller.getUserId()), calledOnParentInstance); + return admin.permittedInputMethods; } - return admin.permittedInputMethods; } } @@ -12302,37 +12307,45 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private @Nullable List<String> getPermittedInputMethodsUnchecked(@UserIdInt int userId) { - synchronized (getLockObject()) { - List<String> result = null; - // Only device or profile owners can have permitted lists set. - List<ActiveAdmin> admins = getActiveAdminsForAffectedUserInclPermissionBasedAdminLocked(userId); - for (ActiveAdmin admin: admins) { - List<String> fromAdmin = admin.permittedInputMethods; - if (fromAdmin != null) { - if (result == null) { - result = new ArrayList<String>(fromAdmin); - } else { - result.retainAll(fromAdmin); + List<String> result = null; + if (isPolicyEngineForFinanceFlagEnabled()) { + Set<String> policy = mDevicePolicyEngine.getResolvedPolicy( + PolicyDefinition.PERMITTED_INPUT_METHODS, userId); + result = policy == null ? null : new ArrayList<>(policy); + } else { + synchronized (getLockObject()) { + // Only device or profile owners can have permitted lists set. + List<ActiveAdmin> admins = + getActiveAdminsForAffectedUserInclPermissionBasedAdminLocked( + userId); + for (ActiveAdmin admin : admins) { + List<String> fromAdmin = admin.permittedInputMethods; + if (fromAdmin != null) { + if (result == null) { + result = new ArrayList<String>(fromAdmin); + } else { + result.retainAll(fromAdmin); + } } } } + } - // If we have a permitted list add all system input methods. - if (result != null) { - List<InputMethodInfo> imes = InputMethodManagerInternal - .get().getInputMethodListAsUser(userId); - if (imes != null) { - for (InputMethodInfo ime : imes) { - ServiceInfo serviceInfo = ime.getServiceInfo(); - ApplicationInfo applicationInfo = serviceInfo.applicationInfo; - if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { - result.add(serviceInfo.packageName); - } + // If we have a permitted list add all system input methods. + if (result != null) { + List<InputMethodInfo> imes = InputMethodManagerInternal + .get().getInputMethodListAsUser(userId); + if (imes != null) { + for (InputMethodInfo ime : imes) { + ServiceInfo serviceInfo = ime.getServiceInfo(); + ApplicationInfo applicationInfo = serviceInfo.applicationInfo; + if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + result.add(serviceInfo.packageName); } } } - return result; } + return result; } @Override @@ -12347,17 +12360,38 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { String.format(NOT_SYSTEM_CALLER_MSG, "query if an input method is disabled by admin")); - synchronized (getLockObject()) { - ActiveAdmin admin = getParentOfAdminIfRequired( - getActiveAdminUncheckedLocked(who, userHandle), calledOnParentInstance); - if (admin == null) { - return false; + if (isPolicyEngineForFinanceFlagEnabled()) { + int affectedUser = calledOnParentInstance ? getProfileParentId(userHandle) : userHandle; + Map<EnforcingAdmin, PolicyValue<Set<String>>> policies = + mDevicePolicyEngine.getLocalPoliciesSetByAdmins( + PolicyDefinition.PERMITTED_INPUT_METHODS, affectedUser); + EnforcingAdmin admin = null; + for (EnforcingAdmin a : policies.keySet()) { + if (a.getPackageName().equals(who.getPackageName())) { + if (policies.get(a).getValue() == null) { + return true; + } else { + return checkPackagesInPermittedListOrSystem( + Collections.singletonList(packageName), + new ArrayList<>(policies.get(a).getValue()), affectedUser); + } + } } - if (admin.permittedInputMethods == null) { - return true; + // Admin didn't set a policy + return false; + } else { + synchronized (getLockObject()) { + ActiveAdmin admin = getParentOfAdminIfRequired( + getActiveAdminUncheckedLocked(who, userHandle), calledOnParentInstance); + if (admin == null) { + return false; + } + if (admin.permittedInputMethods == null) { + return true; + } + return checkPackagesInPermittedListOrSystem(Collections.singletonList(packageName), + admin.permittedInputMethods, userHandle); } - return checkPackagesInPermittedListOrSystem(Collections.singletonList(packageName), - admin.permittedInputMethods, userHandle); } } @@ -21613,7 +21647,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } copyAccount(targetUser, sourceUser, accountToMigrate, callerPackage); if (!keepAccountMigrated) { - removeAccount(accountToMigrate); + removeAccount(accountToMigrate, sourceUserId); } } @@ -21657,9 +21691,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { .write(); } - private void removeAccount(Account account) { - final AccountManager accountManager = - mContext.getSystemService(AccountManager.class); + private void removeAccount(Account account, @UserIdInt int sourceUserId) { + final AccountManager accountManager = mContext.createContextAsUser( + UserHandle.of(sourceUserId), /* flags= */ 0) + .getSystemService(AccountManager.class); final AccountManagerFuture<Bundle> bundle = accountManager.removeAccount(account, null, null /* callback */, null /* handler */); try { @@ -23191,6 +23226,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } /** + * Checks if the calling process has been granted permission to apply a device policy on a + * specific user. Only one permission provided in the list needs to be granted to pass this + * check. + * The given permissions will be checked along with their associated cross-user permissions if + * they exist and the target user is different to the calling user. + * Returns an {@link EnforcingAdmin} for the caller. + * + * @param admin the component name of the admin. + * @param callerPackageName The package name of the calling application. + * @param permissions The names of the permissions being checked. + * @param deviceAdminPolicy The userId of the user which the caller needs permission to act on. + * @throws SecurityException if the caller has not been granted the given permission, + * the associated cross-user permission if the caller's user is different to the target user. + */ + private EnforcingAdmin enforcePermissionsAndGetEnforcingAdmin(@Nullable ComponentName admin, + String[] permissions, int deviceAdminPolicy, String callerPackageName, + int targetUserId) { + enforcePermissions(permissions, deviceAdminPolicy, callerPackageName, targetUserId); + return getEnforcingAdminForCaller(admin, callerPackageName); + } + + /** * Checks whether the calling process has been granted permission to query a device policy on * a specific user. * The given permission will be checked along with its associated cross-user permission if it @@ -23236,12 +23293,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** * Checks if the calling process has been granted permission to apply a device policy on a - * specific user. - * The given permission will be checked along with its associated cross-user permission if it - * exists and the target user is different to the calling user. + * specific user. Only one permission provided in the list needs to be granted to pass this + * check. + * The given permissions will be checked along with their associated cross-user permissions if + * they exists and the target user is different to the calling user. * * @param callerPackageName The package name of the calling application. - * @param permission The name of the permission being checked. + * @param permissions The names of the permissions being checked. * @param targetUserId The userId of the user which the caller needs permission to act on. * @throws SecurityException if the caller has not been granted the given permission, * the associated cross-user permission if the caller's user is different to the target user. @@ -23306,6 +23364,27 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } /** + * Checks if the calling process has been granted permission to apply a device policy on a + * specific user. + * The given permission will be checked along with its associated cross-user permission if it + * exists and the target user is different to the calling user. + * + * @param callerPackageName The package name of the calling application. + * @param adminPolicy The admin policy that should grant holders permission. + * @param permission The name of the permission being checked. + * @param targetUserId The userId of the user which the caller needs permission to act on. + * @throws SecurityException if the caller has not been granted the given permission, + * the associated cross-user permission if the caller's user is different to the target user. + */ + private void enforcePermissions(String[] permissions, int adminPolicy, + String callerPackageName, int targetUserId) throws SecurityException { + if (hasAdminPolicy(adminPolicy, callerPackageName)) { + return; + } + enforcePermissions(permissions, callerPackageName, targetUserId); + } + + /** * Checks whether the calling process has been granted permission to query a device policy on * a specific user. * The given permission will be checked along with its associated cross-user permission if it @@ -23432,7 +23511,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Check for non-DPC active admins. admin = getActiveAdminForCaller(who, caller); if (admin != null) { - return EnforcingAdmin.createDeviceAdminEnforcingAdmin(who, userId, admin); + return EnforcingAdmin.createDeviceAdminEnforcingAdmin(admin.info.getComponent(), userId, + admin); } admin = getUserData(userId).createOrGetPermissionBasedAdmin(userId); return EnforcingAdmin.createEnforcingAdmin(caller.getPackageName(), userId, admin); @@ -23720,15 +23800,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private void updateDialerAndSmsManagedShortcutsOverrideCache( String defaultDialerPackageName, String defaultSmsPackageName) { - - List<String> shortcutOverrides = new ArrayList<>(); + ArrayMap<String, String> shortcutOverrides = new ArrayMap<>(); if (defaultDialerPackageName != null) { - shortcutOverrides.add(defaultDialerPackageName); + shortcutOverrides.put(defaultDialerPackageName, defaultDialerPackageName); } if (defaultSmsPackageName != null) { - shortcutOverrides.add(defaultSmsPackageName); + shortcutOverrides.put(defaultSmsPackageName, defaultSmsPackageName); } mPolicyCache.setLauncherShortcutOverrides(shortcutOverrides); } @@ -23793,6 +23872,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { public DevicePolicyState getDevicePolicyState() { Preconditions.checkCallAuthorization( hasCallingOrSelfPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)); + return mInjector.binderWithCleanCallingIdentity(mDevicePolicyEngine::getDevicePolicyState); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java index 638596b5cc20..43a2c9bbf5c5 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java @@ -308,6 +308,13 @@ final class PolicyDefinition<V> { DevicePolicyIdentifiers.ACCOUNT_MANAGEMENT_DISABLED_POLICY, accountType)); } + static PolicyDefinition<Set<String>> PERMITTED_INPUT_METHODS = new PolicyDefinition<>( + new NoArgsPolicyKey(DevicePolicyIdentifiers.PERMITTED_INPUT_METHODS_POLICY), + new MostRecent<>(), + POLICY_FLAG_LOCAL_ONLY_POLICY, + (Set<String> value, Context context, Integer userId, PolicyKey policyKey) -> true, + new StringSetPolicySerializer()); + private static final Map<String, PolicyDefinition<?>> POLICY_DEFINITIONS = new HashMap<>(); private static Map<String, Integer> USER_RESTRICTION_FLAGS = new HashMap<>(); @@ -333,6 +340,8 @@ final class PolicyDefinition<V> { GENERIC_APPLICATION_HIDDEN); POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.ACCOUNT_MANAGEMENT_DISABLED_POLICY, GENERIC_ACCOUNT_MANAGEMENT_DISABLED); + POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERMITTED_INPUT_METHODS_POLICY, + PERMITTED_INPUT_METHODS); // User Restriction Policies USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MODIFY_ACCOUNTS, /* flags= */ 0); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java index 741f209a90c3..dd4c6afdcfb6 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java @@ -67,9 +67,8 @@ final class PolicyState<V> { /** * Returns {@code true} if the resolved policy has changed, {@code false} otherwise. */ - boolean addPolicy(@NonNull EnforcingAdmin admin, @NonNull PolicyValue<V> policy) { + boolean addPolicy(@NonNull EnforcingAdmin admin, @Nullable PolicyValue<V> policy) { Objects.requireNonNull(admin); - Objects.requireNonNull(policy); //LinkedHashMap doesn't update the insertion order of existing keys, removing the existing // key will cause it to update. @@ -89,9 +88,9 @@ final class PolicyState<V> { * Returns {@code true} if the resolved policy has changed, {@code false} otherwise. */ boolean addPolicy( - @NonNull EnforcingAdmin admin, @NonNull PolicyValue<V> policy, + @NonNull EnforcingAdmin admin, @Nullable PolicyValue<V> policy, LinkedHashMap<EnforcingAdmin, PolicyValue<V>> globalPoliciesSetByAdmins) { - mPoliciesSetByAdmins.put(Objects.requireNonNull(admin), Objects.requireNonNull(policy)); + mPoliciesSetByAdmins.put(Objects.requireNonNull(admin), policy); return resolvePolicy(globalPoliciesSetByAdmins); } @@ -210,10 +209,12 @@ final class PolicyState<V> { for (EnforcingAdmin admin : mPoliciesSetByAdmins.keySet()) { serializer.startTag(/* namespace= */ null, TAG_ADMIN_POLICY_ENTRY); - serializer.startTag(/* namespace= */ null, TAG_POLICY_VALUE_ENTRY); - mPolicyDefinition.savePolicyValueToXml( - serializer, mPoliciesSetByAdmins.get(admin).getValue()); - serializer.endTag(/* namespace= */ null, TAG_POLICY_VALUE_ENTRY); + if (mPoliciesSetByAdmins.get(admin) != null) { + serializer.startTag(/* namespace= */ null, TAG_POLICY_VALUE_ENTRY); + mPolicyDefinition.savePolicyValueToXml( + serializer, mPoliciesSetByAdmins.get(admin).getValue()); + serializer.endTag(/* namespace= */ null, TAG_POLICY_VALUE_ENTRY); + } serializer.startTag(/* namespace= */ null, TAG_ENFORCING_ADMIN_ENTRY); admin.saveToXml(serializer); @@ -250,7 +251,7 @@ final class PolicyState<V> { break; } } - if (admin != null && value != null) { + if (admin != null) { policiesSetByAdmins.put(admin, value); } else { Log.e(TAG, "Error Parsing TAG_ADMIN_POLICY_ENTRY"); diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java index a5adf3f9bf80..f1d4de9369f0 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java @@ -54,6 +54,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_HIGH; import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_ALLOW_LIST; import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_COMPAT; +import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_LISTENER; import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_NOT_APPLICABLE; import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_PERMISSION; import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_POLICY_PERMISSION; @@ -2728,6 +2729,66 @@ public final class AlarmManagerServiceTest { } @Test + public void exactListenerBinderCallWithoutPermissionWithoutAllowlist() throws RemoteException { + mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); + mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true); + + mockScheduleExactAlarmState(false); + mockUseExactAlarmState(false); + when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(false); + + final IAlarmListener listener = getNewListener(() -> {}); + mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0, + 0, null, listener, "test-tag", null, null); + + verify(mService, never()).hasUseExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID); + verify(mService, never()).hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, + TEST_CALLING_UID); + verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt()); + + final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); + verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L), + isNull(), eq(listener), eq("test-tag"), eq(FLAG_STANDALONE), isNull(), isNull(), + eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(), + eq(EXACT_ALLOW_REASON_LISTENER)); + + final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue()); + final int type = idleOptions.getTemporaryAppAllowlistType(); + assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type); + } + + @Test + public void exactAllowWhileIdleListenerBinderCallWithoutPermissionWithoutAllowlist() + throws RemoteException { + mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); + mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true); + + mockScheduleExactAlarmState(false); + mockUseExactAlarmState(false); + when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(false); + + final IAlarmListener listener = getNewListener(() -> {}); + mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0, + FLAG_ALLOW_WHILE_IDLE, null, listener, "test-tag", null, null); + + verify(mService, never()).hasUseExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID); + verify(mService, never()).hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, + TEST_CALLING_UID); + verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt()); + + final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); + verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L), + isNull(), eq(listener), eq("test-tag"), + eq(FLAG_STANDALONE | FLAG_ALLOW_WHILE_IDLE_COMPAT), isNull(), isNull(), + eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(), + eq(EXACT_ALLOW_REASON_LISTENER)); + + final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue()); + final int type = idleOptions.getTemporaryAppAllowlistType(); + assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type); + } + + @Test public void inexactAllowWhileIdleBinderCall() throws RemoteException { // Both permission and power exemption status don't matter for these alarms. // We only want to test that the flags and idleOptions are correct. diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java index 3fb7fb4e6aea..acfea85d60a2 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java @@ -40,6 +40,7 @@ import static com.android.server.am.BroadcastQueueTest.PACKAGE_YELLOW; import static com.android.server.am.BroadcastQueueTest.getUidForPackage; import static com.android.server.am.BroadcastQueueTest.makeManifestReceiver; import static com.android.server.am.BroadcastQueueTest.withPriority; +import static com.android.server.am.BroadcastRecord.isReceiverEquals; import static com.google.common.truth.Truth.assertThat; @@ -49,13 +50,16 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import android.annotation.NonNull; @@ -116,6 +120,7 @@ public final class BroadcastQueueModernImplTest { TestLooperManager mLooper; BroadcastConstants mConstants; + private BroadcastSkipPolicy mSkipPolicy; BroadcastQueueModernImpl mImpl; BroadcastProcessQueue mHead; @@ -139,29 +144,18 @@ public final class BroadcastQueueModernImplTest { mConstants.DELAY_NORMAL_MILLIS = 10_000; mConstants.DELAY_CACHED_MILLIS = 120_000; - final BroadcastSkipPolicy emptySkipPolicy = new BroadcastSkipPolicy(mAms) { - public boolean shouldSkip(BroadcastRecord r, Object o) { - // Ignored - return false; - } - public String shouldSkipMessage(BroadcastRecord r, Object o) { - // Ignored - return null; - } - public boolean disallowBackgroundStart(BroadcastRecord r) { - // Ignored - return false; - } - }; + mSkipPolicy = spy(new BroadcastSkipPolicy(mAms)); + doReturn(null).when(mSkipPolicy).shouldSkipMessage(any(), any()); + doReturn(false).when(mSkipPolicy).disallowBackgroundStart(any()); + final BroadcastHistory emptyHistory = new BroadcastHistory(mConstants) { public void addBroadcastToHistoryLocked(BroadcastRecord original) { // Ignored } }; - mImpl = new BroadcastQueueModernImpl(mAms, mHandlerThread.getThreadHandler(), - mConstants, mConstants, emptySkipPolicy, emptyHistory); + mConstants, mConstants, mSkipPolicy, emptyHistory); doReturn(1L).when(mQueue1).getRunnableAt(); doReturn(2L).when(mQueue2).getRunnableAt(); @@ -256,17 +250,12 @@ public final class BroadcastQueueModernImplTest { private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue, BroadcastRecord record, int recordIndex) { - enqueueOrReplaceBroadcast(queue, record, recordIndex, false, 42_000_000L); + enqueueOrReplaceBroadcast(queue, record, recordIndex, 42_000_000L); } private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue, BroadcastRecord record, int recordIndex, long enqueueTime) { - enqueueOrReplaceBroadcast(queue, record, recordIndex, false, enqueueTime); - } - - private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue, - BroadcastRecord record, int recordIndex, boolean wouldBeSkipped, long enqueueTime) { - queue.enqueueOrReplaceBroadcast(record, recordIndex, wouldBeSkipped, (r, i) -> { + queue.enqueueOrReplaceBroadcast(record, recordIndex, (r, i) -> { throw new UnsupportedOperationException(); }); record.enqueueTime = enqueueTime; @@ -1199,6 +1188,42 @@ public final class BroadcastQueueModernImplTest { assertEquals(ProcessList.SCHED_GROUP_DEFAULT, queue.getPreferredSchedulingGroupLocked()); } + @Test + public void testSkipPolicy_atEnqueueTime() throws Exception { + final Intent userPresent = new Intent(Intent.ACTION_USER_PRESENT); + final Object greenReceiver = makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN); + final Object redReceiver = makeManifestReceiver(PACKAGE_RED, CLASS_RED); + + final BroadcastRecord userPresentRecord = makeBroadcastRecord(userPresent, + List.of(greenReceiver, redReceiver)); + + final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK); + final BroadcastRecord timeTickRecord = makeBroadcastRecord(timeTick, + List.of(greenReceiver, redReceiver)); + + doAnswer(invocation -> { + final BroadcastRecord r = invocation.getArgument(0); + final Object o = invocation.getArgument(1); + if (userPresent.getAction().equals(r.intent.getAction()) + && isReceiverEquals(o, greenReceiver)) { + return "receiver skipped by test"; + } + return null; + }).when(mSkipPolicy).shouldSkipMessage(any(BroadcastRecord.class), any()); + + mImpl.enqueueBroadcastLocked(userPresentRecord); + mImpl.enqueueBroadcastLocked(timeTickRecord); + + final BroadcastProcessQueue greenQueue = mImpl.getProcessQueue(PACKAGE_GREEN, + getUidForPackage(PACKAGE_GREEN)); + // There should be only one broadcast for green process as the other would have + // been skipped. + verifyPendingRecords(greenQueue, List.of(timeTick)); + final BroadcastProcessQueue redQueue = mImpl.getProcessQueue(PACKAGE_RED, + getUidForPackage(PACKAGE_RED)); + verifyPendingRecords(redQueue, List.of(userPresent, timeTick)); + } + private Intent createPackageChangedIntent(int uid, List<String> componentNameList) { final Intent packageChangedIntent = new Intent(Intent.ACTION_PACKAGE_CHANGED); packageChangedIntent.putExtra(Intent.EXTRA_UID, uid); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java index 96eca7171af0..8cfc150afe56 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java @@ -281,8 +281,8 @@ public class AccessibilityManagerServiceTest { @Test public void testRegisterProxy() throws Exception { mA11yms.registerProxyForDisplay(mMockServiceClient, TEST_DISPLAY); - verify(mProxyManager).registerProxy(eq(mMockServiceClient), eq(TEST_DISPLAY), - eq(mTestableContext), anyInt(), any(), eq(mMockSecurityPolicy), + verify(mProxyManager).registerProxy(eq(mMockServiceClient), eq(TEST_DISPLAY), anyInt(), + eq(mMockSecurityPolicy), eq(mA11yms), eq(mA11yms.getTraceManager()), eq(mMockWindowManagerService)); } @@ -295,7 +295,7 @@ public class AccessibilityManagerServiceTest { assertThrows(SecurityException.class, () -> mA11yms.registerProxyForDisplay(mMockServiceClient, TEST_DISPLAY)); - verify(mProxyManager, never()).registerProxy(any(), anyInt(), any(), anyInt(), any(), any(), + verify(mProxyManager, never()).registerProxy(any(), anyInt(), anyInt(), any(), any(), any(), any()); } @@ -307,7 +307,7 @@ public class AccessibilityManagerServiceTest { assertThrows(SecurityException.class, () -> mA11yms.registerProxyForDisplay(mMockServiceClient, TEST_DISPLAY)); - verify(mProxyManager, never()).registerProxy(any(), anyInt(), any(), anyInt(), any(), any(), + verify(mProxyManager, never()).registerProxy(any(), anyInt(), anyInt(), any(), any(), any(), any()); } @@ -316,7 +316,7 @@ public class AccessibilityManagerServiceTest { public void testRegisterProxyForDefaultDisplay() throws Exception { assertThrows(IllegalArgumentException.class, () -> mA11yms.registerProxyForDisplay(mMockServiceClient, Display.DEFAULT_DISPLAY)); - verify(mProxyManager, never()).registerProxy(any(), anyInt(), any(), anyInt(), any(), any(), + verify(mProxyManager, never()).registerProxy(any(), anyInt(), anyInt(), any(), any(), any(), any()); } @@ -325,7 +325,7 @@ public class AccessibilityManagerServiceTest { public void testRegisterProxyForInvalidDisplay() throws Exception { assertThrows(IllegalArgumentException.class, () -> mA11yms.registerProxyForDisplay(mMockServiceClient, Display.INVALID_DISPLAY)); - verify(mProxyManager, never()).registerProxy(any(), anyInt(), any(), anyInt(), any(), any(), + verify(mProxyManager, never()).registerProxy(any(), anyInt(), anyInt(), any(), any(), any(), any()); } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java index eb6670ee964c..8f0d0144a40e 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java @@ -146,7 +146,7 @@ public class AccessibilitySecurityPolicyTest { @Mock private PolicyWarningUIController mPolicyWarningUIController; @Mock - private PackageManagerInternal mPackageManagerInternal; + private PackageManagerInternal mMockPackageManagerInternal; @Before public void setUp() { @@ -158,7 +158,8 @@ public class AccessibilitySecurityPolicyTest { R.dimen.accessibility_focus_highlight_stroke_width, 1); mA11ySecurityPolicy = new AccessibilitySecurityPolicy( - mPolicyWarningUIController, mContext, mMockA11yUserManager); + mPolicyWarningUIController, mContext, mMockA11yUserManager, + mMockPackageManagerInternal); mA11ySecurityPolicy.setSendingNonA11yToolNotificationLocked(true); mA11ySecurityPolicy.setAccessibilityWindowManager(mMockA11yWindowManager); mA11ySecurityPolicy.setAppWidgetManager(mMockAppWidgetManager); @@ -237,8 +238,8 @@ public class AccessibilitySecurityPolicyTest { @Test public void resolveValidReportedPackage_uidAndPkgNameMatched_returnPkgName() throws PackageManager.NameNotFoundException { - when(mMockPackageManager.getPackageUidAsUser(PACKAGE_NAME, - PackageManager.MATCH_ANY_USER, TEST_USER_ID)).thenReturn(APP_UID); + when(mMockPackageManagerInternal.isSameApp(PACKAGE_NAME, APP_UID, TEST_USER_ID)) + .thenReturn(true); assertEquals(mA11ySecurityPolicy.resolveValidReportedPackageLocked( PACKAGE_NAME, APP_UID, TEST_USER_ID, APP_PID), @@ -257,8 +258,8 @@ public class AccessibilitySecurityPolicyTest { when(mMockAppWidgetManager.getHostedWidgetPackages(widgetHostUid)) .thenReturn(widgetPackages); - when(mMockPackageManager.getPackageUidAsUser(hostPackageName, TEST_USER_ID)) - .thenReturn(widgetHostUid); + when(mMockPackageManagerInternal.isSameApp(hostPackageName, widgetHostUid, TEST_USER_ID)) + .thenReturn(true); assertEquals(mA11ySecurityPolicy.resolveValidReportedPackageLocked( widgetPackageName, widgetHostUid, TEST_USER_ID, widgetHostPid), @@ -272,8 +273,8 @@ public class AccessibilitySecurityPolicyTest { final String[] uidPackages = {PACKAGE_NAME, PACKAGE_NAME2}; when(mMockPackageManager.getPackagesForUid(APP_UID)) .thenReturn(uidPackages); - when(mMockPackageManager.getPackageUidAsUser(invalidPackageName, TEST_USER_ID)) - .thenThrow(PackageManager.NameNotFoundException.class); + when(mMockPackageManagerInternal.isSameApp(invalidPackageName, APP_UID, TEST_USER_ID)) + .thenReturn(false); when(mMockAppWidgetManager.getHostedWidgetPackages(APP_UID)) .thenReturn(new ArraySet<>()); mContext.getTestablePermissions().setPermission( @@ -292,8 +293,8 @@ public class AccessibilitySecurityPolicyTest { final String[] uidPackages = {PACKAGE_NAME}; when(mMockPackageManager.getPackagesForUid(APP_UID)) .thenReturn(uidPackages); - when(mMockPackageManager.getPackageUidAsUser(wantedPackageName, TEST_USER_ID)) - .thenReturn(wantedUid); + when(mMockPackageManagerInternal.isSameApp(wantedPackageName, wantedUid, TEST_USER_ID)) + .thenReturn(true); when(mMockAppWidgetManager.getHostedWidgetPackages(APP_UID)) .thenReturn(new ArraySet<>()); mContext.getTestablePermissions().setPermission( @@ -312,8 +313,8 @@ public class AccessibilitySecurityPolicyTest { final String[] uidPackages = {PACKAGE_NAME}; when(mMockPackageManager.getPackagesForUid(APP_UID)) .thenReturn(uidPackages); - when(mMockPackageManager.getPackageUidAsUser(wantedPackageName, TEST_USER_ID)) - .thenReturn(wantedUid); + when(mMockPackageManagerInternal.isSameApp(wantedPackageName, wantedUid, TEST_USER_ID)) + .thenReturn(true); when(mMockAppWidgetManager.getHostedWidgetPackages(APP_UID)) .thenReturn(new ArraySet<>()); mContext.getTestablePermissions().setPermission( diff --git a/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java index dd44a7968639..6ac3658bc3b4 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java @@ -29,12 +29,14 @@ import android.accessibilityservice.AccessibilityTrace; import android.content.ComponentName; import android.content.Context; import android.content.res.Resources; +import android.graphics.Color; import android.os.Handler; import android.view.accessibility.AccessibilityEvent; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -79,12 +81,15 @@ public class ProxyAccessibilityServiceConnectionTest { WindowManagerInternal mMockWindowManagerInternal; ProxyAccessibilityServiceConnection mProxyConnection; AccessibilityServiceInfo mAccessibilityServiceInfo; + private int mFocusStrokeWidthDefaultValue; + private int mFocusColorDefaultValue; @Before public void setup() { final Resources resources = getInstrumentation().getContext().getResources(); MockitoAnnotations.initMocks(this); when(mMockContext.getResources()).thenReturn(resources); + when(mMockSecurityPolicy.checkAccessibilityAccess(any())).thenReturn(true); mAccessibilityServiceInfo = new AccessibilityServiceInfo(); mProxyConnection = new ProxyAccessibilityServiceConnection(mMockContext, COMPONENT_NAME, @@ -92,10 +97,13 @@ public class ProxyAccessibilityServiceConnectionTest { getInstrumentation().getContext().getMainLooper()), mMockLock, mMockSecurityPolicy, mMockSystemSupport, mMockA11yTrace, mMockWindowManagerInternal, mMockA11yWindowManager, DISPLAY_ID, DEVICE_ID); + + mFocusStrokeWidthDefaultValue = mProxyConnection.getFocusStrokeWidthLocked(); + mFocusColorDefaultValue = mProxyConnection.getFocusColorLocked(); } @Test - public void testSetInstalledAndEnabledServices_clientChanged() { + public void testSetInstalledAndEnabledServices_updateInfos_notifiesSystemOfProxyChange() { final List<AccessibilityServiceInfo> infos = new ArrayList<>(); final AccessibilityServiceInfo info1 = new AccessibilityServiceInfo(); infos.add(info1); @@ -106,6 +114,17 @@ public class ProxyAccessibilityServiceConnectionTest { } @Test + public void testSetFocusAppearance_updateAppearance_notifiesSystemOfProxyChange() { + final int updatedWidth = mFocusStrokeWidthDefaultValue + 10; + final int updatedColor = mFocusColorDefaultValue + == Color.BLUE ? Color.RED : Color.BLUE; + + mProxyConnection.setFocusAppearance(updatedWidth, updatedColor); + + verify(mMockSystemSupport).onProxyChanged(DEVICE_ID); + } + + @Test public void testSetInstalledAndEnabledServices_returnList() { final List<AccessibilityServiceInfo> infos = new ArrayList<>(); final AccessibilityServiceInfo info1 = new AccessibilityServiceInfo(); @@ -196,7 +215,7 @@ public class ProxyAccessibilityServiceConnectionTest { } @Test - public void testSetServiceInfo_setIllegalOperationExceptionThrown_() { + public void testSetServiceInfo_setIllegalOperationExceptionThrown() { UnsupportedOperationException thrown = assertThrows( UnsupportedOperationException.class, diff --git a/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java new file mode 100644 index 000000000000..6c7b995d07a2 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java @@ -0,0 +1,527 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.accessibility; + +import static com.android.server.accessibility.ProxyAccessibilityServiceConnectionTest.INTERACTIVE_UI_TIMEOUT_100MS; +import static com.android.server.accessibility.ProxyAccessibilityServiceConnectionTest.INTERACTIVE_UI_TIMEOUT_200MS; +import static com.android.server.accessibility.ProxyAccessibilityServiceConnectionTest.NON_INTERACTIVE_UI_TIMEOUT_100MS; +import static com.android.server.accessibility.ProxyAccessibilityServiceConnectionTest.NON_INTERACTIVE_UI_TIMEOUT_200MS; +import static com.android.server.accessibility.ProxyManager.PROXY_COMPONENT_CLASS_NAME; +import static com.android.server.accessibility.ProxyManager.PROXY_COMPONENT_PACKAGE_NAME; + +import static org.junit.Assert.fail; + +import android.accessibilityservice.AccessibilityGestureEvent; +import android.accessibilityservice.AccessibilityServiceInfo; +import android.accessibilityservice.AccessibilityTrace; +import android.accessibilityservice.IAccessibilityServiceClient; +import android.accessibilityservice.IAccessibilityServiceConnection; +import android.accessibilityservice.MagnificationConfig; +import android.companion.virtual.IVirtualDeviceManager; +import android.companion.virtual.VirtualDeviceManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Region; +import android.os.IBinder; +import android.os.RemoteCallbackList; +import android.os.RemoteException; +import android.util.ArraySet; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.IAccessibilityManagerClient; +import android.view.inputmethod.EditorInfo; + +import com.android.internal.R; +import com.android.internal.inputmethod.IAccessibilityInputMethodSession; +import com.android.internal.inputmethod.IAccessibilityInputMethodSessionCallback; +import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection; +import com.android.internal.util.IntPair; +import com.android.server.LocalServices; +import com.android.server.accessibility.test.MessageCapturingHandler; +import com.android.server.companion.virtual.VirtualDeviceManagerInternal; +import com.android.server.wm.WindowManagerInternal; + +import static com.google.common.truth.Truth.assertThat; + +import androidx.test.InstrumentationRegistry; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * Tests for ProxyManager. + */ +public class ProxyManagerTest { + private static final int DISPLAY_ID = 1000; + private static final int DISPLAY_2_ID = 1001; + private static final int DEVICE_ID = 10; + private static final int STREAMED_CALLING_UID = 9876; + + @Mock private Context mMockContext; + @Mock private AccessibilitySecurityPolicy mMockSecurityPolicy; + @Mock private AccessibilityWindowManager mMockA11yWindowManager; + @Mock private ProxyManager.SystemSupport mMockProxySystemSupport; + @Mock private AbstractAccessibilityServiceConnection.SystemSupport mMockConnectionSystemSupport; + @Mock private AccessibilityTrace mMockA11yTrace; + @Mock private WindowManagerInternal mMockWindowManagerInternal; + @Mock private IAccessibilityServiceClient mMockAccessibilityServiceClient; + @Mock private IBinder mMockServiceAsBinder; + @Mock private VirtualDeviceManagerInternal mMockVirtualDeviceManagerInternal; + @Mock private IVirtualDeviceManager mMockIVirtualDeviceManager; + + private int mFocusStrokeWidthDefaultValue; + private int mFocusColorDefaultValue; + + private MessageCapturingHandler mMessageCapturingHandler = new MessageCapturingHandler(null); + private ProxyManager mProxyManager; + + @Before + public void setup() throws RemoteException { + MockitoAnnotations.initMocks(this); + final Resources resources = InstrumentationRegistry.getContext().getResources(); + + mFocusStrokeWidthDefaultValue = + resources.getDimensionPixelSize(R.dimen.accessibility_focus_highlight_stroke_width); + mFocusColorDefaultValue = resources.getColor(R.color.accessibility_focus_highlight_color); + when(mMockContext.getResources()).thenReturn(resources); + + when(mMockVirtualDeviceManagerInternal.getDeviceIdsForUid(anyInt())).thenReturn( + new ArraySet(Set.of(DEVICE_ID))); + LocalServices.removeServiceForTest(VirtualDeviceManagerInternal.class); + LocalServices.addService(VirtualDeviceManagerInternal.class, + mMockVirtualDeviceManagerInternal); + + when(mMockIVirtualDeviceManager.getDeviceIdForDisplayId(anyInt())).thenReturn(DEVICE_ID); + final VirtualDeviceManager virtualDeviceManager = + new VirtualDeviceManager(mMockIVirtualDeviceManager, mMockContext); + when(mMockContext.getSystemServiceName(VirtualDeviceManager.class)).thenReturn( + Context.VIRTUAL_DEVICE_SERVICE); + when(mMockContext.getSystemService(VirtualDeviceManager.class)) + .thenReturn(virtualDeviceManager); + + when(mMockA11yTrace.isA11yTracingEnabled()).thenReturn(false); + + final RemoteCallbackList<IAccessibilityManagerClient> userClients = + new RemoteCallbackList<>(); + final RemoteCallbackList<IAccessibilityManagerClient> globalClients = + new RemoteCallbackList<>(); + when(mMockProxySystemSupport.getCurrentUserClientsLocked()).thenReturn(userClients); + when(mMockProxySystemSupport.getGlobalClientsLocked()).thenReturn(globalClients); + + when(mMockAccessibilityServiceClient.asBinder()).thenReturn(mMockServiceAsBinder); + + mProxyManager = new ProxyManager(new Object(), mMockA11yWindowManager, mMockContext, + mMessageCapturingHandler, new UiAutomationManager(new Object()), + mMockProxySystemSupport); + } + + @After + public void tearDown() { + mMessageCapturingHandler.removeAllMessages(); + } + + /** + * Tests that the proxy’s backing AccessibilityServiceClient is initialized when registering a + * proxy. + */ + @Test + public void registerProxy_always_connectsServiceClient() throws RemoteException { + registerProxy(DISPLAY_ID); + verify(mMockAccessibilityServiceClient).init(any(), anyInt(), any()); + } + + /** Tests that unregistering a proxy removes its display from tracking. */ + @Test + public void unregisterProxy_always_stopsTrackingDisplay() { + registerProxy(DISPLAY_ID); + + mProxyManager.unregisterProxy(DISPLAY_ID); + + verify(mMockA11yWindowManager).stopTrackingDisplayProxy(DISPLAY_ID); + assertThat(mProxyManager.isProxyedDisplay(DISPLAY_ID)).isFalse(); + } + /** + * Tests that unregistering a proxied display of a virtual device, where that virtual device + * owned only that one proxied display, removes the device from tracking. + */ + @Test + public void unregisterProxy_deviceAssociatedWithSingleDisplay_stopsTrackingDevice() { + registerProxy(DISPLAY_ID); + + mProxyManager.unregisterProxy(DISPLAY_ID); + + assertThat(mProxyManager.isProxyedDeviceId(DEVICE_ID)).isFalse(); + verify(mMockProxySystemSupport).removeDeviceIdLocked(DEVICE_ID); + } + + /** + * Tests that unregistering a proxied display of a virtual device, where that virtual device + * owns more than one proxied display, does not remove the device from tracking. + */ + @Test + public void unregisterProxy_deviceAssociatedWithMultipleDisplays_tracksRemainingProxy() { + registerProxy(DISPLAY_ID); + registerProxy(DISPLAY_2_ID); + + mProxyManager.unregisterProxy(DISPLAY_ID); + + assertThat(mProxyManager.isProxyedDeviceId(DEVICE_ID)).isTrue(); + verify(mMockProxySystemSupport, never()).removeDeviceIdLocked(DEVICE_ID); + } + + /** + * Tests that changing a proxy, e.g. registering/unregistering a proxy or updating its service + * info, notifies the apps being streamed and AccessibilityManagerService. + */ + @Test + public void testOnProxyChanged_always_propagatesChange() { + registerProxy(DISPLAY_ID); + mMessageCapturingHandler.sendAllMessages(); + + mProxyManager.onProxyChanged(DEVICE_ID); + + // Messages to notify IAccessibilityManagerClients should be posted. + assertThat(mMessageCapturingHandler.hasMessages()).isTrue(); + + verify(mMockProxySystemSupport).updateWindowsForAccessibilityCallbackLocked(); + verify(mMockProxySystemSupport).notifyClearAccessibilityCacheLocked(); + } + + /** + * Tests that getting the first device id for an app uid, such as when an app queries for + * device-specific state, returns the right device id. + */ + @Test + public void testGetFirstDeviceForUid_streamedAppQueriesState_getsHostDeviceId() { + registerProxy(DISPLAY_ID); + assertThat(mProxyManager.getFirstDeviceIdForUidLocked(STREAMED_CALLING_UID)) + .isEqualTo(DEVICE_ID); + } + + /** + * Tests that the app client state retrieved for a device reflects that touch exploration is + * enabled since a proxy info has requested touch exploration. + */ + @Test + public void testGetClientState_proxyWantsTouchExploration_returnsTouchExplorationEnabled() { + registerProxy(DISPLAY_ID); + + final AccessibilityServiceInfo secondDisplayInfo = new AccessibilityServiceInfo(); + secondDisplayInfo.flags |= AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE; + AccessibilityServiceClientImpl client = new AccessibilityServiceClientImpl( + secondDisplayInfo); + registerProxy(DISPLAY_2_ID, client); + + final int deviceClientState = mProxyManager.getStateLocked(DEVICE_ID); + assertThat((deviceClientState + & AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED) != 0).isTrue(); + } + + /** + * Tests that the highest interactive and non-interactive timeout is returned if there are + * multiple proxied displays belonging to a device. + */ + @Test + public void testGetRecommendedTimeout_multipleProxies_returnsHighestTimeout() { + final AccessibilityServiceInfo firstDisplayInfo = new AccessibilityServiceInfo(); + firstDisplayInfo.setInteractiveUiTimeoutMillis(INTERACTIVE_UI_TIMEOUT_100MS); + firstDisplayInfo.setNonInteractiveUiTimeoutMillis(NON_INTERACTIVE_UI_TIMEOUT_200MS); + + final AccessibilityServiceInfo secondDisplayInfo = new AccessibilityServiceInfo(); + secondDisplayInfo.setInteractiveUiTimeoutMillis(INTERACTIVE_UI_TIMEOUT_200MS); + secondDisplayInfo.setNonInteractiveUiTimeoutMillis(NON_INTERACTIVE_UI_TIMEOUT_100MS); + + registerProxy(DISPLAY_ID, new AccessibilityServiceClientImpl(firstDisplayInfo)); + registerProxy(DISPLAY_2_ID, new AccessibilityServiceClientImpl(secondDisplayInfo)); + + final long timeout = mProxyManager.getRecommendedTimeoutMillisLocked(DEVICE_ID); + final int interactiveTimeout = IntPair.first(timeout); + final int nonInteractiveTimeout = IntPair.second(timeout); + + assertThat(interactiveTimeout).isEqualTo(INTERACTIVE_UI_TIMEOUT_200MS); + assertThat(nonInteractiveTimeout).isEqualTo(NON_INTERACTIVE_UI_TIMEOUT_200MS); + } + /** + * Tests that getting the installed and enabled services returns the info of the registered + * proxy. (The component name reflects the display id.) + */ + @Test + public void testGetInstalledAndEnabledServices_defaultInfo_returnsInfoForDisplayId() { + final AccessibilityServiceInfo info = new AccessibilityServiceInfo(); + registerProxy(DISPLAY_ID, new AccessibilityServiceClientImpl(info)); + final List<AccessibilityServiceInfo> installedAndEnabledServices = + mProxyManager.getInstalledAndEnabledServiceInfosLocked( + AccessibilityServiceInfo.FEEDBACK_ALL_MASK, DEVICE_ID); + assertThat(installedAndEnabledServices.size()).isEqualTo(1); + AccessibilityServiceInfo proxyInfo = installedAndEnabledServices.get(0); + + assertThat(proxyInfo.getComponentName()).isEqualTo(new ComponentName( + PROXY_COMPONENT_PACKAGE_NAME, PROXY_COMPONENT_CLASS_NAME + DISPLAY_ID)); + } + + /** + * Tests that the app client state retrieved for a device reflects that accessibility is + * enabled. + */ + @Test + public void testGetClientState_always_returnsAccessibilityEnabled() { + registerProxy(DISPLAY_ID); + + final int deviceClientState = mProxyManager.getStateLocked(DEVICE_ID); + assertThat((deviceClientState + & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0).isTrue(); + } + + /** + * Tests that the manager can retrieve interactive windows if a proxy sets + * AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS. + */ + @Test + public void testCanRetrieveInteractiveWindows_atLeastOneProxyWantsWindows_returnsTrue() { + registerProxy(DISPLAY_ID); + + final AccessibilityServiceInfo secondDisplayInfo = new AccessibilityServiceInfo(); + secondDisplayInfo.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS; + registerProxy(DISPLAY_2_ID, new AccessibilityServiceClientImpl(secondDisplayInfo)); + + assertThat(mProxyManager.canRetrieveInteractiveWindowsLocked()).isTrue(); + } + + /** + * Tests that getting service interfaces to interrupt when AccessibilityManager#interrupt + * returns the registered proxy interface. + */ + @Test + public void testGetServiceInterfacesForInterrupt_defaultProxy_returnsProxyInterface() { + registerProxy(DISPLAY_ID); + final List<IAccessibilityServiceClient> interfacesToInterrupt = new ArrayList<>(); + mProxyManager.addServiceInterfacesLocked(interfacesToInterrupt, DEVICE_ID); + + assertThat(interfacesToInterrupt.size()).isEqualTo(1); + assertThat(interfacesToInterrupt.get(0).asBinder()).isEqualTo(mMockServiceAsBinder); + } + + /** Tests that the default timeout (0) is returned when the proxy is registered. */ + @Test + public void getRecommendedTimeout_defaultProxyInfo_getsDefaultTimeout() { + registerProxy(DISPLAY_ID); + final long timeout = mProxyManager.getRecommendedTimeoutMillisLocked(DEVICE_ID); + final int interactiveTimeout = IntPair.first(timeout); + final int nonInteractiveTimeout = IntPair.second(timeout); + + assertThat(interactiveTimeout).isEqualTo(0); + assertThat(nonInteractiveTimeout).isEqualTo(0); + } + + /** Tests that the manager returns the updated timeout when the proxy’s timeout is updated. */ + @Test + public void getRecommendedTimeout_updateTimeout_getsUpdatedTimeout() { + registerProxy(DISPLAY_ID); + + mProxyManager.updateTimeoutsIfNeeded(NON_INTERACTIVE_UI_TIMEOUT_100MS, + INTERACTIVE_UI_TIMEOUT_200MS); + + final long updatedTimeout = mProxyManager.getRecommendedTimeoutMillisLocked(DEVICE_ID); + final int updatedInteractiveTimeout = IntPair.first(updatedTimeout); + final int updatedNonInteractiveTimeout = IntPair.second(updatedTimeout); + + assertThat(updatedInteractiveTimeout).isEqualTo(INTERACTIVE_UI_TIMEOUT_200MS); + assertThat(updatedNonInteractiveTimeout).isEqualTo(NON_INTERACTIVE_UI_TIMEOUT_100MS); + } + + /** Tests that the system’s default focus color is returned. */ + @Test + public void testGetFocusColor_defaultProxy_getsDefaultSystemColor() { + registerProxy(DISPLAY_ID); + final int focusColor = mProxyManager.getFocusColorLocked(DEVICE_ID); + assertThat(focusColor).isEqualTo(mFocusColorDefaultValue); + } + + /** Tests that the system’s default focus stroke width is returned. */ + @Test + public void testGetFocusStrokeWidth_defaultProxy_getsDefaultSystemWidth() { + registerProxy(DISPLAY_ID); + final int focusStrokeWidth = mProxyManager.getFocusStrokeWidthLocked(DEVICE_ID); + assertThat(focusStrokeWidth).isEqualTo(mFocusStrokeWidthDefaultValue); + } + + private void registerProxy(int displayId) { + try { + mProxyManager.registerProxy(mMockAccessibilityServiceClient, displayId, anyInt(), + mMockSecurityPolicy, mMockConnectionSystemSupport, + mMockA11yTrace, mMockWindowManagerInternal); + } catch (RemoteException e) { + fail("Failed to register proxy " + e); + } + } + + private void registerProxy(int displayId, AccessibilityServiceClientImpl serviceClient) { + try { + mProxyManager.registerProxy(serviceClient, displayId, anyInt(), + mMockSecurityPolicy, mMockConnectionSystemSupport, + mMockA11yTrace, mMockWindowManagerInternal); + } catch (RemoteException e) { + fail("Failed to register proxy " + e); + } + } + + /** + * IAccessibilityServiceClient implementation. + * A proxy connection does not populate non-default AccessibilityServiceInfo values until the + * proxy is connected in A11yDisplayProxy#onServiceConnected. For tests that check for + * non-default values, populate immediately in this testing class, since a real Service is not + * being used and connected. + */ + static class AccessibilityServiceClientImpl extends IAccessibilityServiceClient.Stub { + List<AccessibilityServiceInfo> mInstalledAndEnabledServices; + + AccessibilityServiceClientImpl(AccessibilityServiceInfo + installedAndEnabledService) { + mInstalledAndEnabledServices = List.of(installedAndEnabledService); + } + + @Override + public void init(IAccessibilityServiceConnection connection, int connectionId, + IBinder windowToken) throws RemoteException { + connection.setInstalledAndEnabledServices(mInstalledAndEnabledServices); + } + + @Override + public void onAccessibilityEvent(AccessibilityEvent event, boolean serviceWantsEvent) + throws RemoteException { + + } + + @Override + public void onInterrupt() throws RemoteException { + + } + + @Override + public void onGesture(AccessibilityGestureEvent gestureEvent) throws RemoteException { + + } + + @Override + public void clearAccessibilityCache() throws RemoteException { + + } + + @Override + public void onKeyEvent(KeyEvent event, int sequence) throws RemoteException { + + } + + @Override + public void onMagnificationChanged(int displayId, Region region, MagnificationConfig config) + throws RemoteException { + + } + + @Override + public void onMotionEvent(MotionEvent event) throws RemoteException { + + } + + @Override + public void onTouchStateChanged(int displayId, int state) throws RemoteException { + + } + + @Override + public void onSoftKeyboardShowModeChanged(int showMode) throws RemoteException { + + } + + @Override + public void onPerformGestureResult(int sequence, boolean completedSuccessfully) + throws RemoteException { + + } + + @Override + public void onFingerprintCapturingGesturesChanged(boolean capturing) + throws RemoteException { + + } + + @Override + public void onFingerprintGesture(int gesture) throws RemoteException { + + } + + @Override + public void onAccessibilityButtonClicked(int displayId) throws RemoteException { + + } + + @Override + public void onAccessibilityButtonAvailabilityChanged(boolean available) + throws RemoteException { + + } + + @Override + public void onSystemActionsChanged() throws RemoteException { + + } + + @Override + public void createImeSession(IAccessibilityInputMethodSessionCallback callback) + throws RemoteException { + + } + + @Override + public void setImeSessionEnabled(IAccessibilityInputMethodSession session, boolean enabled) + throws RemoteException { + + } + + @Override + public void bindInput() throws RemoteException { + + } + + @Override + public void unbindInput() throws RemoteException { + + } + + @Override + public void startInput(IRemoteAccessibilityInputConnection connection, + EditorInfo editorInfo, boolean restarting) throws RemoteException { + + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java index d7b12e031c35..e6d3bbc53c83 100644 --- a/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java @@ -19,10 +19,13 @@ package com.android.server.display.brightness; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import android.content.Context; @@ -66,25 +69,27 @@ public final class DisplayBrightnessControllerTest { @Mock private HandlerExecutor mBrightnessChangeExecutor; + private final DisplayBrightnessController.Injector mInjector = new + DisplayBrightnessController.Injector() { + @Override + DisplayBrightnessStrategySelector getDisplayBrightnessStrategySelector( + Context context, int displayId) { + return mDisplayBrightnessStrategySelector; + } + }; + private DisplayBrightnessController mDisplayBrightnessController; @Before public void before() { MockitoAnnotations.initMocks(this); when(mContext.getResources()).thenReturn(mResources); - DisplayBrightnessController.Injector injector = new DisplayBrightnessController.Injector() { - @Override - DisplayBrightnessStrategySelector getDisplayBrightnessStrategySelector( - Context context, int displayId) { - return mDisplayBrightnessStrategySelector; - } - }; when(mBrightnessSetting.getBrightness()).thenReturn(Float.NaN); when(mBrightnessSetting.getBrightnessNitsForDefaultDisplay()).thenReturn(-1f); when(mResources.getBoolean( com.android.internal.R.bool.config_persistBrightnessNitsForDefaultDisplay)) .thenReturn(true); - mDisplayBrightnessController = new DisplayBrightnessController(mContext, injector, + mDisplayBrightnessController = new DisplayBrightnessController(mContext, mInjector, DISPLAY_ID, DEFAULT_BRIGHTNESS, mBrightnessSetting, mOnBrightnessChangeRunnable, mBrightnessChangeExecutor); } @@ -257,27 +262,6 @@ public final class DisplayBrightnessControllerTest { } @Test - public void testBrightnessNitsForDefaultDisplay() { - float brightness = 0.3f; - float nits = 500; - AutomaticBrightnessController automaticBrightnessController = - mock(AutomaticBrightnessController.class); - when(automaticBrightnessController.convertToFloatScale(nits)).thenReturn(brightness); - when(mBrightnessSetting.getBrightnessNitsForDefaultDisplay()).thenReturn(nits); - - mDisplayBrightnessController.setAutomaticBrightnessController( - automaticBrightnessController); - assertEquals(brightness, mDisplayBrightnessController.getCurrentBrightness(), - /* delta= */ 0); - - float newBrightness = 0.5f; - float newNits = 700; - when(automaticBrightnessController.convertToNits(newBrightness)).thenReturn(newNits); - mDisplayBrightnessController.setBrightness(newBrightness); - verify(mBrightnessSetting).setBrightnessNitsForDefaultDisplay(newNits); - } - - @Test public void testConvertToNits() { final float brightness = 0.5f; final float nits = 300; @@ -330,4 +314,48 @@ public final class DisplayBrightnessControllerTest { mDisplayBrightnessController.stop(); verify(mBrightnessSetting).unregisterListener(brightnessSettingListener); } + + @Test + public void testLoadNitBasedBrightnessSetting() { + // When the nits value is valid, the brightness is set from the old default display nits + // value + float nits = 200f; + float brightness = 0.3f; + AutomaticBrightnessController automaticBrightnessController = + mock(AutomaticBrightnessController.class); + when(automaticBrightnessController.convertToFloatScale(nits)).thenReturn(brightness); + when(mBrightnessSetting.getBrightnessNitsForDefaultDisplay()).thenReturn(nits); + mDisplayBrightnessController.setAutomaticBrightnessController( + automaticBrightnessController); + verify(mBrightnessSetting).setBrightness(brightness); + assertEquals(brightness, mDisplayBrightnessController.getCurrentBrightness(), 0.01f); + clearInvocations(automaticBrightnessController, mBrightnessSetting); + + // When the nits value is invalid, the brightness is resumed from where it was last set + nits = -1; + brightness = 0.4f; + when(automaticBrightnessController.convertToFloatScale(nits)).thenReturn(brightness); + when(mBrightnessSetting.getBrightnessNitsForDefaultDisplay()).thenReturn(nits); + when(mBrightnessSetting.getBrightness()).thenReturn(brightness); + mDisplayBrightnessController.setAutomaticBrightnessController( + automaticBrightnessController); + verify(mBrightnessSetting, never()).setBrightness(brightness); + assertEquals(brightness, mDisplayBrightnessController.getCurrentBrightness(), 0.01f); + clearInvocations(automaticBrightnessController, mBrightnessSetting); + + // When the display is a non-default display, the brightness is resumed from where it was + // last set + int nonDefaultDisplayId = 1; + mDisplayBrightnessController = new DisplayBrightnessController(mContext, mInjector, + nonDefaultDisplayId, DEFAULT_BRIGHTNESS, mBrightnessSetting, + mOnBrightnessChangeRunnable, mBrightnessChangeExecutor); + brightness = 0.5f; + when(mBrightnessSetting.getBrightness()).thenReturn(brightness); + mDisplayBrightnessController.setAutomaticBrightnessController( + automaticBrightnessController); + assertEquals(brightness, mDisplayBrightnessController.getCurrentBrightness(), 0.01f); + verifyZeroInteractions(automaticBrightnessController); + verify(mBrightnessSetting, never()).getBrightnessNitsForDefaultDisplay(); + verify(mBrightnessSetting, never()).setBrightness(brightness); + } } diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java index 5751db0727e7..275533fb1c37 100644 --- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java @@ -446,6 +446,25 @@ public class MediaProjectionManagerServiceTest { } @Test + public void testSetUserReviewGrantedConsentResult_projectionNull_consentNotGranted() + throws Exception { + MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(); + projection.start(mIMediaProjectionCallback); + assertThat(mService.isCurrentProjection(projection)).isTrue(); + doReturn(true).when(mWindowManagerInternal).setContentRecordingSession( + any(ContentRecordingSession.class)); + // Some other token. + final IMediaProjection otherProjection = null; + // Waiting for user to review consent. + mService.setContentRecordingSession(mWaitingDisplaySession); + mService.setUserReviewGrantedConsentResult(RECORD_CANCEL, otherProjection); + + // Display result is ignored; only the first session is set. + verify(mWindowManagerInternal, times(1)).setContentRecordingSession( + eq(mWaitingDisplaySession)); + } + + @Test public void testSetUserReviewGrantedConsentResult_noVirtualDisplay() throws Exception { MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(); projection.start(mIMediaProjectionCallback); 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 0033e3e368c6..cb984f814f1a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -851,7 +851,7 @@ public class ActivityRecordTests extends WindowTestsBase { } @Override - public void onAnimationCancelled(boolean isKeyguardOccluded) { + public void onAnimationCancelled() { } }, 0, 0)); activity.updateOptionsLocked(opts); @@ -3124,7 +3124,7 @@ public class ActivityRecordTests extends WindowTestsBase { .setSystemDecorations(true).build(); // Add a decor insets provider window. final WindowState navbar = createNavBarWithProvidedInsets(squareDisplay); - assertTrue(navbar.providesNonDecorInsets() + assertTrue(navbar.providesDisplayDecorInsets() && squareDisplay.getDisplayPolicy().updateDecorInsetsInfo()); squareDisplay.sendNewConfiguration(); final Task task = new TaskBuilder(mSupervisor).setDisplay(squareDisplay).build(); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java index 6d1312458ce2..169968c75fc5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java @@ -87,7 +87,7 @@ public class AppChangeTransitionTests extends WindowTestsBase { } @Override - public void onAnimationCancelled(boolean isKeyguardOccluded) { + public void onAnimationCancelled() { } @Override diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java index 0ae579bab413..a11079be85ab 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java @@ -735,7 +735,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { } @Override - public void onAnimationCancelled(boolean isKeyguardOccluded) throws RemoteException { + public void onAnimationCancelled() throws RemoteException { mFinishedCallback = null; } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java index 59cc4f5b0948..ba8c94dd9218 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -549,7 +549,7 @@ public class AppTransitionTests extends WindowTestsBase { } @Override - public void onAnimationCancelled(boolean isKeyguardOccluded) { + public void onAnimationCancelled() { mCancelled = true; } diff --git a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java index 06b4ad975a87..7b4392b5e15d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java @@ -50,7 +50,6 @@ import android.platform.test.annotations.Presubmit; import android.util.Log; import android.view.IWindowManager; -import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import com.android.server.am.AssistDataRequester; @@ -155,7 +154,6 @@ public class AssistDataRequesterTest { } @Test - @FlakyTest(bugId = 130388718) public void testRequestData() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, CALLER_ASSIST_SCREENSHOT_ALLOWED); @@ -263,7 +261,6 @@ public class AssistDataRequesterTest { } @Test - @FlakyTest(bugId = 130388718) public void testNoFetchScreenshots_expectNoScreenshotCallbacks() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, CALLER_ASSIST_SCREENSHOT_ALLOWED); @@ -275,7 +272,6 @@ public class AssistDataRequesterTest { } @Test - @FlakyTest(bugId = 130388718) public void testDisallowAssistScreenshot_expectNullScreenshotCallback() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, !CALLER_ASSIST_SCREENSHOT_ALLOWED); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java index c8fdee06f3e4..353a8ecaf13d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java @@ -45,6 +45,8 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -298,20 +300,27 @@ public class DisplayPolicyTests extends WindowTestsBase { @Test public void testUpdateDisplayConfigurationByDecor() { + doReturn(NO_CUTOUT).when(mDisplayContent).calculateDisplayCutoutForRotation(anyInt()); final WindowState navbar = createNavBarWithProvidedInsets(mDisplayContent); final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy(); final DisplayInfo di = mDisplayContent.getDisplayInfo(); final int prevScreenHeightDp = mDisplayContent.getConfiguration().screenHeightDp; - assertTrue(navbar.providesNonDecorInsets() && displayPolicy.updateDecorInsetsInfo()); + assertTrue(navbar.providesDisplayDecorInsets() && displayPolicy.updateDecorInsetsInfo()); assertEquals(NAV_BAR_HEIGHT, displayPolicy.getDecorInsetsInfo(di.rotation, di.logicalWidth, di.logicalHeight).mConfigInsets.bottom); mDisplayContent.sendNewConfiguration(); assertNotEquals(prevScreenHeightDp, mDisplayContent.getConfiguration().screenHeightDp); - assertFalse(navbar.providesNonDecorInsets() && displayPolicy.updateDecorInsetsInfo()); + assertFalse(navbar.providesDisplayDecorInsets() && displayPolicy.updateDecorInsetsInfo()); navbar.removeIfPossible(); assertEquals(0, displayPolicy.getDecorInsetsInfo(di.rotation, di.logicalWidth, di.logicalHeight).mNonDecorInsets.bottom); + + final WindowState statusBar = createStatusBarWithProvidedInsets(mDisplayContent); + assertTrue(statusBar.providesDisplayDecorInsets() + && displayPolicy.updateDecorInsetsInfo()); + assertEquals(STATUS_BAR_HEIGHT, displayPolicy.getDecorInsetsInfo(di.rotation, + di.logicalWidth, di.logicalHeight).mConfigInsets.top); } @SetupWindows(addWindows = { W_NAVIGATION_BAR, W_INPUT_METHOD }) diff --git a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java index 027f90333561..8cf2776b85e9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java @@ -27,7 +27,6 @@ import static org.junit.Assert.assertTrue; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; -import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import org.junit.After; @@ -110,7 +109,6 @@ public class PersisterQueueTests { } @Test - @FlakyTest(bugId = 131005232) public void testProcessOneItem_Flush() throws Exception { mFactory.setExpectedProcessedItemNumber(1); mListener.setExpectedOnPreProcessItemCallbackTimes(1); @@ -162,7 +160,6 @@ public class PersisterQueueTests { } @Test - @FlakyTest(bugId = 128526085) public void testProcessTwoItems_OneAfterAnother() throws Exception { // First item mFactory.setExpectedProcessedItemNumber(1); diff --git a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java index 0db983c6396c..c4d03bebc751 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java @@ -37,7 +37,6 @@ import android.view.Surface; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.server.wm.RefreshRatePolicy.FrameRateVote; @@ -53,7 +52,6 @@ import org.junit.runner.RunWith; @SmallTest @Presubmit @RunWith(WindowTestRunner.class) -@FlakyTest public class RefreshRatePolicyTest extends WindowTestsBase { private static final int HI_MODE_ID = 1; private static final float HI_REFRESH_RATE = 90; diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java index eb26415c2b21..11d9629cf25e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java @@ -211,7 +211,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN); adapter.onAnimationCancelled(mMockLeash); - verify(mMockRunner).onAnimationCancelled(anyBoolean()); + verify(mMockRunner).onAnimationCancelled(); } @Test @@ -227,7 +227,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { mClock.fastForward(10500); mHandler.timeAdvance(); - verify(mMockRunner).onAnimationCancelled(anyBoolean()); + verify(mMockRunner).onAnimationCancelled(); verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION), eq(adapter)); } @@ -248,12 +248,12 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { mClock.fastForward(10500); mHandler.timeAdvance(); - verify(mMockRunner, never()).onAnimationCancelled(anyBoolean()); + verify(mMockRunner, never()).onAnimationCancelled(); mClock.fastForward(52500); mHandler.timeAdvance(); - verify(mMockRunner).onAnimationCancelled(anyBoolean()); + verify(mMockRunner).onAnimationCancelled(); verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION), eq(adapter)); } finally { @@ -265,7 +265,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { public void testZeroAnimations() throws Exception { mController.goodToGo(TRANSIT_OLD_NONE); verify(mMockRunner, never()).onAnimationStart(anyInt(), any(), any(), any(), any()); - verify(mMockRunner).onAnimationCancelled(anyBoolean()); + verify(mMockRunner).onAnimationCancelled(); } @Test @@ -275,7 +275,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { new Point(50, 100), null, new Rect(50, 100, 150, 150), null, false); mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN); verify(mMockRunner, never()).onAnimationStart(anyInt(), any(), any(), any(), any()); - verify(mMockRunner).onAnimationCancelled(anyBoolean()); + verify(mMockRunner).onAnimationCancelled(); } @Test @@ -317,7 +317,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { win.mActivityRecord.removeImmediately(); mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN); verify(mMockRunner, never()).onAnimationStart(anyInt(), any(), any(), any(), any()); - verify(mMockRunner).onAnimationCancelled(anyBoolean()); + verify(mMockRunner).onAnimationCancelled(); verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION), eq(adapter)); } @@ -575,7 +575,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { // Cancel the wallpaper window animator and ensure the runner is not canceled wallpaperWindowToken.cancelAnimation(); - verify(mMockRunner, never()).onAnimationCancelled(anyBoolean()); + verify(mMockRunner, never()).onAnimationCancelled(); } finally { mDisplayContent.mOpeningApps.clear(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java index ff753f21d01b..339162a02301 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java @@ -98,7 +98,6 @@ public class SurfaceAnimationRunnerTest { mFinishCallbackLatch.countDown(); } - @FlakyTest(bugId = 144611135) @Test public void testAnimation() throws Exception { mSurfaceAnimationRunner diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java index 790b15443198..453e4684e859 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java @@ -52,7 +52,6 @@ import android.view.Display; import android.view.ViewGroup; import android.widget.LinearLayout; -import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import org.junit.After; @@ -319,7 +318,6 @@ public class TaskStackChangedListenerTest { }; @Presubmit - @FlakyTest(bugId = 150409355) @Test public void testNotifyTaskRequestedOrientationChanged() throws Exception { final ArrayBlockingQueue<int[]> taskIdAndOrientationQueue = new ArrayBlockingQueue<>(10); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java index a1ddd5748002..ad606cb90841 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -1112,7 +1112,7 @@ public class WindowContainerTests extends WindowTestsBase { } @Override - public void onAnimationCancelled(boolean isKeyguardOccluded) { + public void onAnimationCancelled() { } }, 0, 0, false); adapter.setCallingPidUid(123, 456); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java index 0b1b877c27de..2ae117214dd3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java @@ -26,7 +26,6 @@ import static org.mockito.ArgumentMatchers.any; import android.hardware.HardwareBuffer; import android.platform.test.annotations.Presubmit; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Test; @@ -55,7 +54,6 @@ public class WindowContainerThumbnailTest extends WindowTestsBase { } @Test - @FlakyTest(bugId = 131005232) public void testDestroy_nullsSurface() { final WindowContainerThumbnail t = buildThumbnail(); assertNotNull(t.getSurfaceControl()); 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 07244a4f2478..a63807d23a14 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -471,6 +471,17 @@ class WindowTestsBase extends SystemServiceTestsBase { return navbar; } + WindowState createStatusBarWithProvidedInsets(DisplayContent dc) { + final WindowState statusBar = createWindow(null, TYPE_STATUS_BAR, dc, "statusBar"); + final Binder owner = new Binder(); + statusBar.mAttrs.providedInsets = new InsetsFrameProvider[] { + new InsetsFrameProvider(owner, 0, WindowInsets.Type.statusBars()) + .setInsetsSize(Insets.of(0, STATUS_BAR_HEIGHT, 0, 0)) + }; + dc.getDisplayPolicy().addWindowLw(statusBar, statusBar.mAttrs); + return statusBar; + } + WindowState createAppWindow(Task task, int type, String name) { final ActivityRecord activity = createNonAttachedActivityRecord(task.getDisplayContent()); task.addChild(activity, 0); diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java index 10b7952acab2..ba178845a536 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java @@ -584,15 +584,34 @@ public final class UsbDescriptorParser { } /** + * Returns true only if there is a terminal whose subtype and terminal type are the same as + * the given values. * @hide */ - public boolean hasAudioTerminal(int subType) { + public boolean hasAudioTerminal(int subType, int terminalType) { for (UsbDescriptor descriptor : mDescriptors) { - if (descriptor instanceof UsbACInterface) { - if (((UsbACInterface) descriptor).getSubclass() - == UsbDescriptor.AUDIO_AUDIOCONTROL - && ((UsbACInterface) descriptor).getSubtype() - == subType) { + if (descriptor instanceof UsbACTerminal) { + if (((UsbACTerminal) descriptor).getSubclass() == UsbDescriptor.AUDIO_AUDIOCONTROL + && ((UsbACTerminal) descriptor).getSubtype() == subType + && ((UsbACTerminal) descriptor).getTerminalType() == terminalType) { + return true; + } + } + } + return false; + } + + /** + * Returns true only if there is an interface whose subtype is the same as the given one and + * terminal type is different from the given one. + * @hide + */ + public boolean hasAudioTerminalExcludeType(int subType, int excludedTerminalType) { + for (UsbDescriptor descriptor : mDescriptors) { + if (descriptor instanceof UsbACTerminal) { + if (((UsbACTerminal) descriptor).getSubclass() == UsbDescriptor.AUDIO_AUDIOCONTROL + && ((UsbACTerminal) descriptor).getSubtype() == subType + && ((UsbACTerminal) descriptor).getTerminalType() != excludedTerminalType) { return true; } } @@ -604,14 +623,21 @@ public final class UsbDescriptorParser { * @hide */ public boolean hasAudioPlayback() { - return hasAudioTerminal(UsbACInterface.ACI_OUTPUT_TERMINAL); + return hasAudioTerminalExcludeType( + UsbACInterface.ACI_OUTPUT_TERMINAL, UsbTerminalTypes.TERMINAL_USB_STREAMING) + && hasAudioTerminal( + UsbACInterface.ACI_INPUT_TERMINAL, UsbTerminalTypes.TERMINAL_USB_STREAMING); } /** * @hide */ public boolean hasAudioCapture() { - return hasAudioTerminal(UsbACInterface.ACI_INPUT_TERMINAL); + return hasAudioTerminalExcludeType( + UsbACInterface.ACI_INPUT_TERMINAL, UsbTerminalTypes.TERMINAL_USB_STREAMING) + && hasAudioTerminal( + UsbACInterface.ACI_OUTPUT_TERMINAL, + UsbTerminalTypes.TERMINAL_USB_STREAMING); } /** diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 9dd2a61671ec..26590c4704c3 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -744,10 +744,6 @@ public class TelecomManager { * state of calls in the self-managed {@link ConnectionService}. An example use-case is * exposing these calls to an automotive device via its companion app. * <p> - * This meta-data can only be set for an {@link InCallService} which also sets - * {@link #METADATA_IN_CALL_SERVICE_UI}. Only the default phone/dialer app, or a car-mode - * {@link InCallService} can see self-managed calls. - * <p> * See also {@link Connection#PROPERTY_SELF_MANAGED}. */ public static final String METADATA_INCLUDE_SELF_MANAGED_CALLS = diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index 1ce85ba93d95..28ea5a681730 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -1186,6 +1186,7 @@ public class ApnSetting implements Parcelable { ApnSetting other = (ApnSetting) o; return mEntryName.equals(other.mEntryName) + && Objects.equals(mId, other.mId) && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) && Objects.equals(mApnName, other.mApnName) && Objects.equals(mProxyAddress, other.mProxyAddress) @@ -1337,6 +1338,14 @@ public class ApnSetting implements Parcelable { public ContentValues toContentValues() { ContentValues apnValue = new ContentValues(); apnValue.put(Telephony.Carriers.NUMERIC, nullToEmpty(mOperatorNumeric)); + // If the APN is editable, the user may be able to set an invalid numeric. The numeric must + // always be 5 or 6 characters (depending on the length of the MNC), so skip if it is + // potentially invalid. + if (!TextUtils.isEmpty(mOperatorNumeric) + && (mOperatorNumeric.length() == 5 || mOperatorNumeric.length() == 6)) { + apnValue.put(Telephony.Carriers.MCC, mOperatorNumeric.substring(0, 3)); + apnValue.put(Telephony.Carriers.MNC, mOperatorNumeric.substring(3)); + } apnValue.put(Telephony.Carriers.NAME, nullToEmpty(mEntryName)); apnValue.put(Telephony.Carriers.APN, nullToEmpty(mApnName)); apnValue.put(Telephony.Carriers.PROXY, nullToEmpty(mProxyAddress)); @@ -1356,6 +1365,7 @@ public class ApnSetting implements Parcelable { getProtocolStringFromInt(mRoamingProtocol)); apnValue.put(Telephony.Carriers.CARRIER_ENABLED, mCarrierEnabled); apnValue.put(Telephony.Carriers.MVNO_TYPE, getMvnoTypeStringFromInt(mMvnoType)); + apnValue.put(Telephony.Carriers.MVNO_MATCH_DATA, nullToEmpty(mMvnoMatchData)); apnValue.put(Telephony.Carriers.NETWORK_TYPE_BITMASK, mNetworkTypeBitmask); apnValue.put(Telephony.Carriers.LINGERING_NETWORK_TYPE_BITMASK, mLingeringNetworkTypeBitmask); diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt index 4e3ae0c0752a..efd9b004f8fd 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt @@ -18,7 +18,7 @@ package com.android.server.wm.flicker import android.app.Instrumentation import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.flicker.junit.FlickerBuilderProvider import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.FlickerTest 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 f389e13a6884..1f120d47a1ac 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt @@ -19,9 +19,9 @@ package com.android.server.wm.flicker import android.tools.common.PlatformConsts -import android.tools.common.datatypes.component.ComponentNameMatcher -import android.tools.common.datatypes.component.IComponentNameMatcher import android.tools.common.flicker.subject.region.RegionSubject +import android.tools.common.traces.component.ComponentNameMatcher +import android.tools.common.traces.component.IComponentNameMatcher import android.tools.common.traces.wm.WindowManagerTrace import android.tools.device.flicker.legacy.FlickerTest import android.tools.device.helpers.WindowUtils diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingSecondaryToSplitTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingSecondaryToSplitTest.kt index c3cbb84fd37f..863828881d36 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingSecondaryToSplitTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingSecondaryToSplitTest.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.activityembedding import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt index 5dc2dd7d93a8..10b71ff1efd7 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt @@ -40,20 +40,27 @@ import org.junit.runners.Parameterized * Launch an app [testApp] and wait animation to complete * Press back button * ``` + * * To run only the presubmit assertions add: `-- + * * ``` * --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest * --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Presubmit` * ``` + * * To run only the postsubmit assertions add: `-- + * * ``` * --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest * --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Postsubmit` * ``` + * * To run only the flaky assertions add: `-- + * * ``` * --module-arg FlickerTests:include-annotation:androidx.test.filters.FlakyTest` * ``` + * * Notes: * ``` * 1. Some default assertions (e.g., nav bar, status bar and screen covered) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt index b042a14b30da..e5bd350019c8 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt @@ -40,20 +40,27 @@ import org.junit.runners.Parameterized * Launch an app [testApp] and wait animation to complete * Press home button * ``` + * * To run only the presubmit assertions add: `-- + * * ``` * --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest * --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Presubmit` * ``` + * * To run only the postsubmit assertions add: `-- + * * ``` * --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest * --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Postsubmit` * ``` + * * To run only the flaky assertions add: `-- + * * ``` * --module-arg FlickerTests:include-annotation:androidx.test.filters.FlakyTest` * ``` + * * Notes: * ``` * 1. Some default assertions (e.g., nav bar, status bar and screen covered) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt index c4628aaa90af..4570fa23dc43 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.close import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.component.ComponentNameMatcher.Companion.LAUNCHER +import android.tools.common.traces.component.ComponentNameMatcher.Companion.LAUNCHER import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.FlickerTest 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 e531bc06fb3d..6053f1dc9319 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 @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.common.traces.wm.WindowManagerState.Companion.STATE_RESUMED import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.helpers.FIND_TIMEOUT diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt index afb9fbf47350..94ac1a6e1e02 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper class AppPairsHelper( diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt index 47dd4e9fb32d..c6fa1bb89220 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.traces.parsers.toFlickerComponent import com.android.server.wm.flicker.testapp.ActivityOptions diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt index d4f48fe8d50f..747cf3742bf7 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.traces.parsers.WindowManagerStateHelper import android.tools.device.traces.parsers.toFlickerComponent diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt index 73effbde4515..d1722521bba8 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.helpers.FIND_TIMEOUT import android.tools.device.traces.parsers.WindowManagerStateHelper diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt index a6e57d5641d6..7a8d780c3d9f 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.helpers.FIND_TIMEOUT import android.tools.device.traces.parsers.WindowManagerStateHelper import android.tools.device.traces.parsers.toFlickerComponent diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt index d61a500e3293..83a41abbd4bd 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt @@ -18,10 +18,10 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation import android.tools.common.Rotation -import android.tools.common.datatypes.component.ComponentNameMatcher -import android.tools.common.datatypes.component.IComponentMatcher import android.tools.common.traces.Condition import android.tools.common.traces.DeviceStateDump +import android.tools.common.traces.component.ComponentNameMatcher +import android.tools.common.traces.component.IComponentMatcher import android.tools.device.helpers.FIND_TIMEOUT import android.tools.device.helpers.IME_PACKAGE import android.tools.device.traces.parsers.WindowManagerStateHelper diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt index fb5e1d2da26b..b2aeb14aaf78 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.traces.parsers.toFlickerComponent import com.android.server.wm.flicker.testapp.ActivityOptions diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt index 1ccac13c280f..a670d68cabd9 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt @@ -17,15 +17,15 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import androidx.test.uiautomator.By -import androidx.test.uiautomator.Until -import com.android.server.wm.flicker.testapp.ActivityOptions -import android.tools.common.datatypes.component.ComponentNameMatcher -import android.tools.device.traces.parsers.toFlickerComponent -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.helpers.FIND_TIMEOUT import android.tools.device.helpers.SYSTEMUI_PACKAGE +import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.device.traces.parsers.toFlickerComponent +import androidx.test.uiautomator.By +import androidx.test.uiautomator.Until +import com.android.server.wm.flicker.testapp.ActivityOptions class LetterboxAppHelper @JvmOverloads @@ -37,13 +37,21 @@ constructor( ) : StandardAppHelper(instr, launcherName, component) { fun clickRestart(wmHelper: WindowManagerStateHelper) { - val restartButton = uiDevice.wait(Until.findObject(By.res( - SYSTEMUI_PACKAGE, "size_compat_restart_button")), FIND_TIMEOUT) + val restartButton = + uiDevice.wait( + Until.findObject(By.res(SYSTEMUI_PACKAGE, "size_compat_restart_button")), + FIND_TIMEOUT + ) restartButton?.run { restartButton.click() } ?: error("Restart button not found") // size compat mode restart confirmation dialog button - val restartDialogButton = uiDevice.wait(Until.findObject(By.res( - SYSTEMUI_PACKAGE, "letterbox_restart_dialog_restart_button")), FIND_TIMEOUT) + val restartDialogButton = + uiDevice.wait( + Until.findObject( + By.res(SYSTEMUI_PACKAGE, "letterbox_restart_dialog_restart_button") + ), + FIND_TIMEOUT + ) restartDialogButton?.run { restartDialogButton.click() } ?: error("Restart dialog button not found") wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt index ab916858858a..c98f1c4b4d29 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.helpers.FIND_TIMEOUT import android.tools.device.traces.parsers.toFlickerComponent diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt index e93e9c8e9bfb..65175ef33afb 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt @@ -19,7 +19,7 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation import android.content.Context import android.provider.Settings -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper import android.util.Log import com.android.compatibility.common.util.SystemUtil diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt index c547ad06fe6c..5b3d3083fe1c 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.helpers.FIND_TIMEOUT import android.tools.device.traces.parsers.WindowManagerStateHelper diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt index 20ee3b9d236d..ee65004e9e78 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.traces.parsers.toFlickerComponent import com.android.server.wm.flicker.testapp.ActivityOptions diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt index 78f8bcf70b60..7665690a3122 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.helpers.FIND_TIMEOUT import android.tools.device.traces.parsers.WindowManagerStateHelper 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 c5a21a80d8d0..24e231c73a0f 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 @@ -21,8 +21,8 @@ import android.media.session.MediaController import android.media.session.MediaSessionManager import android.tools.common.datatypes.Rect import android.tools.common.datatypes.Region -import android.tools.common.datatypes.component.IComponentMatcher import android.tools.common.traces.ConditionsFactory +import android.tools.common.traces.component.IComponentMatcher import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.helpers.FIND_TIMEOUT import android.tools.device.helpers.SYSTEMUI_PACKAGE @@ -250,7 +250,8 @@ open class PipAppHelper(instrumentation: Instrumentation) : waitConditions = arrayOf(ConditionsFactory.hasPipWindow()) ) - wmHelper.StateSyncBuilder() + wmHelper + .StateSyncBuilder() .withWindowSurfaceAppeared(this) .withPipShown() .waitForAndVerify() diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt index 06e668ea07a1..cac3530399de 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.traces.parsers.toFlickerComponent import com.android.server.wm.flicker.testapp.ActivityOptions diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt index 94c90dabd2c8..8366a7a1fe41 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.traces.parsers.toFlickerComponent import com.android.server.wm.flicker.testapp.ActivityOptions diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt index 64af811d1c4f..89c6c35af47d 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.traces.parsers.toFlickerComponent import com.android.server.wm.flicker.testapp.ActivityOptions diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt index 316766a5c3f3..895725c1efef 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.helpers.FIND_TIMEOUT import android.tools.device.traces.parsers.WindowManagerStateHelper diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt index 34fa921f5777..7e0632d216ea 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt @@ -18,8 +18,8 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.Presubmit import android.tools.common.Rotation -import android.tools.common.datatypes.component.ComponentNameMatcher import android.tools.common.flicker.subject.region.RegionSubject +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt index 823328af57aa..7f496d828996 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt @@ -19,7 +19,7 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.IwTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt index df9d33bf2c8f..cbe03dcd932a 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt @@ -18,7 +18,7 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.Presubmit import android.tools.common.Rotation -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt index 7954dd13e906..82c390b77d59 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt @@ -18,7 +18,7 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.Presubmit import android.tools.common.Rotation -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt index 10ce5eab4f29..c693ca759bdd 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt @@ -18,7 +18,7 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.IwTest import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt index 579c10f62f52..8e3371986056 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt @@ -18,7 +18,7 @@ package com.android.server.wm.flicker.ime -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.flicker.legacy.FlickerTest fun FlickerTest.imeLayerBecomesVisible() { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt index 3f87aef16cdb..19bbf0cb92b0 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt @@ -18,8 +18,8 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.Presubmit import android.tools.common.NavBar import android.tools.common.Rotation -import android.tools.common.datatypes.component.ComponentNameMatcher import android.tools.common.flicker.subject.region.RegionSubject +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt index 6179fc2aef21..f64ad53bf2f7 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt @@ -18,7 +18,7 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.Presubmit import android.tools.common.Rotation -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt index 690ed53df5f2..11bc7b9f29c0 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt @@ -19,7 +19,7 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.Presubmit import android.tools.common.NavBar import android.tools.common.Rotation -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt index 866e858f3865..46967db55086 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt @@ -18,7 +18,7 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.Presubmit import android.tools.common.Rotation -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt index 6f225891f39c..277b91558416 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt @@ -18,7 +18,7 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.Presubmit import android.tools.common.Rotation -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt index 231d0d74c2a1..9275d6a2f17f 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt @@ -17,8 +17,8 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.component.ComponentNameMatcher import android.tools.common.traces.ConditionsFactory +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt index 3c577ac2db35..e6594c969373 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.launch import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTestCfArm.kt index 3289bc601160..ac05c7687311 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTestCfArm.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTestCfArm.kt @@ -41,4 +41,4 @@ class OpenAppAfterCameraTestCfArm(flicker: FlickerTest) : OpenAppAfterCameraTest return FlickerTestFactory.nonRotationTests() } } -}
\ No newline at end of file +} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt index d0dc42f29b9e..26f88d23cda0 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt @@ -23,9 +23,9 @@ import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.FlickerTest import android.tools.device.flicker.legacy.FlickerTestFactory +import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.helpers.setRotation -import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -42,6 +42,7 @@ import org.junit.runners.Parameterized * Make sure no apps are running on the device * Launch an app [testApp] and wait animation to complete * ``` + * * Notes: * ``` * 1. Some default assertions (e.g., nav bar, status bar and screen covered) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTestCfArm.kt index f75d9eede25b..d9a99dadbd3d 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTestCfArm.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTestCfArm.kt @@ -49,4 +49,4 @@ class OpenAppColdTestCfArm(flicker: FlickerTest) : OpenAppColdTest(flicker) { return FlickerTestFactory.nonRotationTests() } } -}
\ No newline at end of file +} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt index 1a1d4036579f..3d5a8e309b10 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.launch import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.flicker.legacy.FlickerTest import com.android.server.wm.flicker.replacesLayer import org.junit.Test diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt index b1a267ac27b4..b21777b30b21 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt @@ -78,9 +78,7 @@ open class OpenAppFromLockNotificationCold(flicker: FlickerTest) : override fun taskBarLayerIsVisibleAtStartAndEnd() {} /** {@inheritDoc} */ - @Test - @Ignore("Display is off at the start") - override fun taskBarWindowIsAlwaysVisible() {} + @Test @Ignore("Display is off at the start") override fun taskBarWindowIsAlwaysVisible() {} /** {@inheritDoc} */ @Test diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt index e41432555ded..ec92ca65f80a 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt @@ -20,7 +20,7 @@ import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.Presubmit import android.platform.test.rule.SettingOverrideRule import android.provider.Settings -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt index 0b09e248b221..009d61797fe0 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt @@ -19,7 +19,7 @@ package com.android.server.wm.flicker.launch import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest @@ -113,9 +113,7 @@ class OpenAppFromLockNotificationWithLockOverlayApp(flicker: FlickerTest) : @Test override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible() - @Presubmit - @Test - override fun entireScreenCovered() = super.entireScreenCovered() + @Presubmit @Test override fun entireScreenCovered() = super.entireScreenCovered() @FlakyTest(bugId = 278227468) @Test diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt index 730f78ff3bc2..eae9ca10c711 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt @@ -18,7 +18,7 @@ package com.android.server.wm.flicker.launch import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.FlickerTest import com.android.server.wm.flicker.navBarLayerPositionAtEnd diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt index 9c16b7938e73..7bcb91070ecf 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt @@ -18,7 +18,7 @@ package com.android.server.wm.flicker.launch import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdCfArm.kt index 4aa78d4482fb..8b4a613305c0 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdCfArm.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdCfArm.kt @@ -44,4 +44,4 @@ class OpenAppFromNotificationColdCfArm(flicker: FlickerTest) : return FlickerTestFactory.nonRotationTests() } } -}
\ No newline at end of file +} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt index 23cb1d49619f..425e674dec3a 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt @@ -18,7 +18,7 @@ package com.android.server.wm.flicker.launch import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt index 00d7544f7217..8e1b059b2bc7 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt @@ -44,6 +44,7 @@ import org.junit.runners.Parameterized * Relaunch an app [testApp] by selecting it in the overview screen, and wait animation to * complete (only this action is traced) * ``` + * * Notes: * ``` * 1. Some default assertions (e.g., nav bar, status bar and screen covered) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt index 17f5638a1a50..1383ae39f760 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt @@ -20,7 +20,7 @@ import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.Presubmit import android.tools.common.NavBar import android.tools.common.Rotation -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.flicker.annotation.FlickerServiceCompatible import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerTest @@ -47,6 +47,7 @@ import org.junit.runners.Parameterized * Lock the device. * Launch an app on top of the lock screen [testApp] and wait animation to complete * ``` + * * Notes: * ``` * 1. Some default assertions (e.g., nav bar, status bar and screen covered) @@ -161,9 +162,7 @@ open class OpenAppNonResizeableTest(flicker: FlickerTest) : OpenAppFromLockTrans super.appWindowBecomesFirstAndOnlyTopWindow() /** {@inheritDoc} */ - @Presubmit - @Test - override fun appWindowBecomesVisible() = super.appWindowBecomesVisible() + @Presubmit @Test override fun appWindowBecomesVisible() = super.appWindowBecomesVisible() /** Checks the [ComponentNameMatcher.NAV_BAR] is visible at the end of the transition */ @Presubmit diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt index e0db96f3b5c6..87a14c69e3ac 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.launch import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt index cdd2d45769bb..3385830ee77f 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt @@ -42,6 +42,7 @@ import org.junit.runners.Parameterized * Press home * Relaunch an app [testApp] and wait animation to complete (only this action is traced) * ``` + * * Notes: * ``` * 1. Some default assertions (e.g., nav bar, status bar and screen covered) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTestCfArm.kt index 9679059e5069..d8b38b30cf13 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTestCfArm.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTestCfArm.kt @@ -43,4 +43,4 @@ class OpenAppWarmTestCfArm(flicker: FlickerTest) : OpenAppWarmTest(flicker) { return FlickerTestFactory.nonRotationTests() } } -}
\ No newline at end of file +} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt index b848e63c9c87..b48611edd738 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt @@ -20,20 +20,20 @@ import android.app.Instrumentation import android.os.Bundle import android.os.Handler import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.component.ComponentNameMatcher import android.tools.common.traces.ConditionsFactory +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.flicker.junit.FlickerBuilderProvider import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.FlickerTest import android.tools.device.flicker.legacy.FlickerTestFactory +import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule +import android.tools.device.helpers.wakeUpAndGoToHomeScreen import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry import com.android.server.wm.flicker.R -import com.android.server.wm.flicker.helpers.setRotation -import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule -import android.tools.device.helpers.wakeUpAndGoToHomeScreen import com.android.server.wm.flicker.helpers.SimpleAppHelper +import com.android.server.wm.flicker.helpers.setRotation import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt index be735477dc40..d0fd73207c42 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt @@ -21,11 +21,11 @@ import android.app.WallpaperManager import android.content.res.Resources import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.component.ComponentNameMatcher -import android.tools.common.datatypes.component.ComponentNameMatcher.Companion.SPLASH_SCREEN -import android.tools.common.datatypes.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER -import android.tools.common.datatypes.component.ComponentSplashScreenMatcher -import android.tools.common.datatypes.component.IComponentMatcher +import android.tools.common.traces.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher.Companion.SPLASH_SCREEN +import android.tools.common.traces.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER +import android.tools.common.traces.component.ComponentSplashScreenMatcher +import android.tools.common.traces.component.IComponentMatcher import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt index eadeef5bf3e6..a8b80ad1d16c 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt @@ -20,7 +20,7 @@ import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.Presubmit import android.tools.common.NavBar import android.tools.common.datatypes.Rect -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt index 136049533350..96cd8ffa3eff 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt @@ -20,7 +20,7 @@ import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.Presubmit import android.tools.common.NavBar import android.tools.common.datatypes.Rect -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt index d49f035fa84a..7e935f03aeb1 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt @@ -21,7 +21,7 @@ import android.platform.test.annotations.Presubmit import android.tools.common.NavBar import android.tools.common.Rotation import android.tools.common.datatypes.Rect -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt index fe789a7a7384..855ea3e38b3e 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt @@ -18,7 +18,7 @@ package com.android.server.wm.flicker.rotation import android.platform.test.annotations.IwTest import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt index 3c0bbd6c4c1c..fe9da335a675 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.rotation import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.FlickerTest diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt index 4d010f35d4eb..0cbbb83b48ee 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt @@ -19,7 +19,7 @@ package com.android.server.wm.flicker.rotation import android.platform.test.annotations.IwTest import android.platform.test.annotations.Presubmit import android.tools.common.ScenarioBuilder -import android.tools.common.datatypes.component.ComponentNameMatcher +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.FlickerTest |