diff options
279 files changed, 5174 insertions, 1817 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..9ba94c8b9d11 100644 --- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java +++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java @@ -69,6 +69,8 @@ import java.io.IOException; import java.util.ArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicReference; /** * Perf tests for user life cycle events. @@ -101,7 +103,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"; @@ -1471,17 +1472,10 @@ 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 + 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 +1538,11 @@ public class UserLifecycleTests { } private void waitForBroadcastIdle() { - ShellHelper.runShellCommand("am wait-for-broadcast-idle"); + try { + 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) { @@ -1560,4 +1558,41 @@ public class UserLifecycleTests { waitForBroadcastIdle(); sleep(tenSeconds); } + + /** + * Runs a Shell command with a timeout, returning a trimmed response. + */ + private String runShellCommandWithTimeout(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(ShellHelper.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) { + Log.e(TAG, "Command: '" + command + "' failed.", exception.get()); + throw new RuntimeException(exception.get()); + } + + return result.get(); + } } 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/Notification.java b/core/java/android/app/Notification.java index d37576092af2..67226d0f2228 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -6994,7 +6994,7 @@ public class Notification implements Parcelable */ public boolean isColorized() { return extras.getBoolean(EXTRA_COLORIZED) - && (hasColorizedPermission() || isForegroundService()); + && (hasColorizedPermission() || isFgsOrUij()); } /** 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/app/admin/DevicePolicyResources.java b/core/java/android/app/admin/DevicePolicyResources.java index 052f670b71bd..77ba560f29a1 100644 --- a/core/java/android/app/admin/DevicePolicyResources.java +++ b/core/java/android/app/admin/DevicePolicyResources.java @@ -1662,14 +1662,16 @@ public final class DevicePolicyResources { /** * Label returned from * {@link android.content.pm.CrossProfileApps#getProfileSwitchingLabel(UserHandle)} - * that calling app can show to user for the semantic of switching to work profile. + * that calling app can show to user for the semantic of switching to work profile, and + * accepts the app name as a param. */ public static final String SWITCH_TO_WORK_LABEL = PREFIX + "SWITCH_TO_WORK_LABEL"; /** * Label returned from * {@link android.content.pm.CrossProfileApps#getProfileSwitchingLabel(UserHandle)} - * that calling app can show to user for the semantic of switching to personal profile. + * that calling app can show to user for the semantic of switching to personal profile, + * and accepts the app name as a param. */ public static final String SWITCH_TO_PERSONAL_LABEL = PREFIX + "SWITCH_TO_PERSONAL_LABEL"; diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java index d6951eec904f..7ac8f37c645e 100644 --- a/core/java/android/content/pm/CrossProfileApps.java +++ b/core/java/android/content/pm/CrossProfileApps.java @@ -18,6 +18,7 @@ package android.content.pm; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.app.admin.DevicePolicyResources.Strings.Core.SWITCH_TO_PERSONAL_LABEL; import static android.app.admin.DevicePolicyResources.Strings.Core.SWITCH_TO_WORK_LABEL; +import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY; import android.annotation.NonNull; import android.annotation.Nullable; @@ -40,6 +41,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.text.TextUtils; import com.android.internal.R; import com.android.internal.util.UserIcons; @@ -329,19 +331,40 @@ public class CrossProfileApps { final boolean isManagedProfile = mUserManager.isManagedProfile(userHandle.getIdentifier()); final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class); + final String callingAppLabel = getCallingApplicationLabel().toString(); return dpm.getResources().getString( getUpdatableProfileSwitchingLabelId(isManagedProfile), - () -> getDefaultProfileSwitchingLabel(isManagedProfile)); + () -> getDefaultProfileSwitchingLabel(isManagedProfile, callingAppLabel), + callingAppLabel); + } + + private CharSequence getCallingApplicationLabel() { + PackageManager pm = mContext.getPackageManager(); + // If there is a label for the launcher intent, then use that as it is typically shorter. + // Otherwise, just use the top-level application name. + Intent launchIntent = pm.getLaunchIntentForPackage(mContext.getPackageName()); + List<ResolveInfo> infos = + pm.queryIntentActivities( + launchIntent, PackageManager.ResolveInfoFlags.of(MATCH_DEFAULT_ONLY)); + if (infos.size() > 0) { + return infos.get(0).loadLabel(pm); + } + return mContext.getApplicationInfo() + .loadSafeLabel( + pm, + /* ellipsizeDip= */ 0, + TextUtils.SAFE_STRING_FLAG_SINGLE_LINE + | TextUtils.SAFE_STRING_FLAG_TRIM); } private String getUpdatableProfileSwitchingLabelId(boolean isManagedProfile) { return isManagedProfile ? SWITCH_TO_WORK_LABEL : SWITCH_TO_PERSONAL_LABEL; } - private String getDefaultProfileSwitchingLabel(boolean isManagedProfile) { + private String getDefaultProfileSwitchingLabel(boolean isManagedProfile, String label) { final int stringRes = isManagedProfile - ? R.string.managed_profile_label : R.string.user_owner_label; - return mResources.getString(stringRes); + ? R.string.managed_profile_app_label : R.string.user_owner_app_label; + return mResources.getString(stringRes, label); } @@ -366,10 +389,18 @@ public class CrossProfileApps { if (isManagedProfile) { return mContext.getPackageManager().getUserBadgeForDensityNoBackground( userHandle, /* density= */ 0); - } else { - return UserIcons.getDefaultUserIcon( - mResources, UserHandle.USER_SYSTEM, true /* light */); } + Drawable personalProfileIcon = UserIcons.getDefaultUserIcon( + mResources, UserHandle.USER_SYSTEM, /* light= */ true); + // Using the same colors as the managed profile icon. + int colorId = mContext.getResources().getConfiguration().isNightModeActive() + ? R.color.profile_badge_1_dark + : R.color.profile_badge_1; + // First set the color filter to null so that it does not override + // the tint. + personalProfileIcon.setColorFilter(null); + personalProfileIcon.setTint(mResources.getColor(colorId, /* theme= */ null)); + return personalProfileIcon; } /** diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java index 65528e306943..bc80c8b20b86 100644 --- a/core/java/android/os/WorkSource.java +++ b/core/java/android/os/WorkSource.java @@ -12,11 +12,11 @@ import android.util.Log; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; /** * Describes the source of some work that may be done by someone else. @@ -29,9 +29,13 @@ public class WorkSource implements Parcelable { @UnsupportedAppUsage int mNum; + @UnsupportedAppUsage - int[] mUids; + @NonNull + int[] mUids = new int[0]; + @UnsupportedAppUsage + @Nullable String[] mNames; private ArrayList<WorkChain> mChains; @@ -73,13 +77,8 @@ public class WorkSource implements Parcelable { return; } mNum = orig.mNum; - if (orig.mUids != null) { - mUids = orig.mUids.clone(); - mNames = orig.mNames != null ? orig.mNames.clone() : null; - } else { - mUids = null; - mNames = null; - } + mUids = orig.mUids.clone(); + mNames = orig.mNames != null ? orig.mNames.clone() : null; if (orig.mChains != null) { // Make a copy of all WorkChains that exist on |orig| since they are mutable. @@ -114,7 +113,7 @@ public class WorkSource implements Parcelable { */ @SystemApi public WorkSource(int uid, @NonNull String packageName) { - Preconditions.checkNotNull(packageName, "packageName can't be null"); + Objects.requireNonNull(packageName, "packageName can't be null"); mNum = 1; mUids = new int[] { uid, 0 }; mNames = new String[] { packageName, null }; @@ -124,7 +123,7 @@ public class WorkSource implements Parcelable { @UnsupportedAppUsage WorkSource(Parcel in) { mNum = in.readInt(); - mUids = in.createIntArray(); + mUids = Objects.requireNonNullElse(in.createIntArray(), new int[0]); mNames = in.createStringArray(); int numChains = in.readInt(); @@ -318,30 +317,22 @@ public class WorkSource implements Parcelable { */ public void set(WorkSource other) { if (other == null) { - mNum = 0; - if (mChains != null) { - mChains.clear(); - } + clear(); return; } mNum = other.mNum; - if (other.mUids != null) { - if (mUids != null && mUids.length >= mNum) { - System.arraycopy(other.mUids, 0, mUids, 0, mNum); - } else { - mUids = other.mUids.clone(); - } - if (other.mNames != null) { - if (mNames != null && mNames.length >= mNum) { - System.arraycopy(other.mNames, 0, mNames, 0, mNum); - } else { - mNames = other.mNames.clone(); - } + if (mUids.length >= mNum) { // this has more data than other + System.arraycopy(other.mUids, 0, mUids, 0, mNum); + } else { + mUids = other.mUids.clone(); + } + if (other.mNames != null) { + if (mNames != null && mNames.length >= mNum) { + System.arraycopy(other.mNames, 0, mNames, 0, mNum); } else { - mNames = null; + mNames = other.mNames.clone(); } } else { - mUids = null; mNames = null; } @@ -361,7 +352,7 @@ public class WorkSource implements Parcelable { /** @hide */ public void set(int uid) { mNum = 1; - if (mUids == null) mUids = new int[2]; + if (mUids.length == 0) mUids = new int[2]; mUids[0] = uid; mNames = null; if (mChains != null) { @@ -375,7 +366,7 @@ public class WorkSource implements Parcelable { throw new NullPointerException("Name can't be null"); } mNum = 1; - if (mUids == null) { + if (mUids.length == 0) { mUids = new int[2]; mNames = new String[2]; } @@ -727,7 +718,7 @@ public class WorkSource implements Parcelable { if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1 + ": insert " + uids2[i2]); changed = true; - if (uids1 == null) { + if (uids1.length == 0) { uids1 = new int[4]; uids1[0] = uids2[i2]; } else if (N1 >= uids1.length) { @@ -866,7 +857,7 @@ public class WorkSource implements Parcelable { private void insert(int index, int uid) { if (DEBUG) Log.d(TAG, "Insert in " + this + " @ " + index + " uid " + uid); - if (mUids == null) { + if (mUids.length == 0) { mUids = new int[4]; mUids[0] = uid; mNum = 1; @@ -891,7 +882,7 @@ public class WorkSource implements Parcelable { } private void insert(int index, int uid, String name) { - if (mUids == null) { + if (mNum == 0) { mUids = new int[4]; mUids[0] = uid; mNames = new String[4]; @@ -1244,8 +1235,8 @@ public class WorkSource implements Parcelable { proto.end(workSourceToken); } - public static final @android.annotation.NonNull Parcelable.Creator<WorkSource> CREATOR - = new Parcelable.Creator<WorkSource>() { + @NonNull + public static final Parcelable.Creator<WorkSource> CREATOR = new Parcelable.Creator<>() { public WorkSource createFromParcel(Parcel in) { return new WorkSource(in); } 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/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/proto/android/server/windowmanagertransitiontrace.proto b/core/proto/android/server/windowmanagertransitiontrace.proto index c3cbc9102b27..a776bd2a4330 100644 --- a/core/proto/android/server/windowmanagertransitiontrace.proto +++ b/core/proto/android/server/windowmanagertransitiontrace.proto @@ -44,6 +44,10 @@ message TransitionTraceProto { // Additional debugging info only collected and dumped when explicitly requested to trace repeated TransitionState transition_states = 3; repeated TransitionInfo transition_info = 4; + + /* offset between real-time clock and elapsed time clock in nanoseconds. + Calculated as: 1000000 * System.currentTimeMillis() - SystemClock.elapsedRealtimeNanos() */ + optional fixed64 real_to_elapsed_time_offset_nanos = 5; } message Transition { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 31220b438ac4..dd535a12d013 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -8228,6 +8228,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/strings.xml b/core/res/res/values/strings.xml index c6462f15ec50..a49ea0bd55fb 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -861,6 +861,12 @@ <!-- "Switch" is a verb; it means to change user profile by tapping another user profile name. --> <string name="managed_profile_label">Switch to work profile</string> + <!-- "Switch" is a verb; it means to change user profile by tapping another user profile name. --> + <string name="user_owner_app_label">Switch to personal <xliff:g id="app_name" example="Gmail">%1$s</xliff:g></string> + + <!-- "Switch" is a verb; it means to change user profile by tapping another user profile name. --> + <string name="managed_profile_app_label">Switch to work <xliff:g id="app_name" example="Gmail">%1$s</xliff:g></string> + <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. --> <string name="permgrouplab_contacts">Contacts</string> <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index b7df6a482983..bb10f7ae7c93 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1068,7 +1068,9 @@ <java-symbol type="string" name="action_bar_home_subtitle_description_format" /> <java-symbol type="string" name="wireless_display_route_description" /> <java-symbol type="string" name="user_owner_label" /> + <java-symbol type="string" name="user_owner_app_label" /> <java-symbol type="string" name="managed_profile_label" /> + <java-symbol type="string" name="managed_profile_app_label" /> <java-symbol type="string" name="managed_profile_label_badge" /> <java-symbol type="string" name="managed_profile_label_badge_2" /> <java-symbol type="string" name="managed_profile_label_badge_3" /> @@ -1713,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/coretests/Android.bp b/core/tests/coretests/Android.bp index 34b4c5177852..67842f05165c 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -73,6 +73,7 @@ android_test { ], jni_libs: [ "libpowermanagertest_jni", + "libworksourceparceltest_jni", ], sdk_version: "core_platform", diff --git a/core/tests/coretests/jni/Android.bp b/core/tests/coretests/jni/Android.bp index edac8ef25fe7..7cc844ae9fc6 100644 --- a/core/tests/coretests/jni/Android.bp +++ b/core/tests/coretests/jni/Android.bp @@ -43,3 +43,27 @@ cc_test_library { ], gtest: false, } + +cc_test_library { + name: "libworksourceparceltest_jni", + srcs: [ + "NativeWorkSourceParcelTest.cpp", + ], + shared_libs: [ + "libandroid", + "libandroid_runtime_lazy", + "libbase", + "libbinder", + "liblog", + "libnativehelper", + "libpowermanager", + "libutils", + ], + header_libs: ["jni_headers"], + stl: "libc++_static", + cflags: [ + "-Werror", + "-Wall", + ], + gtest: false, +} diff --git a/core/tests/coretests/jni/NativePowerManagerTest.cpp b/core/tests/coretests/jni/NativePowerManagerTest.cpp index 5f20e4f9c407..c15c0cefcb08 100644 --- a/core/tests/coretests/jni/NativePowerManagerTest.cpp +++ b/core/tests/coretests/jni/NativePowerManagerTest.cpp @@ -18,6 +18,7 @@ #define LOG_TAG "NativePowerManagerTest" #include "jni.h" +#include "ParcelHelper.h" #include <android_util_Binder.h> #include <binder/IServiceManager.h> @@ -36,21 +37,6 @@ using android::base::StringPrintf; namespace android { -#define FIND_CLASS(var, className) \ - var = env->FindClass(className); \ - LOG_FATAL_IF(!(var), "Unable to find class %s", className); - -#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ - var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ - LOG_FATAL_IF(!(var), "Unable to find field %s", fieldName); - -#define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \ - var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \ - LOG_FATAL_IF(!(var), "Unable to find method %s", fieldName); - -static jclass gParcelClazz; -static jfieldID gParcelDataFieldID; -static jmethodID gParcelObtainMethodID; static struct BatterySaverPolicyConfigFieldId { jfieldID adjustBrightnessFactor; jfieldID advertiseIsEnabled; @@ -73,102 +59,6 @@ static struct BatterySaverPolicyConfigFieldId { jfieldID soundTriggerMode; } gBSPCFieldIds; -static jobject nativeObtainParcel(JNIEnv* env) { - jobject parcel = env->CallStaticObjectMethod(gParcelClazz, gParcelObtainMethodID); - if (parcel == nullptr) { - jniThrowException(env, "java/lang/IllegalArgumentException", "Obtain parcel failed."); - } - return parcel; -} - -static Parcel* nativeGetParcelData(JNIEnv* env, jobject obj) { - Parcel* parcel = reinterpret_cast<Parcel*>(env->GetLongField(obj, gParcelDataFieldID)); - if (parcel && parcel->objectsCount() != 0) { - jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid parcel object."); - } - parcel->setDataPosition(0); - return parcel; -} - -static jobject nativeObtainWorkSourceParcel(JNIEnv* env, jobject /* obj */, jintArray uidArray, - jobjectArray nameArray) { - std::vector<int32_t> uids; - std::optional<std::vector<std::optional<String16>>> names = std::nullopt; - - if (uidArray != nullptr) { - jint *ptr = env->GetIntArrayElements(uidArray, 0); - for (jint i = 0; i < env->GetArrayLength(uidArray); i++) { - uids.push_back(static_cast<int32_t>(ptr[i])); - } - } - - if (nameArray != nullptr) { - std::vector<std::optional<String16>> namesVec; - for (jint i = 0; i < env->GetArrayLength(nameArray); i++) { - jstring string = (jstring) (env->GetObjectArrayElement(nameArray, i)); - const char *rawString = env->GetStringUTFChars(string, 0); - namesVec.push_back(std::make_optional<String16>(String16(rawString))); - } - names = std::make_optional(std::move(namesVec)); - } - - WorkSource ws = WorkSource(uids, names); - jobject wsParcel = nativeObtainParcel(env); - Parcel* parcel = nativeGetParcelData(env, wsParcel); - status_t err = ws.writeToParcel(parcel); - if (err != OK) { - jniThrowException(env, "java/lang/IllegalArgumentException", - StringPrintf("WorkSource writeToParcel failed %d", err).c_str()); - } - parcel->setDataPosition(0); - return wsParcel; -} - -static void nativeUnparcelAndVerifyWorkSource(JNIEnv* env, jobject /* obj */, jobject wsParcel, - jintArray uidArray, jobjectArray nameArray) { - WorkSource ws = {}; - Parcel* parcel = nativeGetParcelData(env, wsParcel); - - status_t err = ws.readFromParcel(parcel); - if (err != OK) { - ALOGE("WorkSource writeToParcel failed %d", err); - } - - // Now we have a native WorkSource object, verify it. - if (uidArray != nullptr) { - jint *ptr = env->GetIntArrayElements(uidArray, 0); - for (jint i = 0; i < env->GetArrayLength(uidArray); i++) { - if (ws.getUids().at(i) != static_cast<int32_t>(ptr[i])) { - jniThrowException(env, "java/lang/IllegalArgumentException", - StringPrintf("WorkSource uid not equal %d %d", - ws.getUids().at(i), static_cast<int32_t>(ptr[i])).c_str()); - } - } - } else { - if (ws.getUids().size() != 0) { - jniThrowException(env, "java/lang/IllegalArgumentException", - StringPrintf("WorkSource parcel size not 0").c_str()); - } - } - - if (nameArray != nullptr) { - std::vector<std::optional<String16>> namesVec; - for (jint i = 0; i < env->GetArrayLength(nameArray); i++) { - jstring string = (jstring) (env->GetObjectArrayElement(nameArray, i)); - const char *rawString = env->GetStringUTFChars(string, 0); - if (String16(rawString) != ws.getNames()->at(i)) { - jniThrowException(env, "java/lang/IllegalArgumentException", - StringPrintf("WorkSource uid not equal %s", rawString).c_str()); - } - } - } else { - if (ws.getNames() != std::nullopt) { - jniThrowException(env, "java/lang/IllegalArgumentException", - StringPrintf("WorkSource parcel name not empty").c_str()); - } - } -} - static jobject nativeObtainPowerSaveStateParcel(JNIEnv* env, jobject /* obj */, jboolean batterySaverEnabled, jboolean globalBatterySaverEnabled, jint locationMode, jint soundTriggerMode, jfloat brightnessFactor) { @@ -305,10 +195,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) JNIEnv* env; const JNINativeMethod methodTable[] = { /* name, signature, funcPtr */ - { "nativeObtainWorkSourceParcel", "([I[Ljava/lang/String;)Landroid/os/Parcel;", - (void*) nativeObtainWorkSourceParcel }, - { "nativeUnparcelAndVerifyWorkSource", "(Landroid/os/Parcel;[I[Ljava/lang/String;)V", - (void*) nativeUnparcelAndVerifyWorkSource }, { "nativeObtainPowerSaveStateParcel", "(ZZIIF)Landroid/os/Parcel;", (void*) nativeObtainPowerSaveStateParcel }, { "nativeUnparcelAndVerifyPowerSaveState", "(Landroid/os/Parcel;ZZIIF)V", @@ -327,34 +213,40 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) return JNI_ERR; } - jclass bspcClazz; - FIND_CLASS(gParcelClazz, "android/os/Parcel"); - GET_FIELD_ID(gParcelDataFieldID, gParcelClazz, "mNativePtr", "J"); - GET_STATIC_METHOD_ID(gParcelObtainMethodID, gParcelClazz, "obtain", "()Landroid/os/Parcel;"); - FIND_CLASS(bspcClazz, "android/os/BatterySaverPolicyConfig"); - GET_FIELD_ID(gBSPCFieldIds.adjustBrightnessFactor, bspcClazz, "mAdjustBrightnessFactor", "F"); - GET_FIELD_ID(gBSPCFieldIds.advertiseIsEnabled, bspcClazz, "mAdvertiseIsEnabled", "Z"); - GET_FIELD_ID(gBSPCFieldIds.deferFullBackup, bspcClazz, "mDeferFullBackup", "Z"); - GET_FIELD_ID(gBSPCFieldIds.deferKeyValueBackup, bspcClazz, "mDeferKeyValueBackup", "Z"); - GET_FIELD_ID(gBSPCFieldIds.deviceSpecificSettings, bspcClazz, "mDeviceSpecificSettings", - "Ljava/util/Map;"); - GET_FIELD_ID(gBSPCFieldIds.disableAnimation, bspcClazz, "mDisableAnimation", "Z"); - GET_FIELD_ID(gBSPCFieldIds.disableAod, bspcClazz, "mDisableAod", "Z"); - GET_FIELD_ID(gBSPCFieldIds.disableLaunchBoost, bspcClazz, "mDisableLaunchBoost", "Z"); - GET_FIELD_ID(gBSPCFieldIds.disableOptionalSensors, bspcClazz, "mDisableOptionalSensors", "Z"); - GET_FIELD_ID(gBSPCFieldIds.disableVibration, bspcClazz, "mDisableVibration", "Z"); - GET_FIELD_ID(gBSPCFieldIds.enableAdjustBrightness, bspcClazz, "mEnableAdjustBrightness", "Z"); - GET_FIELD_ID(gBSPCFieldIds.enableDataSaver, bspcClazz, "mEnableDataSaver", "Z"); - GET_FIELD_ID(gBSPCFieldIds.enableFirewall, bspcClazz, "mEnableFirewall", "Z"); - GET_FIELD_ID(gBSPCFieldIds.enableNightMode, bspcClazz, "mEnableNightMode", "Z"); - GET_FIELD_ID(gBSPCFieldIds.enableQuickDoze, bspcClazz, "mEnableQuickDoze", "Z"); - GET_FIELD_ID(gBSPCFieldIds.forceAllAppsStandby, bspcClazz, "mForceAllAppsStandby", "Z"); - GET_FIELD_ID(gBSPCFieldIds.forceBackgroundCheck, bspcClazz, "mForceBackgroundCheck", "Z"); - GET_FIELD_ID(gBSPCFieldIds.locationMode, bspcClazz, "mLocationMode", "I"); - GET_FIELD_ID(gBSPCFieldIds.soundTriggerMode, bspcClazz, "mSoundTriggerMode", "I"); + loadParcelClass(env); + + jclass bspcClazz = FindClassOrDie(env, "android/os/BatterySaverPolicyConfig"); + + gBSPCFieldIds.adjustBrightnessFactor = + GetFieldIDOrDie(env, bspcClazz, "mAdjustBrightnessFactor", "F"); + gBSPCFieldIds.advertiseIsEnabled = GetFieldIDOrDie(env, bspcClazz, "mAdvertiseIsEnabled", "Z"); + gBSPCFieldIds.deferFullBackup = GetFieldIDOrDie(env, bspcClazz, "mDeferFullBackup", "Z"); + gBSPCFieldIds.deferKeyValueBackup = + GetFieldIDOrDie(env, bspcClazz, "mDeferKeyValueBackup", "Z"); + gBSPCFieldIds.deviceSpecificSettings = + GetFieldIDOrDie(env, bspcClazz, "mDeviceSpecificSettings", "Ljava/util/Map;"); + gBSPCFieldIds.disableAnimation = GetFieldIDOrDie(env, bspcClazz, "mDisableAnimation", "Z"); + gBSPCFieldIds.disableAod = GetFieldIDOrDie(env, bspcClazz, "mDisableAod", "Z"); + gBSPCFieldIds.disableLaunchBoost = GetFieldIDOrDie(env, bspcClazz, "mDisableLaunchBoost", "Z"); + gBSPCFieldIds.disableOptionalSensors = + GetFieldIDOrDie(env, bspcClazz, "mDisableOptionalSensors", "Z"); + gBSPCFieldIds.disableVibration = GetFieldIDOrDie(env, bspcClazz, "mDisableVibration", "Z"); + gBSPCFieldIds.enableAdjustBrightness = + GetFieldIDOrDie(env, bspcClazz, "mEnableAdjustBrightness", "Z"); + gBSPCFieldIds.enableDataSaver = GetFieldIDOrDie(env, bspcClazz, "mEnableDataSaver", "Z"); + gBSPCFieldIds.enableFirewall = GetFieldIDOrDie(env, bspcClazz, "mEnableFirewall", "Z"); + gBSPCFieldIds.enableNightMode = GetFieldIDOrDie(env, bspcClazz, "mEnableNightMode", "Z"); + gBSPCFieldIds.enableQuickDoze = GetFieldIDOrDie(env, bspcClazz, "mEnableQuickDoze", "Z"); + gBSPCFieldIds.forceAllAppsStandby = + GetFieldIDOrDie(env, bspcClazz, "mForceAllAppsStandby", "Z"); + gBSPCFieldIds.forceBackgroundCheck = + GetFieldIDOrDie(env, bspcClazz, "mForceBackgroundCheck", "Z"); + gBSPCFieldIds.locationMode = GetFieldIDOrDie(env, bspcClazz, "mLocationMode", "I"); + gBSPCFieldIds.soundTriggerMode = GetFieldIDOrDie(env, bspcClazz, "mSoundTriggerMode", "I"); jniRegisterNativeMethods(env, "android/os/PowerManagerTest", methodTable, sizeof(methodTable) / sizeof(JNINativeMethod)); + return JNI_VERSION_1_6; } diff --git a/core/tests/coretests/jni/NativeWorkSourceParcelTest.cpp b/core/tests/coretests/jni/NativeWorkSourceParcelTest.cpp new file mode 100644 index 000000000000..db1f7bde4b4f --- /dev/null +++ b/core/tests/coretests/jni/NativeWorkSourceParcelTest.cpp @@ -0,0 +1,156 @@ +/* + * 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. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "NativeWorkSourceParcelTest" + +#include "jni.h" +#include "ParcelHelper.h" + +#include <android_util_Binder.h> +#include <nativehelper/JNIHelp.h> +#include <nativehelper/ScopedPrimitiveArray.h> +#include <utils/Log.h> + +#include <android/WorkSource.h> +#include <android-base/stringprintf.h> +#include <android-base/strings.h> + +using namespace android::os; +using android::base::StringPrintf; + +namespace android { + +static jobject nativeObtainWorkSourceParcel(JNIEnv* env, jobject /* obj */, jintArray uidArray, + jobjectArray nameArray, jint parcelEndMarker) { + std::vector<int32_t> uids; + std::optional<std::vector<std::optional<String16>>> names = std::nullopt; + + if (uidArray != nullptr) { + ScopedIntArrayRO workSourceUids(env, uidArray); + for (int i = 0; i < workSourceUids.size(); i++) { + uids.push_back(static_cast<int32_t>(workSourceUids[i])); + } + } + + if (nameArray != nullptr) { + std::vector<std::optional<String16>> namesVec; + for (jint i = 0; i < env->GetArrayLength(nameArray); i++) { + jstring string = static_cast<jstring>(env->GetObjectArrayElement(nameArray, i)); + const char *rawString = env->GetStringUTFChars(string, 0); + namesVec.push_back(std::make_optional<String16>(String16(rawString))); + } + names = std::make_optional(std::move(namesVec)); + } + + WorkSource ws = WorkSource(uids, names); + jobject wsParcel = nativeObtainParcel(env); + Parcel* parcel = nativeGetParcelData(env, wsParcel); + + // write WorkSource and if no error write end marker + status_t err = ws.writeToParcel(parcel) ?: parcel->writeInt32(parcelEndMarker); + + if (err != OK) { + jniThrowException(env, "java/lang/IllegalArgumentException", + StringPrintf("WorkSource writeToParcel failed %d", err).c_str()); + } + parcel->setDataPosition(0); + return wsParcel; +} + +static void nativeUnparcelAndVerifyWorkSource(JNIEnv* env, jobject /* obj */, jobject wsParcel, + jintArray uidArray, jobjectArray nameArray, jint parcelEndMarker) { + WorkSource ws = {}; + Parcel* parcel = nativeGetParcelData(env, wsParcel); + int32_t endMarker; + + // read WorkSource and if no error read end marker + status_t err = ws.readFromParcel(parcel) ?: parcel->readInt32(&endMarker); + int32_t dataAvailable = parcel->dataAvail(); + + if (err != OK) { + ALOGE("WorkSource readFromParcel failed %d", err); + } + + // Now we have a native WorkSource object, verify it. + if (dataAvailable > 0) { // not all data read from the parcel + jniThrowException(env, "java/lang/IllegalArgumentException", + StringPrintf("WorkSource contains more data than native read (%d)", + dataAvailable).c_str()); + } else if (endMarker != parcelEndMarker) { // more date than available read from parcel + jniThrowException(env, "java/lang/IllegalArgumentException", + StringPrintf("WorkSource contains less data than native read").c_str()); + } + + if (uidArray != nullptr) { + ScopedIntArrayRO workSourceUids(env, uidArray); + for (int i = 0; i < workSourceUids.size(); i++) { + if (ws.getUids().at(i) != static_cast<int32_t>(workSourceUids[i])) { + jniThrowException(env, "java/lang/IllegalArgumentException", + StringPrintf("WorkSource uid not equal %d %d", + ws.getUids().at(i), static_cast<int32_t>(workSourceUids[i])).c_str()); + } + } + } else { + if (ws.getUids().size() != 0) { + jniThrowException(env, "java/lang/IllegalArgumentException", + StringPrintf("WorkSource parcel size not 0").c_str()); + } + } + + if (nameArray != nullptr) { + std::vector<std::optional<String16>> namesVec; + for (jint i = 0; i < env->GetArrayLength(nameArray); i++) { + jstring string = (jstring) (env->GetObjectArrayElement(nameArray, i)); + const char *rawString = env->GetStringUTFChars(string, 0); + if (String16(rawString) != ws.getNames()->at(i)) { + jniThrowException(env, "java/lang/IllegalArgumentException", + StringPrintf("WorkSource uid not equal %s", rawString).c_str()); + } + } + } else { + if (ws.getNames() != std::nullopt) { + jniThrowException(env, "java/lang/IllegalArgumentException", + StringPrintf("WorkSource parcel name not empty").c_str()); + } + } +} + +extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) +{ + JNIEnv* env; + + const JNINativeMethod workSourceMethodTable[] = { + /* name, signature, funcPtr */ + { "nativeObtainWorkSourceParcel", "([I[Ljava/lang/String;I)Landroid/os/Parcel;", + (void*) nativeObtainWorkSourceParcel }, + { "nativeUnparcelAndVerifyWorkSource", "(Landroid/os/Parcel;[I[Ljava/lang/String;I)V", + (void*) nativeUnparcelAndVerifyWorkSource }, + }; + + if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + return JNI_ERR; + } + + loadParcelClass(env); + + jniRegisterNativeMethods(env, "android/os/WorkSourceParcelTest", workSourceMethodTable, + sizeof(workSourceMethodTable) / sizeof(JNINativeMethod)); + + return JNI_VERSION_1_6; +} + +} /* namespace android */ diff --git a/core/tests/coretests/jni/ParcelHelper.h b/core/tests/coretests/jni/ParcelHelper.h new file mode 100644 index 000000000000..1485a2a3be17 --- /dev/null +++ b/core/tests/coretests/jni/ParcelHelper.h @@ -0,0 +1,73 @@ +/* + * 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. + */ +#pragma once + +#include <nativehelper/JNIHelp.h> +#include <binder/Parcel.h> + +namespace android { + static jclass gParcelClazz; + static jfieldID gParcelDataFieldID; + static jmethodID gParcelObtainMethodID; + + static inline jclass FindClassOrDie(JNIEnv* env, const char* class_name) { + jclass clazz = env->FindClass(class_name); + LOG_ALWAYS_FATAL_IF(clazz == NULL, "Unable to find class %s", class_name); + return clazz; + } + + static inline jfieldID GetFieldIDOrDie(JNIEnv* env, jclass clazz, const char* field_name, + const char* field_signature) { + jfieldID res = env->GetFieldID(clazz, field_name, field_signature); + LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find field %s with signature %s", field_name, + field_signature); + return res; + } + + static inline jmethodID GetStaticMethodIDOrDie(JNIEnv* env, jclass clazz, + const char* method_name, + const char* method_signature) { + jmethodID res = env->GetStaticMethodID(clazz, method_name, method_signature); + LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find method %s with signature %s", method_name, + method_signature); + return res; + } + + static jobject nativeObtainParcel(JNIEnv* env) { + jobject parcel = env->CallStaticObjectMethod(gParcelClazz, gParcelObtainMethodID); + if (parcel == nullptr) { + jniThrowException(env, "java/lang/IllegalArgumentException", "Obtain parcel failed."); + } + return parcel; + } + + static Parcel* nativeGetParcelData(JNIEnv* env, jobject obj) { + Parcel* parcel = reinterpret_cast<Parcel*>(env->GetLongField(obj, gParcelDataFieldID)); + if (parcel && parcel->objectsCount() != 0) { + jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid parcel object."); + } + parcel->setDataPosition(0); + return parcel; + } + + static void loadParcelClass(JNIEnv* env) { + gParcelClazz = FindClassOrDie(env, "android/os/Parcel"); + gParcelDataFieldID = GetFieldIDOrDie(env, gParcelClazz, "mNativePtr", "J"); + gParcelObtainMethodID = + GetStaticMethodIDOrDie(env, gParcelClazz, "obtain", "()Landroid/os/Parcel;"); + } + +}
\ No newline at end of file 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/core/tests/coretests/src/android/content/pm/CrossProfileAppsTest.java b/core/tests/coretests/src/android/content/pm/CrossProfileAppsTest.java index 5e076076d2f4..661b210f3e18 100644 --- a/core/tests/coretests/src/android/content/pm/CrossProfileAppsTest.java +++ b/core/tests/coretests/src/android/content/pm/CrossProfileAppsTest.java @@ -20,15 +20,18 @@ import static android.app.admin.DevicePolicyResources.Strings.Core.SWITCH_TO_PER import static android.app.admin.DevicePolicyResources.Strings.Core.SWITCH_TO_WORK_LABEL; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyResourcesManager; import android.content.Context; +import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.UserHandle; @@ -76,15 +79,21 @@ public class CrossProfileAppsTest { private Drawable mDrawable; @Mock private PackageManager mPackageManager; + + @Mock private ApplicationInfo mApplicationInfo; + + private Configuration mConfiguration; + private CrossProfileApps mCrossProfileApps; @Before public void initCrossProfileApps() { - mCrossProfileApps = new CrossProfileApps(mContext, mService); + mCrossProfileApps = spy(new CrossProfileApps(mContext, mService)); } @Before public void mockContext() { + mConfiguration = new Configuration(); when(mContext.getPackageName()).thenReturn(MY_PACKAGE); when(mContext.getSystemServiceName(UserManager.class)).thenReturn(Context.USER_SERVICE); when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); @@ -94,6 +103,8 @@ public class CrossProfileAppsTest { mDevicePolicyManager); when(mDevicePolicyManager.getResources()).thenReturn(mDevicePolicyResourcesManager); when(mContext.getPackageManager()).thenReturn(mPackageManager); + when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo); + when(mResources.getConfiguration()).thenReturn(mConfiguration); } @Before @@ -115,17 +126,20 @@ public class CrossProfileAppsTest { @Test public void getProfileSwitchingLabel_managedProfile() { setValidTargetProfile(MANAGED_PROFILE); + when(mApplicationInfo.loadSafeLabel(any(), anyFloat(), anyInt())).thenReturn("app"); mCrossProfileApps.getProfileSwitchingLabel(MANAGED_PROFILE); - verify(mDevicePolicyResourcesManager).getString(eq(SWITCH_TO_WORK_LABEL), any()); + verify(mDevicePolicyResourcesManager).getString(eq(SWITCH_TO_WORK_LABEL), any(), eq("app")); } @Test public void getProfileSwitchingLabel_personalProfile() { setValidTargetProfile(PERSONAL_PROFILE); + when(mApplicationInfo.loadSafeLabel(any(), anyFloat(), anyInt())).thenReturn("app"); mCrossProfileApps.getProfileSwitchingLabel(PERSONAL_PROFILE); - verify(mDevicePolicyResourcesManager).getString(eq(SWITCH_TO_PERSONAL_LABEL), any()); + verify(mDevicePolicyResourcesManager) + .getString(eq(SWITCH_TO_PERSONAL_LABEL), any(), eq("app")); } @Test(expected = SecurityException.class) diff --git a/core/tests/coretests/src/android/os/PowerManagerTest.java b/core/tests/coretests/src/android/os/PowerManagerTest.java index 0dfc37131f7f..9f85d6f02ec3 100644 --- a/core/tests/coretests/src/android/os/PowerManagerTest.java +++ b/core/tests/coretests/src/android/os/PowerManagerTest.java @@ -49,9 +49,6 @@ public class PowerManagerTest extends AndroidTestCase { @Mock private PowerManager.OnThermalStatusChangedListener mListener2; private static final long CALLBACK_TIMEOUT_MILLI_SEC = 5000; - private native Parcel nativeObtainWorkSourceParcel(int[] uids, String[] names); - private native void nativeUnparcelAndVerifyWorkSource(Parcel parcel, int[] uids, - String[] names); private native Parcel nativeObtainPowerSaveStateParcel(boolean batterySaverEnabled, boolean globalBatterySaverEnabled, int locationMode, int soundTriggerMode, float brightnessFactor); @@ -300,54 +297,6 @@ public class PowerManagerTest extends AndroidTestCase { } /** - * Helper function to obtain a WorkSource object as parcel from native, with - * specified uids and names and verify the WorkSource object created from the parcel. - */ - private void unparcelWorkSourceFromNativeAndVerify(int[] uids, String[] names) { - // Obtain WorkSource as parcel from native, with uids and names. - Parcel wsParcel = nativeObtainWorkSourceParcel(uids, names); - WorkSource ws = WorkSource.CREATOR.createFromParcel(wsParcel); - if (uids == null) { - assertEquals(ws.size(), 0); - } else { - assertEquals(uids.length, ws.size()); - for (int i = 0; i < ws.size(); i++) { - assertEquals(ws.getUid(i), uids[i]); - } - } - if (names != null) { - for (int i = 0; i < names.length; i++) { - assertEquals(ws.getName(i), names[i]); - } - } - } - - /** - * Helper function to send a WorkSource as parcel from java to native. - * Native will verify the WorkSource in native is expected. - */ - private void parcelWorkSourceToNativeAndVerify(int[] uids, String[] names) { - WorkSource ws = new WorkSource(); - if (uids != null) { - if (names == null) { - for (int i = 0; i < uids.length; i++) { - ws.add(uids[i]); - } - } else { - assertEquals(uids.length, names.length); - for (int i = 0; i < uids.length; i++) { - ws.add(uids[i], names[i]); - } - } - } - Parcel wsParcel = Parcel.obtain(); - ws.writeToParcel(wsParcel, 0 /* flags */); - wsParcel.setDataPosition(0); - //Set the WorkSource as parcel to native and verify. - nativeUnparcelAndVerifyWorkSource(wsParcel, uids, names); - } - - /** * Helper function to obtain a PowerSaveState as parcel from native, with * specified parameters, and verify the PowerSaveState object created from the parcel. */ @@ -422,43 +371,6 @@ public class PowerManagerTest extends AndroidTestCase { } /** - * Confirm that we can pass WorkSource from native to Java. - * - * @throws Exception - */ - @Test - public void testWorkSourceNativeToJava() { - final int[] uids1 = {1000}; - final int[] uids2 = {1000, 2000}; - final String[] names1 = {"testWorkSource1"}; - final String[] names2 = {"testWorkSource1", "testWorkSource2"}; - unparcelWorkSourceFromNativeAndVerify(null /* uids */, null /* names */); - unparcelWorkSourceFromNativeAndVerify(uids1, null /* names */); - unparcelWorkSourceFromNativeAndVerify(uids2, null /* names */); - unparcelWorkSourceFromNativeAndVerify(null /* uids */, names1); - unparcelWorkSourceFromNativeAndVerify(uids1, names1); - unparcelWorkSourceFromNativeAndVerify(uids2, names2); - } - - /** - * Confirm that we can pass WorkSource from Java to native. - * - * @throws Exception - */ - @Test - public void testWorkSourceJavaToNative() { - final int[] uids1 = {1000}; - final int[] uids2 = {1000, 2000}; - final String[] names1 = {"testGetWorkSource1"}; - final String[] names2 = {"testGetWorkSource1", "testGetWorkSource2"}; - parcelWorkSourceToNativeAndVerify(null /* uids */, null /* names */); - parcelWorkSourceToNativeAndVerify(uids1, null /* names */); - parcelWorkSourceToNativeAndVerify(uids2, null /* names */); - parcelWorkSourceToNativeAndVerify(uids1, names1); - parcelWorkSourceToNativeAndVerify(uids2, names2); - } - - /** * Confirm that we can pass PowerSaveState from native to Java. * * @throws Exception diff --git a/core/tests/coretests/src/android/os/WorkSourceParcelTest.java b/core/tests/coretests/src/android/os/WorkSourceParcelTest.java new file mode 100644 index 000000000000..483160687723 --- /dev/null +++ b/core/tests/coretests/src/android/os/WorkSourceParcelTest.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class WorkSourceParcelTest { + /** + * END_OF_PARCEL_MARKER is added at the end of Parcel on native or java side on write and + * then read on java or native side on read. This way we can ensure that no extra data + * is read from the parcel. + */ + private static final int END_OF_PARCEL_MARKER = 99; + + private native Parcel nativeObtainWorkSourceParcel(int[] uids, String[] names, + int parcelEndMarker); + + private native void nativeUnparcelAndVerifyWorkSource(Parcel parcel, int[] uids, + String[] names, int parcelEndMarker); + + static { + System.loadLibrary("worksourceparceltest_jni"); + } + /** + * Confirm that we can pass WorkSource from native to Java. + */ + @Test + public void testWorkSourceNativeToJava() { + final int[] uids1 = {1000}; + final int[] uids2 = {1000, 2000}; + final String[] names1 = {"testWorkSource1"}; + final String[] names2 = {"testWorkSource1", "testWorkSource2"}; + unparcelWorkSourceFromNativeAndVerify(/* uids= */ null , /* names= */ null); + unparcelWorkSourceFromNativeAndVerify(uids1, /* names= */ null); + unparcelWorkSourceFromNativeAndVerify(uids2, /* names= */ null); + unparcelWorkSourceFromNativeAndVerify(/* uids= */ null , names1); + unparcelWorkSourceFromNativeAndVerify(uids1, names1); + unparcelWorkSourceFromNativeAndVerify(uids2, names2); + } + + /** + * Confirm that we can pass WorkSource from Java to native. + */ + @Test + public void testWorkSourceJavaToNative() { + final int[] uids1 = {1000}; + final int[] uids2 = {1000, 2000}; + final String[] names1 = {"testGetWorkSource1"}; + final String[] names2 = {"testGetWorkSource1", "testGetWorkSource2"}; + + parcelWorkSourceToNativeAndVerify(/* uids= */ null , /* names= */ null); + parcelWorkSourceToNativeAndVerify(uids1, /* names= */ null); + parcelWorkSourceToNativeAndVerify(uids2, /* names= */ null); + parcelWorkSourceToNativeAndVerify(uids1, names1); + parcelWorkSourceToNativeAndVerify(uids2, names2); + } + + /** + * Helper function to obtain a WorkSource object as parcel from native, with + * specified uids and names and verify the WorkSource object created from the parcel. + */ + private void unparcelWorkSourceFromNativeAndVerify(int[] uids, String[] names) { + // Obtain WorkSource as parcel from native, with uids and names. + // END_OF_PARCEL_MARKER is written at the end of parcel + Parcel wsParcel = nativeObtainWorkSourceParcel(uids, names, END_OF_PARCEL_MARKER); + // read WorkSource created on native side + WorkSource ws = WorkSource.CREATOR.createFromParcel(wsParcel); + // read end marker written on native side + int endMarker = wsParcel.readInt(); + + assertEquals(0, wsParcel.dataAvail()); // we have read everything + assertEquals(END_OF_PARCEL_MARKER, endMarker); // endMarkers match + + if (uids == null) { + assertEquals(ws.size(), 0); + } else { + assertEquals(uids.length, ws.size()); + for (int i = 0; i < ws.size(); i++) { + assertEquals(ws.getUid(i), uids[i]); + } + } + if (names != null) { + for (int i = 0; i < names.length; i++) { + assertEquals(ws.getPackageName(i), names[i]); + } + } + } + + /** + * Helper function to send a WorkSource as parcel from java to native. + * Native will verify the WorkSource in native is expected. + */ + private void parcelWorkSourceToNativeAndVerify(int[] uids, String[] names) { + WorkSource ws = new WorkSource(); + if (uids != null) { + if (names == null) { + for (int uid : uids) { + ws.add(uid); + } + } else { + assertEquals(uids.length, names.length); + for (int i = 0; i < uids.length; i++) { + ws.add(uids[i], names[i]); + } + } + } + Parcel wsParcel = Parcel.obtain(); + // write WorkSource on java side + ws.writeToParcel(wsParcel, 0 /* flags */); + // write end marker on java side + wsParcel.writeInt(END_OF_PARCEL_MARKER); + wsParcel.setDataPosition(0); + //Verify parcel and end marker on native side + nativeUnparcelAndVerifyWorkSource(wsParcel, uids, names, END_OF_PARCEL_MARKER); + } +} 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 f8f8897e41d5..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(); } }; @@ -1007,6 +1013,7 @@ public class BubbleStackView extends FrameLayout updatePointerPosition(false /* forIme */); mExpandedAnimationController.expandFromStack(() -> { afterExpandedViewAnimation(); + mExpandedViewContainer.setVisibility(VISIBLE); showManageMenu(mShowingManage); } /* after */); PointF p = mPositioner.getExpandedBubbleXY(getBubbleIndex(mExpandedBubble), @@ -1772,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); @@ -2142,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) { @@ -2152,6 +2173,9 @@ public class BubbleStackView extends FrameLayout @Override public void onAnimationEnd(Animator animation) { mScrimAnimating = false; + if (after != null) { + after.run(); + } } }; if (show) { @@ -2178,7 +2202,7 @@ public class BubbleStackView extends FrameLayout } beforeExpandedViewAnimation(); - showScrim(true); + showScrim(true, null /* runnable */); updateZOrder(); updateBadges(false /* setBadgeForCollapsedStack */); mBubbleContainer.setActiveController(mExpandedAnimationController); @@ -2302,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/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index d8e2f5c4a817..2f0f56cfdfb0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -634,14 +634,8 @@ public abstract class WMShellModule { @WMSingleton @Provides - static UnfoldBackgroundController provideUnfoldBackgroundController( - RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, - Context context - ) { - return new UnfoldBackgroundController( - context, - rootTaskDisplayAreaOrganizer - ); + static UnfoldBackgroundController provideUnfoldBackgroundController(Context context) { + return new UnfoldBackgroundController(context); } // diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index 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/unfold/UnfoldBackgroundController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldBackgroundController.java index fe0a3fb7b9dc..96657af22e37 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldBackgroundController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldBackgroundController.java @@ -19,14 +19,12 @@ package com.android.wm.shell.unfold; import static android.graphics.Color.blue; import static android.graphics.Color.green; import static android.graphics.Color.red; -import static android.view.Display.DEFAULT_DISPLAY; import android.annotation.NonNull; import android.content.Context; import android.view.SurfaceControl; import com.android.wm.shell.R; -import com.android.wm.shell.RootTaskDisplayAreaOrganizer; /** * Controls background color layer for the unfold animations @@ -34,15 +32,10 @@ import com.android.wm.shell.RootTaskDisplayAreaOrganizer; public class UnfoldBackgroundController { private static final int BACKGROUND_LAYER_Z_INDEX = -1; - - private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer; private final float[] mBackgroundColor; private SurfaceControl mBackgroundLayer; - public UnfoldBackgroundController( - @NonNull Context context, - @NonNull RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) { - mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer; + public UnfoldBackgroundController(@NonNull Context context) { mBackgroundColor = getBackgroundColor(context); } @@ -57,7 +50,6 @@ public class UnfoldBackgroundController { .setName("app-unfold-background") .setCallsite("AppUnfoldTransitionController") .setColorLayer(); - mRootTaskDisplayAreaOrganizer.attachToDisplayArea(DEFAULT_DISPLAY, colorLayerBuilder); mBackgroundLayer = colorLayerBuilder.build(); transaction 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/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/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/res-keyguard/color/numpad_key_color_secondary.xml b/packages/SystemUI/res-keyguard/color/numpad_key_color_secondary.xml index 08c66a24348c..47641ee64ee1 100644 --- a/packages/SystemUI/res-keyguard/color/numpad_key_color_secondary.xml +++ b/packages/SystemUI/res-keyguard/color/numpad_key_color_secondary.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:color="?androidprv:attr/colorAccentSecondaryVariant"/> + <item android:color="?androidprv:attr/materialColorSecondaryFixedDim"/> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml b/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml index 07642736869c..5e7cf3ee41fb 100644 --- a/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml +++ b/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml @@ -19,7 +19,7 @@ android:color="?attr/wallpaperTextColorSecondary"> <item android:id="@android:id/background"> <shape android:shape="rectangle"> - <solid android:color="?androidprv:attr/colorAccentTertiary"/> + <solid android:color="?androidprv:attr/materialColorTertiaryFixed"/> <corners android:radius="24dp"/> </shape> </item> diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml index 67fd5b9a78bd..83736e9d9473 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml @@ -19,6 +19,7 @@ <!-- This contains disable eSim buttons shared by sim_pin/sim_puk screens --> <com.android.keyguard.KeyguardEsimArea xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:id="@+id/keyguard_disable_esim" style="@style/Keyguard.TextView" android:layout_width="wrap_content" @@ -26,8 +27,8 @@ android:background="@drawable/kg_bouncer_secondary_button" android:drawablePadding="10dp" android:drawableStart="@drawable/ic_no_sim" - android:drawableTint="?android:attr/textColorPrimary" + android:drawableTint="?androidprv:attr/materialColorOnSurface" android:text="@string/disable_carrier_button_text" - android:textColor="?android:attr/textColorPrimary" + android:textColor="?androidprv:attr/materialColorOnSurface" android:textSize="@dimen/kg_status_line_font_size" android:visibility="gone" /> diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_security_container_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_security_container_view.xml index 426cfafb190e..751b07ae9a6e 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_security_container_view.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_security_container_view.xml @@ -19,13 +19,14 @@ <com.android.keyguard.KeyguardSecurityContainer xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:androidprv="http://schemas.android.com/apk/res-auto" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:id="@+id/keyguard_security_container" + android:background="?androidprv:attr/materialColorSurfaceContainer" android:layout_width="match_parent" android:layout_height="match_parent" android:clipChildren="false" android:clipToPadding="false" - android:paddingTop="@dimen/keyguard_lock_padding" + android:paddingTop="@dimen/status_bar_height" android:importantForAccessibility="yes"> <!-- Needed because TYPE_WINDOW_STATE_CHANGED is sent from this view when bouncer is shown --> <com.android.keyguard.KeyguardSecurityViewFlipper diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml index 04dffb6e8c52..4fc411eaea9d 100644 --- a/packages/SystemUI/res-keyguard/values/styles.xml +++ b/packages/SystemUI/res-keyguard/values/styles.xml @@ -24,7 +24,7 @@ <item name="android:textSize">@dimen/kg_status_line_font_size</item> </style> <style name="Keyguard.TextView.EmergencyButton" parent="Theme.SystemUI"> - <item name="android:textColor">?androidprv:attr/textColorOnAccent</item> + <item name="android:textColor">?androidprv:attr/materialColorOnTertiaryFixed</item> <item name="android:textSize">16sp</item> <item name="android:background">@drawable/kg_emergency_button_background</item> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml index fe9542b7aed6..d9fe949bb327 100644 --- a/packages/SystemUI/res/layout/super_notification_shade.xml +++ b/packages/SystemUI/res/layout/super_notification_shade.xml @@ -101,7 +101,6 @@ </LinearLayout> <FrameLayout android:id="@+id/keyguard_bouncer_container" - android:paddingTop="@dimen/status_bar_height" android:layout_height="match_parent" android:layout_width="match_parent" android:layout_weight="1" diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index a2eba81155c7..0aa880fe6d88 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -808,6 +808,8 @@ <dimen name="keyguard_lock_height">42dp</dimen> <dimen name="keyguard_lock_padding">20dp</dimen> + <dimen name="keyguard_security_container_padding_top">20dp</dimen> + <dimen name="keyguard_indication_margin_bottom">32dp</dimen> <dimen name="lock_icon_margin_bottom">74dp</dimen> <dimen name="ambient_indication_margin_bottom">71dp</dimen> 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/BouncerKeyguardMessageArea.kt b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt index f59bf8e766fe..62f4f2282e66 100644 --- a/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt +++ b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt @@ -28,6 +28,7 @@ import android.util.AttributeSet import android.view.View import com.android.settingslib.Utils import com.android.systemui.animation.Interpolators +import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.TITLE /** Displays security messages for the keyguard bouncer. */ open class BouncerKeyguardMessageArea(context: Context?, attrs: AttributeSet?) : @@ -56,8 +57,7 @@ open class BouncerKeyguardMessageArea(context: Context?, attrs: AttributeSet?) : } override fun onThemeChanged() { - val array: TypedArray = - mContext.obtainStyledAttributes(intArrayOf(android.R.attr.textColorPrimary)) + val array: TypedArray = mContext.obtainStyledAttributes(intArrayOf(TITLE)) val newTextColors: ColorStateList = ColorStateList.valueOf(array.getColor(0, Color.RED)) array.recycle() mDefaultColorState = newTextColors @@ -65,7 +65,7 @@ open class BouncerKeyguardMessageArea(context: Context?, attrs: AttributeSet?) : } override fun reloadColor() { - mDefaultColorState = Utils.getColorAttr(context, android.R.attr.textColorPrimary) + mDefaultColorState = Utils.getColorAttr(context, TITLE) super.reloadColor() } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index ba5a8c94dc23..b88d85c843e4 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -54,6 +54,7 @@ import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon; import android.graphics.drawable.LayerDrawable; import android.os.UserManager; import android.provider.Settings; @@ -333,6 +334,11 @@ public class KeyguardSecurityContainer extends ConstraintLayout { mSpringAnimation = new SpringAnimation(this, DynamicAnimation.TRANSLATION_Y); mViewConfiguration = ViewConfiguration.get(context); mDoubleTapDetector = new GestureDetector(context, new DoubleTapListener()); + + // Add additional top padding. + setPadding(getPaddingLeft(), getPaddingTop() + getResources().getDimensionPixelSize( + R.dimen.keyguard_security_container_padding_top), getPaddingRight(), + getPaddingBottom()); } void onResume(SecurityMode securityMode, boolean faceAuthEnabled) { @@ -780,6 +786,8 @@ public class KeyguardSecurityContainer extends ConstraintLayout { void reloadColors() { mViewMode.reloadColors(); + setBackgroundColor(Utils.getColorAttrDefaultColor(getContext(), + com.android.internal.R.attr.materialColorSurface)); } /** Handles density or font scale changes. */ @@ -1022,11 +1030,15 @@ public class KeyguardSecurityContainer extends ConstraintLayout { mUserSwitcherController.removeUserSwitchCallback(mUserSwitchCallback); } - private Drawable findUserIcon(int userId) { + private Drawable findLargeUserIcon(int userId) { Bitmap userIcon = UserManager.get(mView.getContext()).getUserIcon(userId); if (userIcon != null) { - return CircleFramedDrawable.getInstance(mView.getContext(), - userIcon); + int iconSize = + mResources.getDimensionPixelSize(R.dimen.bouncer_user_switcher_icon_size); + return CircleFramedDrawable.getInstance( + mView.getContext(), + Icon.scaleDownIfNecessary(userIcon, iconSize, iconSize) + ); } return UserIcons.getDefaultUserIcon(mResources, userId, false); @@ -1085,7 +1097,7 @@ public class KeyguardSecurityContainer extends ConstraintLayout { return; } final String currentUserName = mUserSwitcherController.getCurrentUserName(); - Drawable userIcon = findUserIcon(currentUser.info.id); + Drawable userIcon = findLargeUserIcon(currentUser.info.id); ((ImageView) mView.findViewById(R.id.user_icon)).setImageDrawable(userIcon); mUserSwitcher.setText(currentUserName); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimInputView.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardSimInputView.kt index b4bfca1185f4..3fc39afe5d0f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimInputView.kt +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimInputView.kt @@ -20,7 +20,9 @@ import android.content.Context import android.util.AttributeSet import android.widget.ImageView import androidx.core.graphics.drawable.DrawableCompat +import com.android.settingslib.Utils import com.android.systemui.R +import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.EMERGENCY_BUTTON abstract class KeyguardSimInputView(context: Context, attrs: AttributeSet) : KeyguardPinBasedInputView(context, attrs) { @@ -42,10 +44,7 @@ abstract class KeyguardSimInputView(context: Context, attrs: AttributeSet) : override fun reloadColors() { super.reloadColors() - val customAttrs = intArrayOf(android.R.attr.textColorSecondary) - val a = context.obtainStyledAttributes(customAttrs) - val imageColor = a.getColor(0, 0) - a.recycle() + val imageColor = Utils.getColorAttrDefaultColor(context, EMERGENCY_BUTTON) simImageView?.let { val wrappedDrawable = DrawableCompat.wrap(it.drawable) DrawableCompat.setTint(wrappedDrawable, imageColor) 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/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index 5f2afe8f755d..7cedecc33a02 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -56,6 +56,7 @@ import com.android.systemui.R; import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.AuthRippleController; import com.android.systemui.biometrics.UdfpsController; +import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; @@ -66,7 +67,6 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.VibratorHelper; -import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.ViewController; @@ -84,7 +84,7 @@ import javax.inject.Inject; * For devices with UDFPS, the lock icon will show at the sensor location. Else, the lock * icon will show a set distance from the bottom of the device. */ -@CentralSurfacesComponent.CentralSurfacesScope +@SysUISingleton public class LockIconViewController extends ViewController<LockIconView> implements Dumpable { private static final String TAG = "LockIconViewController"; private static final float sDefaultDensity = diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java index ad669099284f..c6c7113d7f9a 100644 --- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java +++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java @@ -15,12 +15,19 @@ */ package com.android.keyguard; +import static com.android.settingslib.Utils.getColorAttrDefaultColor; +import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_BACKGROUND; +import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_BACKGROUND_PRESSED; +import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_BUTTON; +import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_KEY; +import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_PRESSED; import static com.android.systemui.util.ColorUtilKt.getPrivateAttrColorIfUnset; import android.animation.AnimatorSet; import android.animation.ArgbEvaluator; import android.animation.ValueAnimator; import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; @@ -112,20 +119,18 @@ class NumPadAnimator { int[] customAttrs = {android.R.attr.colorControlNormal}; ContextThemeWrapper ctw = new ContextThemeWrapper(context, mStyle); - TypedArray a = ctw.obtainStyledAttributes(customAttrs); + @SuppressLint("ResourceType") TypedArray a = ctw.obtainStyledAttributes(customAttrs); mNormalBackgroundColor = getPrivateAttrColorIfUnset(ctw, a, 0, 0, - com.android.internal.R.attr.colorSurface); + NUM_PAD_BACKGROUND); a.recycle(); - mBackground.setColor(mNormalBackgroundColor); - mPressedBackgroundColor = context.getColor(android.R.color.system_accent1_200); + mPressedBackgroundColor = getColorAttrDefaultColor(context, NUM_PAD_BACKGROUND_PRESSED); + mTextColorPressed = getColorAttrDefaultColor(context, NUM_PAD_PRESSED); + + mBackground.setColor(mNormalBackgroundColor); mTextColorPrimary = isNumPadKey - ? com.android.settingslib.Utils - .getColorAttrDefaultColor(context, android.R.attr.textColorPrimary) - : com.android.settingslib.Utils - .getColorAttrDefaultColor(context, android.R.attr.textColorPrimaryInverse); - mTextColorPressed = com.android.settingslib.Utils - .getColorAttrDefaultColor(context, com.android.internal.R.attr.textColorOnAccent); + ? getColorAttrDefaultColor(context, NUM_PAD_KEY) + : getColorAttrDefaultColor(context, NUM_PAD_BUTTON); createAnimators(); } diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java index 11c329e9811d..6ae80a62891b 100644 --- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java +++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java @@ -15,10 +15,12 @@ */ package com.android.keyguard; +import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_BUTTON; +import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_KEY; + import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Configuration; -import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.VectorDrawable; @@ -27,6 +29,7 @@ import android.view.MotionEvent; import androidx.annotation.Nullable; +import com.android.settingslib.Utils; import com.android.systemui.R; /** @@ -95,12 +98,8 @@ public class NumPadButton extends AlphaOptimizedImageButton implements NumPadAni public void reloadColors() { if (mAnimator != null) mAnimator.reloadColors(getContext()); - int textColorResId = mIsTransparentMode ? android.R.attr.textColorPrimary - : android.R.attr.textColorPrimaryInverse; - int[] customAttrs = {textColorResId}; - TypedArray a = getContext().obtainStyledAttributes(customAttrs); - int imageColor = a.getColor(0, 0); - a.recycle(); + int textColorResId = mIsTransparentMode ? NUM_PAD_KEY : NUM_PAD_BUTTON; + int imageColor = Utils.getColorAttrDefaultColor(getContext(), textColorResId); ((VectorDrawable) getDrawable()).setTintList(ColorStateList.valueOf(imageColor)); } @@ -119,7 +118,7 @@ public class NumPadButton extends AlphaOptimizedImageButton implements NumPadAni public void setTransparentMode(boolean isTransparentMode) { mIsTransparentMode = isTransparentMode; if (isTransparentMode) { - setBackgroundColor(android.R.color.transparent); + setBackgroundColor(getResources().getColor(android.R.color.transparent)); } else { setBackground(getContext().getDrawable(R.drawable.num_pad_key_background)); } diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java index 7c7680afe368..e22fc300ede5 100644 --- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java +++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java @@ -15,6 +15,8 @@ */ package com.android.keyguard; +import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_KEY; + import android.content.Context; import android.content.res.Configuration; import android.content.res.TypedArray; @@ -150,7 +152,7 @@ public class NumPadKey extends ViewGroup implements NumPadAnimationListener { * Reload colors from resources. **/ public void reloadColors() { - int textColor = Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary) + int textColor = Utils.getColorAttr(getContext(), NUM_PAD_KEY) .getDefaultColor(); int klondikeColor = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary) .getDefaultColor(); diff --git a/packages/SystemUI/src/com/android/keyguard/PinShapeHintingView.java b/packages/SystemUI/src/com/android/keyguard/PinShapeHintingView.java index fc5c254fdf29..32f06dcdbf20 100644 --- a/packages/SystemUI/src/com/android/keyguard/PinShapeHintingView.java +++ b/packages/SystemUI/src/com/android/keyguard/PinShapeHintingView.java @@ -16,6 +16,8 @@ package com.android.keyguard; +import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.PIN_SHAPES; + import android.content.Context; import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.Drawable; @@ -37,7 +39,7 @@ public class PinShapeHintingView extends LinearLayout implements PinShapeInput { private int mPinLength; private int mDotDiameter; - private int mColor = Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary) + private int mColor = Utils.getColorAttr(getContext(), PIN_SHAPES) .getDefaultColor(); private int mPosition = 0; private static final int DEFAULT_PIN_LENGTH = 6; diff --git a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java index 14810d9baf02..4aeab970e2f7 100644 --- a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java +++ b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java @@ -16,6 +16,8 @@ package com.android.keyguard; +import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.PIN_SHAPES; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -45,8 +47,7 @@ import com.android.systemui.animation.Interpolators; */ public class PinShapeNonHintingView extends LinearLayout implements PinShapeInput { - private int mColor = Utils.getColorAttr(getContext(), - android.R.attr.textColorPrimary).getDefaultColor(); + private int mColor = Utils.getColorAttr(getContext(), PIN_SHAPES).getDefaultColor(); private int mPosition = 0; private final PinShapeAdapter mPinShapeAdapter; private ValueAnimator mValueAnimator = ValueAnimator.ofFloat(1f, 0f); 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/controls/ui/PanelTaskViewController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt index 9a231814a813..025d7e40201e 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt @@ -41,6 +41,10 @@ class PanelTaskViewController( private val hide: () -> Unit = {} ) { + init { + taskView.alpha = 0f + } + private var detailTaskId = INVALID_TASK_ID private val fillInIntent = @@ -96,6 +100,7 @@ class PanelTaskViewController( override fun onTaskCreated(taskId: Int, name: ComponentName?) { detailTaskId = taskId + taskView.alpha = 1f } override fun onReleased() { 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 17e66a74927b..942730344f20 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -77,6 +77,12 @@ object Flags { // TODO(b/257315550): Tracking Bug val NO_HUN_FOR_OLD_WHEN = releasedFlag(118, "no_hun_for_old_when") + /** Makes sure notification panel is updated before the user switch is complete. */ + // 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") + // TODO(b/277338665): Tracking Bug @JvmField val NOTIFICATION_SHELF_REFACTOR = @@ -678,5 +684,6 @@ object Flags { // TODO(b/278761837): Tracking Bug @JvmField - val USE_NEW_ACTIVITY_STARTER = unreleasedFlag(2801, name = "use_new_activity_starter") + val USE_NEW_ACTIVITY_STARTER = unreleasedFlag(2801, name = "use_new_activity_starter", + teamfood = true) } 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/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt index 1fbfff95ab7e..c0d5abc04e5d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt @@ -48,6 +48,7 @@ constructor( listenForOccludedToDreaming() listenForOccludedToAodOrDozing() listenForOccludedToGone() + listenForOccludedToAlternateBouncer() } private fun listenForOccludedToDreaming() { @@ -167,6 +168,28 @@ constructor( } } + private fun listenForOccludedToAlternateBouncer() { + scope.launch { + keyguardInteractor.alternateBouncerShowing + .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair) + .collect { (isAlternateBouncerShowing, lastStartedTransitionStep) -> + if ( + isAlternateBouncerShowing && + lastStartedTransitionStep.to == KeyguardState.OCCLUDED + ) { + keyguardTransitionRepository.startTransition( + TransitionInfo( + ownerName = name, + from = KeyguardState.OCCLUDED, + to = KeyguardState.ALTERNATE_BOUNCER, + animator = getAnimator(), + ) + ) + } + } + } + } + private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator { return ValueAnimator().apply { setInterpolator(Interpolators.LINEAR) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt index 94961cbf4240..a681c43be19f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt @@ -48,10 +48,51 @@ constructor( override fun start() { listenForPrimaryBouncerToGone() - listenForPrimaryBouncerToLockscreenAodOrDozing() + listenForPrimaryBouncerToAodOrDozing() + listenForPrimaryBouncerToLockscreenOrOccluded() } - private fun listenForPrimaryBouncerToLockscreenAodOrDozing() { + private fun listenForPrimaryBouncerToLockscreenOrOccluded() { + scope.launch { + keyguardInteractor.primaryBouncerShowing + .sample( + combine( + keyguardInteractor.wakefulnessModel, + keyguardTransitionInteractor.startedKeyguardTransitionStep, + keyguardInteractor.isKeyguardOccluded, + ::toTriple + ), + ::toQuad + ) + .collect { (isBouncerShowing, wakefulnessState, lastStartedTransitionStep, occluded) + -> + if ( + !isBouncerShowing && + lastStartedTransitionStep.to == KeyguardState.PRIMARY_BOUNCER && + (wakefulnessState.state == WakefulnessState.AWAKE || + wakefulnessState.state == WakefulnessState.STARTING_TO_WAKE) + ) { + val to = + if (occluded) { + KeyguardState.OCCLUDED + } else { + KeyguardState.LOCKSCREEN + } + + keyguardTransitionRepository.startTransition( + TransitionInfo( + ownerName = name, + from = KeyguardState.PRIMARY_BOUNCER, + to = to, + animator = getAnimator(), + ) + ) + } + } + } + } + + private fun listenForPrimaryBouncerToAodOrDozing() { scope.launch { keyguardInteractor.primaryBouncerShowing .sample( @@ -68,21 +109,17 @@ constructor( -> if ( !isBouncerShowing && - lastStartedTransitionStep.to == KeyguardState.PRIMARY_BOUNCER + lastStartedTransitionStep.to == KeyguardState.PRIMARY_BOUNCER && + (wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP || + wakefulnessState.state == WakefulnessState.ASLEEP) ) { val to = - if ( - wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP || - wakefulnessState.state == WakefulnessState.ASLEEP - ) { - if (isAodAvailable) { - KeyguardState.AOD - } else { - KeyguardState.DOZING - } + if (isAodAvailable) { + KeyguardState.AOD } else { - KeyguardState.LOCKSCREEN + KeyguardState.DOZING } + keyguardTransitionRepository.startTransition( TransitionInfo( ownerName = name, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/constants/KeyguardBouncerConstants.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/constants/KeyguardBouncerConstants.kt index 3b3ec39d0209..c45faf0ba961 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/constants/KeyguardBouncerConstants.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/constants/KeyguardBouncerConstants.kt @@ -32,4 +32,15 @@ object KeyguardBouncerConstants { * PIN hinting is enabled */ const val DEFAULT_PIN_LENGTH = 6 + + object ColorId { + const val TITLE = com.android.internal.R.attr.materialColorOnSurface + const val PIN_SHAPES = com.android.internal.R.attr.materialColorOnSurfaceVariant + const val NUM_PAD_BACKGROUND = com.android.internal.R.attr.materialColorSurfaceContainerHigh + const val NUM_PAD_BACKGROUND_PRESSED = com.android.internal.R.attr.materialColorPrimaryFixed + const val NUM_PAD_PRESSED = com.android.internal.R.attr.materialColorOnPrimaryFixed + const val NUM_PAD_KEY = com.android.internal.R.attr.materialColorOnSurface + const val NUM_PAD_BUTTON = com.android.internal.R.attr.materialColorOnSecondaryFixed + const val EMERGENCY_BUTTON = com.android.internal.R.attr.materialColorTertiaryFixed + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt index 85fb5655899f..a98a7d8f8639 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt @@ -155,8 +155,15 @@ constructor( disposables.forEach { it.dispose() } } + /** + * Hides or shows smartspace + * + * @param hide TRUE hides smartspace, FALSE shows smartspace + */ fun hideSmartspace(hide: Boolean) { - smartSpaceView?.visibility = if (hide) View.INVISIBLE else View.VISIBLE + runBlocking(mainDispatcher) { + smartSpaceView?.visibility = if (hide) View.INVISIBLE else View.VISIBLE + } } /** 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/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/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java index f16f0dcc5dba..ffe5489d656f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java @@ -458,13 +458,28 @@ public class InternetTile extends QSTileImpl<SignalState> { getTileSpec(), mLastTileState, arg == null ? "null" : arg.toString()); if (arg instanceof CellularCallbackInfo) { mLastTileState = LAST_STATE_CELLULAR; - handleUpdateCellularState(state, arg); + CellularCallbackInfo cb = (CellularCallbackInfo) arg; + CellularCallbackInfo cellularInfo = new CellularCallbackInfo(); + synchronized (cb) { + cb.copyTo(cellularInfo); + } + handleUpdateCellularState(state, cellularInfo); } else if (arg instanceof WifiCallbackInfo) { mLastTileState = LAST_STATE_WIFI; - handleUpdateWifiState(state, arg); + WifiCallbackInfo cb = (WifiCallbackInfo) arg; + WifiCallbackInfo wifiInfo = new WifiCallbackInfo(); + synchronized (cb) { + cb.copyTo(wifiInfo); + } + handleUpdateWifiState(state, wifiInfo); } else if (arg instanceof EthernetCallbackInfo) { mLastTileState = LAST_STATE_ETHERNET; - handleUpdateEthernetState(state, arg); + EthernetCallbackInfo cb = (EthernetCallbackInfo) arg; + EthernetCallbackInfo ethernetInfo = new EthernetCallbackInfo(); + synchronized (cb) { + cb.copyTo(ethernetInfo); + } + handleUpdateEthernetState(state, ethernetInfo); } else { // handleUpdateState will be triggered when user expands the QuickSetting panel with // arg = null, in this case the last updated CellularCallbackInfo or WifiCallbackInfo @@ -476,11 +491,11 @@ public class InternetTile extends QSTileImpl<SignalState> { } handleUpdateCellularState(state, cellularInfo); } else if (mLastTileState == LAST_STATE_WIFI) { - WifiCallbackInfo mifiInfo = new WifiCallbackInfo(); + WifiCallbackInfo wifiInfo = new WifiCallbackInfo(); synchronized (mSignalCallback.mWifiInfo) { - mSignalCallback.mWifiInfo.copyTo(mifiInfo); + mSignalCallback.mWifiInfo.copyTo(wifiInfo); } - handleUpdateWifiState(state, mifiInfo); + handleUpdateWifiState(state, wifiInfo); } else if (mLastTileState == LAST_STATE_ETHERNET) { EthernetCallbackInfo ethernetInfo = new EthernetCallbackInfo(); synchronized (mSignalCallback.mEthernetInfo) { @@ -667,11 +682,16 @@ public class InternetTile extends QSTileImpl<SignalState> { } @Override + @NonNull public Drawable getDrawable(Context context) { SignalDrawable d = new SignalDrawable(context); d.setLevel(getState()); return d; } + @Override + public String toString() { + return String.format("SignalIcon[mState=0x%08x]", mState); + } } /** 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/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java index 1cdacb93ba45..af3cc860df57 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java @@ -27,9 +27,6 @@ import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.FrameLayout; -import com.android.systemui.R; -import com.android.systemui.statusbar.phone.TapAgainView; - /** The shade view. */ public final class NotificationPanelView extends FrameLayout { static final boolean DEBUG = false; @@ -93,10 +90,6 @@ public final class NotificationPanelView extends FrameLayout { mRtlChangeListener = listener; } - public TapAgainView getTapAgainView() { - return findViewById(R.id.shade_falsing_tap_again); - } - /** Sets the touch handler for this view. */ public void setOnTouchListener(NotificationPanelViewController.TouchHandler touchHandler) { super.setOnTouchListener(touchHandler); diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index ebbf1b5ac7c9..7cc257ba0a97 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -163,6 +163,7 @@ public class NotificationShadeWindowViewController { mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mStatusBarWindowStateController = statusBarWindowStateController; mLockIconViewController = lockIconViewController; + mLockIconViewController.init(); mService = centralSurfaces; mNotificationShadeWindowController = controller; mKeyguardUnlockAnimationController = keyguardUnlockAnimationController; diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt index 4c6673cca473..9cd8c547d1c1 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt @@ -17,6 +17,7 @@ package com.android.systemui.shade import android.view.LayoutInflater +import com.android.keyguard.LockIconView import com.android.systemui.CoreStartable import com.android.systemui.R import com.android.systemui.biometrics.AuthRippleController @@ -24,6 +25,7 @@ import com.android.systemui.biometrics.AuthRippleView import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout +import com.android.systemui.statusbar.phone.TapAgainView import dagger.Binds import dagger.Module import dagger.Provides @@ -89,5 +91,23 @@ abstract class ShadeModule { ): AuthRippleView? { return notificationShadeWindowView.findViewById(R.id.auth_ripple) } + + // TODO(b/277762009): Only allow this view's controller to inject the view. See above. + @Provides + @SysUISingleton + fun providesLockIconView( + notificationShadeWindowView: NotificationShadeWindowView, + ): LockIconView { + return notificationShadeWindowView.findViewById(R.id.lock_icon_view) + } + + // TODO(b/277762009): Only allow this view's controller to inject the view. See above. + @Provides + @SysUISingleton + fun providesTapAgainView( + notificationPanelView: NotificationPanelView, + ): TapAgainView { + return notificationPanelView.findViewById(R.id.shade_falsing_tap_again) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index cac4251bce63..e6e3e7e4fe4c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar; import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED; + import static com.android.systemui.DejankUtils.whitelistIpcs; import android.app.KeyguardManager; @@ -47,6 +48,8 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; 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.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.recents.OverviewProxyService; @@ -59,14 +62,14 @@ import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.ListenerSet; import com.android.systemui.util.settings.SecureSettings; +import dagger.Lazy; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import javax.inject.Inject; -import dagger.Lazy; - /** * Handles keeping track of the current user, profiles, and various things related to hiding * contents, redacting notifications, and the lockscreen. @@ -99,7 +102,7 @@ public class NotificationLockscreenUserManagerImpl implements private final BroadcastDispatcher mBroadcastDispatcher; private final NotificationClickNotifier mClickNotifier; private final Lazy<OverviewProxyService> mOverviewProxyServiceLazy; - + private final FeatureFlags mFeatureFlags; private boolean mShowLockscreenNotifications; private boolean mAllowLockscreenRemoteInput; private LockPatternUtils mLockPatternUtils; @@ -174,6 +177,21 @@ public class NotificationLockscreenUserManagerImpl implements new UserTracker.Callback() { @Override public void onUserChanged(int newUser, @NonNull Context userContext) { + if (!mFeatureFlags.isEnabled( + Flags.LOAD_NOTIFICATIONS_BEFORE_THE_USER_SWITCH_IS_COMPLETE)) { + handleUserChange(newUser); + } + } + + @Override + public void onUserChanging(int newUser, @NonNull Context userContext) { + if (mFeatureFlags.isEnabled( + Flags.LOAD_NOTIFICATIONS_BEFORE_THE_USER_SWITCH_IS_COMPLETE)) { + handleUserChange(newUser); + } + } + + private void handleUserChange(int newUser) { mCurrentUserId = newUser; updateCurrentProfilesCache(); @@ -216,7 +234,8 @@ public class NotificationLockscreenUserManagerImpl implements KeyguardStateController keyguardStateController, SecureSettings secureSettings, DumpManager dumpManager, - LockPatternUtils lockPatternUtils) { + LockPatternUtils lockPatternUtils, + FeatureFlags featureFlags) { mContext = context; mMainHandler = mainHandler; mDevicePolicyManager = devicePolicyManager; @@ -234,6 +253,7 @@ public class NotificationLockscreenUserManagerImpl implements mDeviceProvisionedController = deviceProvisionedController; mSecureSettings = secureSettings; mKeyguardStateController = keyguardStateController; + mFeatureFlags = featureFlags; dumpManager.registerDumpable(this); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java index a37b2a9e530a..58d705417632 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar; +import android.annotation.Nullable; import android.app.Notification; import android.app.RemoteInput; import android.content.Context; @@ -55,6 +56,13 @@ public class RemoteInputController { private final RemoteInputControllerLogger mLogger; + /** + * RemoteInput Active's last emitted value. It's added for debugging purpose to directly see + * its last emitted value. As RemoteInputController holds weak reference, isRemoteInputActive + * in dump may not reflect the last emitted value of Active. + */ + @Nullable private Boolean mLastAppliedRemoteInputActive = null; + public RemoteInputController(Delegate delegate, RemoteInputUriController remoteInputUriController, RemoteInputControllerLogger logger) { @@ -217,6 +225,7 @@ public class RemoteInputController { for (int i = 0; i < N; i++) { mCallbacks.get(i).onRemoteInputActive(remoteInputActive); } + mLastAppliedRemoteInputActive = remoteInputActive; } /** @@ -323,6 +332,8 @@ public class RemoteInputController { /** dump debug info; called by {@link NotificationRemoteInputManager} */ public void dump(@NonNull IndentingPrintWriter pw) { + pw.print("mLastAppliedRemoteInputActive: "); + pw.println((Object) mLastAppliedRemoteInputActive); pw.print("isRemoteInputActive: "); pw.println(isRemoteInputActive()); // Note that this prunes the mOpen list, printed later. pw.println("mOpen: " + mOpen.size()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index aa5aed7451f8..263566e69c88 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -1662,7 +1662,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mShadeController.setNotificationPanelViewController(npvc); mShadeController.setNotificationShadeWindowViewController( mNotificationShadeWindowViewController); - mCentralSurfacesComponent.getLockIconViewController().init(); mStackScrollerController = mCentralSurfacesComponent.getNotificationStackScrollLayoutController(); mQsController = mCentralSurfacesComponent.getQuickSettingsController(); 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/TapAgainViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainViewController.java index 582afb1a23ea..a0f12161b85a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainViewController.java @@ -19,8 +19,8 @@ package com.android.systemui.statusbar.phone; import static com.android.systemui.classifier.FalsingModule.DOUBLE_TAP_TIMEOUT_MS; import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; import com.android.systemui.util.ViewController; @@ -32,7 +32,7 @@ import javax.inject.Named; /** * Controller for {@link TapAgainView}. */ -@CentralSurfacesComponent.CentralSurfacesScope +@SysUISingleton public class TapAgainViewController extends ViewController<TapAgainView> { private final DelayableExecutor mDelayableExecutor; private final ConfigurationController mConfigurationController; @@ -84,7 +84,7 @@ public class TapAgainViewController extends ViewController<TapAgainView> { } /** Hides the associated view, possibly animating it. */ - public void hide() { + private void hide() { mHideCanceler = null; mView.animateOut(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java index ddb6d93e3c4e..273e78350f27 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java @@ -20,8 +20,6 @@ import static com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.ST import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.android.keyguard.LockIconViewController; -import com.android.systemui.biometrics.AuthRippleController; import com.android.systemui.shade.NotificationPanelViewController; import com.android.systemui.shade.NotificationShadeWindowView; import com.android.systemui.shade.NotificationShadeWindowViewController; @@ -107,11 +105,6 @@ public interface CentralSurfacesComponent { QuickSettingsController getQuickSettingsController(); /** - * Creates a LockIconViewController. Must be init after creation. - */ - LockIconViewController getLockIconViewController(); - - /** * Creates a StatusBarHeadsUpChangeListener. */ StatusBarHeadsUpChangeListener getStatusBarHeadsUpChangeListener(); 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 1a943e79a79b..2c57a268f6b8 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,7 +16,6 @@ package com.android.systemui.statusbar.phone.dagger; -import android.annotation.Nullable; import android.content.ContentResolver; import android.os.Handler; import android.view.LayoutInflater; @@ -25,7 +24,6 @@ import android.view.ViewStub; import androidx.constraintlayout.motion.widget.MotionLayout; import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.keyguard.LockIconView; import com.android.systemui.R; import com.android.systemui.battery.BatteryMeterView; import com.android.systemui.battery.BatteryMeterViewController; @@ -63,7 +61,6 @@ 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.TapAgainView; 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; @@ -139,15 +136,6 @@ public abstract class StatusBarViewModule { abstract ShadeViewController bindsShadeViewController( NotificationPanelViewController notificationPanelViewController); - /** */ - @Provides - @CentralSurfacesComponent.CentralSurfacesScope - public static LockIconView getLockIconView( - NotificationShadeWindowView notificationShadeWindowView) { - return notificationShadeWindowView.findViewById(R.id.lock_icon_view); - } - - /** */ @Provides @Named(SHADE_HEADER) @CentralSurfacesComponent.CentralSurfacesScope @@ -221,13 +209,6 @@ public abstract class StatusBarViewModule { /** */ @Provides @CentralSurfacesComponent.CentralSurfacesScope - public static TapAgainView getTapAgainView(NotificationPanelView npv) { - return npv.getTapAgainView(); - } - - /** */ - @Provides - @CentralSurfacesComponent.CentralSurfacesScope public static NotificationsQuickSettingsContainer getNotificationsQuickSettingsContainer( NotificationShadeWindowView notificationShadeWindowView) { return notificationShadeWindowView.findViewById(R.id.notification_container_parent); 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/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt index 0ec1a214660c..c2922c4d6f34 100644 --- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt @@ -26,6 +26,7 @@ import android.content.IntentFilter import android.content.pm.UserInfo import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.graphics.drawable.Icon import android.os.RemoteException import android.os.UserHandle import android.os.UserManager @@ -762,8 +763,18 @@ constructor( } // TODO(b/246631653): cache the bitmaps to avoid the background work to fetch them. - // TODO(b/246631653): downscale the bitmaps to R.dimen.max_avatar_size if requested. - val userIcon = withContext(backgroundDispatcher) { manager.getUserIcon(userId) } + val userIcon = withContext(backgroundDispatcher) { + manager.getUserIcon(userId) + ?.let { bitmap -> + val iconSize = + applicationContext + .resources + .getDimensionPixelSize(R.dimen.bouncer_user_switcher_icon_size) + Icon.scaleDownIfNecessary(bitmap, iconSize, iconSize) + } + } + + if (userIcon != null) { return BitmapDrawable(userIcon) } 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/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/controls/ui/PanelTaskViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt index f7c8ccaf731a..7840525b14aa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt @@ -19,6 +19,7 @@ package com.android.systemui.controls.ui import android.app.ActivityOptions import android.app.PendingIntent +import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK @@ -90,6 +91,11 @@ class PanelTaskViewControllerTest : SysuiTestCase() { } @Test + fun testTaskViewStartsWithAlpha0() { + verify(taskView).alpha = 0f + } + + @Test fun testLaunchTaskViewAttachedListener() { underTest.launchTaskView() verify(taskView).setListener(eq(uiExecutor), any()) @@ -120,6 +126,16 @@ class PanelTaskViewControllerTest : SysuiTestCase() { } @Test + fun testOnTaskCreated_taskViewAlpha1() { + underTest.launchTaskView() + verify(taskView).setListener(any(), capture(listenerCaptor)) + + listenerCaptor.value.onTaskCreated(1, ComponentName("Test", "TEST")) + + verify(taskView).alpha = 1f + } + + @Test fun testHideRunnableCalledWhenBackOnRoot() { underTest.launchTaskView() verify(taskView).setListener(any(), capture(listenerCaptor)) 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/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/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt index fe65236c699f..344df0acc409 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt @@ -180,7 +180,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun DREAMINGtoLOCKSCREEN() = + fun dreamingToLockscreen() = testScope.runTest { // GIVEN a device is dreaming keyguardRepository.setDreamingWithOverlay(true) @@ -215,7 +215,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun LOCKSCREENtoPRIMARY_BOUNCERviaBouncerShowingCall() = + fun lockscreenToPrimaryBouncerViaBouncerShowingCall() = testScope.runTest { // GIVEN a device that has at least woken up keyguardRepository.setWakefulnessModel(startingToWake()) @@ -242,7 +242,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun OCCLUDEDtoDOZING() = + fun occludedToDozing() = testScope.runTest { // GIVEN a device with AOD not available keyguardRepository.setAodAvailable(false) @@ -269,7 +269,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun OCCLUDEDtoAOD() = + fun occludedToAod() = testScope.runTest { // GIVEN a device with AOD available keyguardRepository.setAodAvailable(true) @@ -296,7 +296,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun LOCKSCREENtoDREAMING() = + fun lockscreenToDreaming() = testScope.runTest { // GIVEN a device that is not dreaming or dozing keyguardRepository.setDreamingWithOverlay(false) @@ -327,7 +327,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun LOCKSCREENtoDOZING() = + fun lockscreenToDozing() = testScope.runTest { // GIVEN a device with AOD not available keyguardRepository.setAodAvailable(false) @@ -354,7 +354,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun LOCKSCREENtoAOD() = + fun lockscreenToAod() = testScope.runTest { // GIVEN a device with AOD available keyguardRepository.setAodAvailable(true) @@ -381,7 +381,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun DOZINGtoLOCKSCREEN() = + fun dozingToLockscreen() = testScope.runTest { // GIVEN a prior transition has run to DOZING runTransition(KeyguardState.LOCKSCREEN, KeyguardState.DOZING) @@ -404,7 +404,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun DOZINGtoLOCKSCREENcannotBeInterrupedByDREAMING() = + fun dozingToLockscreenCannotBeInterruptedByDreaming() = testScope.runTest { // GIVEN a prior transition has started to LOCKSCREEN transitionRepository.sendTransitionStep( @@ -430,7 +430,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun DOZINGtoGONE() = + fun dozingToGone() = testScope.runTest { // GIVEN a prior transition has run to DOZING runTransition(KeyguardState.LOCKSCREEN, KeyguardState.DOZING) @@ -453,7 +453,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun GONEtoDOZING() = + fun goneToDozing() = testScope.runTest { // GIVEN a device with AOD not available keyguardRepository.setAodAvailable(false) @@ -480,7 +480,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun GONEtoAOD() = + fun goneToAod() = testScope.runTest { // GIVEN a device with AOD available keyguardRepository.setAodAvailable(true) @@ -507,7 +507,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun GONEtoLOCKSREEN() = + fun goneToLockscreen() = testScope.runTest { // GIVEN a prior transition has run to GONE runTransition(KeyguardState.LOCKSCREEN, KeyguardState.GONE) @@ -530,7 +530,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun GONEtoDREAMING() = + fun goneToDreaming() = testScope.runTest { // GIVEN a device that is not dreaming or dozing keyguardRepository.setDreamingWithOverlay(false) @@ -561,7 +561,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun ALTERNATE_BOUNCERtoPRIMARY_BOUNCER() = + fun alternateBouncerToPrimaryBouncer() = testScope.runTest { // GIVEN a prior transition has run to ALTERNATE_BOUNCER runTransition(KeyguardState.LOCKSCREEN, KeyguardState.ALTERNATE_BOUNCER) @@ -584,7 +584,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun ALTERNATE_BOUNCERtoAOD() = + fun alternateBoucnerToAod() = testScope.runTest { // GIVEN a prior transition has run to ALTERNATE_BOUNCER bouncerRepository.setAlternateVisible(true) @@ -613,7 +613,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun ALTERNATE_BOUNCERtoDOZING() = + fun alternateBouncerToDozing() = testScope.runTest { // GIVEN a prior transition has run to ALTERNATE_BOUNCER bouncerRepository.setAlternateVisible(true) @@ -643,7 +643,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun ALTERNATE_BOUNCERtoLOCKSCREEN() = + fun alternateBouncerToLockscreen() = testScope.runTest { // GIVEN a prior transition has run to ALTERNATE_BOUNCER bouncerRepository.setAlternateVisible(true) @@ -671,7 +671,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun PRIMARY_BOUNCERtoAOD() = + fun primaryBouncerToAod() = testScope.runTest { // GIVEN a prior transition has run to PRIMARY_BOUNCER bouncerRepository.setPrimaryShow(true) @@ -699,7 +699,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun PRIMARY_BOUNCERtoDOZING() = + fun primaryBouncerToDozing() = testScope.runTest { // GIVEN a prior transition has run to PRIMARY_BOUNCER bouncerRepository.setPrimaryShow(true) @@ -727,7 +727,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun PRIMARY_BOUNCERtoLOCKSCREEN() = + fun primaryBouncerToLockscreen() = testScope.runTest { // GIVEN a prior transition has run to PRIMARY_BOUNCER bouncerRepository.setPrimaryShow(true) @@ -754,7 +754,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun OCCLUDEDtoGONE() = + fun occludedToGone() = testScope.runTest { // GIVEN a device on lockscreen keyguardRepository.setKeyguardShowing(true) @@ -785,7 +785,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { } @Test - fun OCCLUDEDtoLOCKSCREEN() = + fun occludedToLockscreen() = testScope.runTest { // GIVEN a device on lockscreen keyguardRepository.setKeyguardShowing(true) @@ -813,6 +813,61 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { coroutineContext.cancelChildren() } + @Test + fun occludedToAlternateBouncer() = + testScope.runTest { + + // GIVEN a prior transition has run to OCCLUDED + runTransition(KeyguardState.LOCKSCREEN, KeyguardState.OCCLUDED) + keyguardRepository.setKeyguardOccluded(true) + runCurrent() + + // WHEN alternate bouncer shows + bouncerRepository.setAlternateVisible(true) + runCurrent() + + val info = + withArgCaptor<TransitionInfo> { + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) + } + // THEN a transition to AlternateBouncer should occur + assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor") + assertThat(info.from).isEqualTo(KeyguardState.OCCLUDED) + assertThat(info.to).isEqualTo(KeyguardState.ALTERNATE_BOUNCER) + assertThat(info.animator).isNotNull() + + coroutineContext.cancelChildren() + } + + @Test + fun primaryBouncerToOccluded() = + testScope.runTest { + // GIVEN device not sleeping + keyguardRepository.setWakefulnessModel(startingToWake()) + + // GIVEN a prior transition has run to PRIMARY_BOUNCER + runTransition(KeyguardState.LOCKSCREEN, KeyguardState.PRIMARY_BOUNCER) + bouncerRepository.setPrimaryShow(true) + runCurrent() + + // WHEN the keyguard is occluded and primary bouncer stops showing + keyguardRepository.setKeyguardOccluded(true) + bouncerRepository.setPrimaryShow(false) + runCurrent() + + val info = + withArgCaptor<TransitionInfo> { + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) + } + // THEN a transition to AlternateBouncer should occur + assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor") + assertThat(info.from).isEqualTo(KeyguardState.PRIMARY_BOUNCER) + assertThat(info.to).isEqualTo(KeyguardState.OCCLUDED) + assertThat(info.animator).isNotNull() + + coroutineContext.cancelChildren() + } + private fun startingToWake() = WakefulnessModel( WakefulnessState.STARTING_TO_WAKE, 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 1a00ac2722fe..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 @@ -17,7 +17,9 @@ 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 @@ -26,6 +28,7 @@ import androidx.test.filters.SmallTest import com.android.internal.logging.InstanceId import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback +import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingCollector import com.android.systemui.dagger.qualifiers.Main @@ -50,9 +53,11 @@ import com.android.systemui.statusbar.notification.collection.provider.OnReorder import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.concurrency.DelayableExecutor +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 @@ -68,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 @@ -77,6 +83,8 @@ import org.mockito.MockitoAnnotations private val DATA = MediaTestUtils.emptyMediaData private val SMARTSPACE_KEY = "smartspace" +private const val PAUSED_LOCAL = "paused local" +private const val PLAYING_LOCAL = "playing local" @SmallTest @TestableLooper.RunWithLooper(setAsMainLooper = true) @@ -118,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( @@ -157,7 +166,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { // Test values: key, data, last active time val playingLocal = Triple( - "playing local", + PLAYING_LOCAL, DATA.copy( active = true, isPlaying = true, @@ -181,7 +190,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { val pausedLocal = Triple( - "paused local", + PAUSED_LOCAL, DATA.copy( active = true, isPlaying = false, @@ -384,8 +393,8 @@ class MediaCarouselControllerTest : SysuiTestCase() { testPlayerOrdering() // playing paused player listener.value.onMediaDataLoaded( - "paused local", - "paused local", + PAUSED_LOCAL, + PAUSED_LOCAL, DATA.copy( active = true, isPlaying = true, @@ -394,8 +403,8 @@ class MediaCarouselControllerTest : SysuiTestCase() { ) ) listener.value.onMediaDataLoaded( - "playing local", - "playing local", + PLAYING_LOCAL, + PLAYING_LOCAL, DATA.copy( active = true, isPlaying = false, @@ -405,7 +414,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { ) assertEquals( - MediaPlayerData.getMediaPlayerIndex("paused local"), + MediaPlayerData.getMediaPlayerIndex(PAUSED_LOCAL), mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex ) // paused player order should stays the same in visibleMediaPLayer map. @@ -486,7 +495,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { @Test fun testMediaLoaded_ScrollToActivePlayer() { listener.value.onMediaDataLoaded( - "playing local", + PLAYING_LOCAL, null, DATA.copy( active = true, @@ -496,7 +505,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { ) ) listener.value.onMediaDataLoaded( - "paused local", + PAUSED_LOCAL, null, DATA.copy( active = true, @@ -514,8 +523,8 @@ class MediaCarouselControllerTest : SysuiTestCase() { mediaCarouselController.shouldScrollToKey = true // switching between media players. listener.value.onMediaDataLoaded( - "playing local", - "playing local", + PLAYING_LOCAL, + PLAYING_LOCAL, DATA.copy( active = true, isPlaying = false, @@ -524,8 +533,8 @@ class MediaCarouselControllerTest : SysuiTestCase() { ) ) listener.value.onMediaDataLoaded( - "paused local", - "paused local", + PAUSED_LOCAL, + PAUSED_LOCAL, DATA.copy( active = true, isPlaying = true, @@ -535,7 +544,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { ) assertEquals( - MediaPlayerData.getMediaPlayerIndex("paused local"), + MediaPlayerData.getMediaPlayerIndex(PAUSED_LOCAL), mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex ) } @@ -548,7 +557,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { false ) listener.value.onMediaDataLoaded( - "playing local", + PLAYING_LOCAL, null, DATA.copy( active = true, @@ -558,7 +567,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { ) ) - var playerIndex = MediaPlayerData.getMediaPlayerIndex("playing local") + var playerIndex = MediaPlayerData.getMediaPlayerIndex(PLAYING_LOCAL) assertEquals( playerIndex, mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex @@ -569,7 +578,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { // And check that the card stays in its position. mediaCarouselController.shouldScrollToKey = true listener.value.onMediaDataLoaded( - "playing local", + PLAYING_LOCAL, null, DATA.copy( active = true, @@ -579,7 +588,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { packageName = "PACKAGE_NAME" ) ) - playerIndex = MediaPlayerData.getMediaPlayerIndex("playing local") + playerIndex = MediaPlayerData.getMediaPlayerIndex(PLAYING_LOCAL) assertEquals(playerIndex, 0) } @@ -676,36 +685,52 @@ class MediaCarouselControllerTest : SysuiTestCase() { @Test fun testOnConfigChanged_playersAreAddedBack() { - listener.value.onMediaDataLoaded( - "playing local", - null, - DATA.copy( - active = true, - isPlaying = true, - playbackLocation = MediaData.PLAYBACK_LOCAL, - resumption = false - ) - ) - listener.value.onMediaDataLoaded( - "paused local", - null, - DATA.copy( - active = true, - isPlaying = false, - playbackLocation = MediaData.PLAYBACK_LOCAL, - resumption = false - ) - ) + testConfigurationChange { configListener.value.onConfigChanged(Configuration()) } + } - val playersSize = MediaPlayerData.players().size + @Test + fun testOnUiModeChanged_playersAreAddedBack() { + testConfigurationChange(configListener.value::onUiModeChanged) - configListener.value.onConfigChanged(Configuration()) + verify(pageIndicator).tintList = + ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator)) + verify(pageIndicator, times(2)).setNumPages(any()) + } - assertEquals(playersSize, MediaPlayerData.players().size) - assertEquals( - MediaPlayerData.getMediaPlayerIndex("playing local"), - mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex - ) + @Test + fun testOnDensityOrFontScaleChanged_playersAreAddedBack() { + testConfigurationChange(configListener.value::onDensityOrFontScaleChanged) + + 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 testOnThemeChanged_playersAreAddedBack() { + testConfigurationChange(configListener.value::onThemeChanged) + + verify(pageIndicator).tintList = + ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator)) + verify(pageIndicator, times(2)).setNumPages(any()) + } + + @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 @@ -846,4 +871,43 @@ class MediaCarouselControllerTest : SysuiTestCase() { // Then the carousel visibility is updated assertTrue(stateUpdated) } + + /** + * Helper method when a configuration change occurs. + * + * @param function called when a certain configuration change occurs. + */ + private fun testConfigurationChange(function: () -> Unit) { + mediaCarouselController.pageIndicator = pageIndicator + listener.value.onMediaDataLoaded( + PLAYING_LOCAL, + null, + DATA.copy( + active = true, + isPlaying = true, + playbackLocation = MediaData.PLAYBACK_LOCAL, + resumption = false + ) + ) + listener.value.onMediaDataLoaded( + PAUSED_LOCAL, + null, + DATA.copy( + active = true, + isPlaying = false, + playbackLocation = MediaData.PLAYBACK_LOCAL, + resumption = false + ) + ) + + val playersSize = MediaPlayerData.players().size + reset(pageIndicator) + function() + + assertEquals(playersSize, MediaPlayerData.players().size) + assertEquals( + MediaPlayerData.getMediaPlayerIndex(PLAYING_LOCAL), + mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex + ) + } } 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/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java index 8ee1ea8a9916..39accfb5ffcc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java @@ -49,6 +49,8 @@ import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; +import com.android.systemui.flags.FakeFeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.settings.UserTracker; @@ -110,6 +112,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { private NotificationEntry mCurrentUserNotif; private NotificationEntry mSecondaryUserNotif; private NotificationEntry mWorkProfileNotif; + private final FakeFeatureFlags mFakeFeatureFlags = new FakeFeatureFlags(); @Before public void setUp() { @@ -291,7 +294,16 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { } @Test + public void testUserSwitchedCallsOnUserSwitching() { + mFakeFeatureFlags.set(Flags.LOAD_NOTIFICATIONS_BEFORE_THE_USER_SWITCH_IS_COMPLETE, true); + mLockscreenUserManager.getUserTrackerCallbackForTest().onUserChanging(mSecondaryUser.id, + mContext); + verify(mPresenter, times(1)).onUserSwitched(mSecondaryUser.id); + } + + @Test public void testUserSwitchedCallsOnUserSwitched() { + mFakeFeatureFlags.set(Flags.LOAD_NOTIFICATIONS_BEFORE_THE_USER_SWITCH_IS_COMPLETE, false); mLockscreenUserManager.getUserTrackerCallbackForTest().onUserChanged(mSecondaryUser.id, mContext); verify(mPresenter, times(1)).onUserSwitched(mSecondaryUser.id); @@ -356,7 +368,8 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { mKeyguardStateController, mSettings, mock(DumpManager.class), - mock(LockPatternUtils.class)); + mock(LockPatternUtils.class), + mFakeFeatureFlags); } public BroadcastReceiver getBaseBroadcastReceiverForTest() { 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/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index a3b4a0f51c75..a510d1663298 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); 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/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/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index 7c32627dd1b1..55e805ab4ad0 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -28,6 +28,7 @@ import static android.app.UiModeManager.MODE_NIGHT_YES; import static android.app.UiModeManager.PROJECTION_TYPE_AUTOMOTIVE; import static android.app.UiModeManager.PROJECTION_TYPE_NONE; import static android.os.UserHandle.USER_SYSTEM; +import static android.os.UserHandle.getCallingUserId; import static android.provider.Settings.Secure.CONTRAST_LEVEL; import static android.util.TimeUtils.isTimeBetween; @@ -199,8 +200,8 @@ final class UiModeManagerService extends SystemService { private PowerManagerInternal mLocalPowerManager; @GuardedBy("mLock") - private final RemoteCallbackList<IUiModeManagerCallback> mUiModeManagerCallbacks = - new RemoteCallbackList<IUiModeManagerCallback>(); + private final SparseArray<RemoteCallbackList<IUiModeManagerCallback>> mUiModeManagerCallbacks = + new SparseArray<>(); @GuardedBy("mLock") @Nullable @@ -371,8 +372,9 @@ final class UiModeManagerService extends SystemService { synchronized (mLock) { if (updateContrastLocked()) { float contrast = getContrastLocked(); - mUiModeManagerCallbacks.broadcast(ignoreRemoteException(callback -> - callback.notifyContrastChanged(contrast))); + mUiModeManagerCallbacks.get(mCurrentUser, new RemoteCallbackList<>()) + .broadcast(ignoreRemoteException( + callback -> callback.notifyContrastChanged(contrast))); } } } @@ -664,8 +666,12 @@ final class UiModeManagerService extends SystemService { private final IUiModeManager.Stub mService = new IUiModeManager.Stub() { @Override public void addCallback(IUiModeManagerCallback callback) { + int userId = getCallingUserId(); synchronized (mLock) { - mUiModeManagerCallbacks.register(callback); + if (!mUiModeManagerCallbacks.contains(userId)) { + mUiModeManagerCallbacks.put(userId, new RemoteCallbackList<>()); + } + mUiModeManagerCallbacks.get(userId).register(callback); } } 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/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java index d8cb094caa65..6015e5f02221 100644 --- a/services/core/java/com/android/server/am/ContentProviderHelper.java +++ b/services/core/java/com/android/server/am/ContentProviderHelper.java @@ -778,7 +778,7 @@ public class ContentProviderHelper { * Drop a content provider from a ProcessRecord's bookkeeping */ void removeContentProvider(IBinder connection, boolean stable) { - mService.enforceNotIsolatedOrSdkSandboxCaller("removeContentProvider"); + mService.enforceNotIsolatedCaller("removeContentProvider"); final long ident = Binder.clearCallingIdentity(); try { ContentProviderConnection conn; diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 33f05525066e..0d89ba88c1cf 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -167,6 +167,51 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private static final int RINGBUFFER_MAX = 100; + private static final float[] BRIGHTNESS_RANGE_BOUNDARIES = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 60, 70, 80, + 90, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1200, + 1400, 1600, 1800, 2000, 2250, 2500, 2750, 3000}; + private static final int[] BRIGHTNESS_RANGE_INDEX = { + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_UNKNOWN, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_0_1, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_1_2, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_2_3, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_3_4, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_4_5, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_5_6, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_6_7, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_7_8, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_8_9, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_9_10, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_10_20, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_20_30, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_30_40, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_40_50, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_50_60, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_60_70, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_70_80, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_80_90, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_90_100, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_100_200, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_200_300, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_300_400, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_400_500, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_500_600, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_600_700, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_700_800, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_800_900, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_900_1000, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_1000_1200, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_1200_1400, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_1400_1600, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_1600_1800, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_1800_2000, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_2000_2250, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_2250_2500, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_2500_2750, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_2750_3000, + }; + private final String mTag; private final Object mLock = new Object(); @@ -1937,8 +1982,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call ? BrightnessEvent.FLAG_USER_SET : 0)); Slog.i(mTag, newEvent.toString(/* includeTime= */ false)); - if (userSetBrightnessChanged) { - logManualBrightnessEvent(newEvent); + if (userSetBrightnessChanged + || newEvent.getReason().getReason() != BrightnessReason.REASON_TEMPORARY) { + logBrightnessEvent(newEvent, unthrottledBrightnessState); } if (mBrightnessEventRingBuffer != null) { mBrightnessEventRingBuffer.append(newEvent); @@ -3091,7 +3137,63 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } - private void logManualBrightnessEvent(BrightnessEvent event) { + // Return bucket index of range_[left]_[right] where + // left <= nits < right + private int nitsToRangeIndex(float nits) { + for (int i = 0; i < BRIGHTNESS_RANGE_BOUNDARIES.length; i++) { + if (nits < BRIGHTNESS_RANGE_BOUNDARIES[i]) { + return BRIGHTNESS_RANGE_INDEX[i]; + } + } + return FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_3000_INF; + } + + private int convertBrightnessReasonToStatsEnum(int brightnessReason) { + switch(brightnessReason) { + case BrightnessReason.REASON_UNKNOWN: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_UNKNOWN; + case BrightnessReason.REASON_MANUAL: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_MANUAL; + case BrightnessReason.REASON_DOZE: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_DOZE; + case BrightnessReason.REASON_DOZE_DEFAULT: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_DOZE_DEFAULT; + case BrightnessReason.REASON_AUTOMATIC: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_AUTOMATIC; + case BrightnessReason.REASON_SCREEN_OFF: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_SCREEN_OFF; + case BrightnessReason.REASON_OVERRIDE: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_OVERRIDE; + case BrightnessReason.REASON_TEMPORARY: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_TEMPORARY; + case BrightnessReason.REASON_BOOST: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_BOOST; + case BrightnessReason.REASON_SCREEN_OFF_BRIGHTNESS_SENSOR: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_SCREEN_OFF_BRIGHTNESS_SENSOR; + case BrightnessReason.REASON_FOLLOWER: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_FOLLOWER; + } + return FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_UNKNOWN; + } + + private void logBrightnessEvent(BrightnessEvent event, float unmodifiedBrightness) { + int modifier = event.getReason().getModifier(); + int flags = event.getFlags(); + // It's easier to check if the brightness is at maximum level using the brightness + // value untouched by any modifiers + boolean brightnessIsMax = unmodifiedBrightness == event.getHbmMax(); + float brightnessInNits = convertToAdjustedNits(event.getBrightness()); float appliedLowPowerMode = event.isLowPowerModeSet() ? event.getPowerFactor() : -1f; int appliedRbcStrength = event.isRbcEnabled() ? event.getRbcStrength() : -1; float appliedHbmMaxNits = @@ -3105,7 +3207,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (mIsDisplayInternal) { FrameworkStatsLog.write(FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED, convertToAdjustedNits(event.getInitialBrightness()), - convertToAdjustedNits(event.getBrightness()), + brightnessInNits, event.getLux(), event.getPhysicalDisplayId(), event.wasShortTermModelActive(), @@ -3114,7 +3216,21 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call appliedHbmMaxNits, appliedThermalCapNits, event.isAutomaticBrightnessEnabled(), - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__REASON__REASON_MANUAL); + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__REASON__REASON_MANUAL, + convertBrightnessReasonToStatsEnum(event.getReason().getReason()), + nitsToRangeIndex(brightnessInNits), + brightnessIsMax, + event.getHbmMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT, + event.getHbmMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, + (modifier & BrightnessReason.MODIFIER_LOW_POWER) > 0, + mBrightnessThrottler.getBrightnessMaxReason(), + (modifier & BrightnessReason.MODIFIER_DIMMED) > 0, + event.isRbcEnabled(), + (flags & BrightnessEvent.FLAG_INVALID_LUX) > 0, + (flags & BrightnessEvent.FLAG_DOZE_SCALE) > 0, + (flags & BrightnessEvent.FLAG_USER_SET) > 0, + (flags & BrightnessEvent.FLAG_IDLE_CURVE) > 0, + (flags & BrightnessEvent.FLAG_LOW_POWER_MODE) > 0); } } diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java index f96b58e9ef2d..9e8c47f64926 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController2.java +++ b/services/core/java/com/android/server/display/DisplayPowerController2.java @@ -157,6 +157,51 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal private static final int RINGBUFFER_MAX = 100; + private static final float[] BRIGHTNESS_RANGE_BOUNDARIES = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 60, 70, 80, + 90, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1200, + 1400, 1600, 1800, 2000, 2250, 2500, 2750, 3000}; + private static final int[] BRIGHTNESS_RANGE_INDEX = { + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_UNKNOWN, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_0_1, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_1_2, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_2_3, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_3_4, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_4_5, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_5_6, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_6_7, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_7_8, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_8_9, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_9_10, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_10_20, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_20_30, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_30_40, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_40_50, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_50_60, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_60_70, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_70_80, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_80_90, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_90_100, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_100_200, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_200_300, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_300_400, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_400_500, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_500_600, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_600_700, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_700_800, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_800_900, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_900_1000, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_1000_1200, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_1200_1400, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_1400_1600, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_1600_1800, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_1800_2000, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_2000_2250, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_2250_2500, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_2500_2750, + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_2750_3000, + }; + private final String mTag; private final Object mLock = new Object(); @@ -1570,8 +1615,9 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal ? BrightnessEvent.FLAG_USER_SET : 0)); Slog.i(mTag, newEvent.toString(/* includeTime= */ false)); - if (userSetBrightnessChanged) { - logManualBrightnessEvent(newEvent); + if (userSetBrightnessChanged + || newEvent.getReason().getReason() != BrightnessReason.REASON_TEMPORARY) { + logBrightnessEvent(newEvent, unthrottledBrightnessState); } if (mBrightnessEventRingBuffer != null) { mBrightnessEventRingBuffer.append(newEvent); @@ -2448,7 +2494,64 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal } } - private void logManualBrightnessEvent(BrightnessEvent event) { + // Return bucket index of range_[left]_[right] where + // left <= nits < right + private int nitsToRangeIndex(float nits) { + for (int i = 0; i < BRIGHTNESS_RANGE_BOUNDARIES.length; i++) { + if (nits < BRIGHTNESS_RANGE_BOUNDARIES[i]) { + return BRIGHTNESS_RANGE_INDEX[i]; + } + } + return FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_3000_INF; + } + + private int convertBrightnessReasonToStatsEnum(int brightnessReason) { + switch(brightnessReason) { + case BrightnessReason.REASON_UNKNOWN: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_UNKNOWN; + case BrightnessReason.REASON_MANUAL: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_MANUAL; + case BrightnessReason.REASON_DOZE: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_DOZE; + case BrightnessReason.REASON_DOZE_DEFAULT: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_DOZE_DEFAULT; + case BrightnessReason.REASON_AUTOMATIC: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_AUTOMATIC; + case BrightnessReason.REASON_SCREEN_OFF: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_SCREEN_OFF; + case BrightnessReason.REASON_OVERRIDE: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_OVERRIDE; + case BrightnessReason.REASON_TEMPORARY: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_TEMPORARY; + case BrightnessReason.REASON_BOOST: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_BOOST; + case BrightnessReason.REASON_SCREEN_OFF_BRIGHTNESS_SENSOR: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_SCREEN_OFF_BRIGHTNESS_SENSOR; + case BrightnessReason.REASON_FOLLOWER: + return FrameworkStatsLog + .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_FOLLOWER; + } + return FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_UNKNOWN; + } + + private void logBrightnessEvent(BrightnessEvent event, float unmodifiedBrightness) { + int modifier = event.getReason().getModifier(); + int flags = event.getFlags(); + // It's easier to check if the brightness is at maximum level using the brightness + // value untouched by any modifiers + boolean brightnessIsMax = unmodifiedBrightness == event.getHbmMax(); + float brightnessInNits = + mDisplayBrightnessController.convertToAdjustedNits(event.getBrightness()); float appliedLowPowerMode = event.isLowPowerModeSet() ? event.getPowerFactor() : -1f; int appliedRbcStrength = event.isRbcEnabled() ? event.getRbcStrength() : -1; float appliedHbmMaxNits = @@ -2462,7 +2565,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal FrameworkStatsLog.write(FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED, mDisplayBrightnessController .convertToAdjustedNits(event.getInitialBrightness()), - mDisplayBrightnessController.convertToAdjustedNits(event.getBrightness()), + brightnessInNits, event.getLux(), event.getPhysicalDisplayId(), event.wasShortTermModelActive(), @@ -2471,7 +2574,21 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal appliedHbmMaxNits, appliedThermalCapNits, event.isAutomaticBrightnessEnabled(), - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__REASON__REASON_MANUAL); + FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__REASON__REASON_MANUAL, + convertBrightnessReasonToStatsEnum(event.getReason().getReason()), + nitsToRangeIndex(brightnessInNits), + brightnessIsMax, + event.getHbmMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT, + event.getHbmMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, + (modifier & BrightnessReason.MODIFIER_LOW_POWER) > 0, + mBrightnessThrottler.getBrightnessMaxReason(), + (modifier & BrightnessReason.MODIFIER_DIMMED) > 0, + event.isRbcEnabled(), + (flags & BrightnessEvent.FLAG_INVALID_LUX) > 0, + (flags & BrightnessEvent.FLAG_DOZE_SCALE) > 0, + (flags & BrightnessEvent.FLAG_USER_SET) > 0, + (flags & BrightnessEvent.FLAG_IDLE_CURVE) > 0, + (flags & BrightnessEvent.FLAG_LOW_POWER_MODE) > 0); } } 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/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index d1d6f5f10bc6..33e6a8f15df2 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -124,6 +124,7 @@ import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_C import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES; import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES; import static com.android.internal.util.Preconditions.checkArgument; +import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER; import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER; import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER; @@ -277,7 +278,6 @@ import android.widget.Toast; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.app.IAppOpsService; import com.android.internal.compat.IPlatformCompat; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags; @@ -306,7 +306,6 @@ import com.android.server.EventLogTags; import com.android.server.IoThread; import com.android.server.LocalServices; import com.android.server.SystemService; -import com.android.server.UiThread; import com.android.server.job.JobSchedulerInternal; import com.android.server.lights.LightsManager; import com.android.server.lights.LogicalLight; @@ -560,10 +559,10 @@ public class NotificationManagerService extends SystemService { private PermissionHelper mPermissionHelper; private UsageStatsManagerInternal mUsageStatsManagerInternal; private TelecomManager mTelecomManager; + private PostNotificationTrackerFactory mPostNotificationTrackerFactory; final IBinder mForegroundToken = new Binder(); private WorkerHandler mHandler; - private Handler mUiHandler; private final HandlerThread mRankingThread = new HandlerThread("ranker", Process.THREAD_PRIORITY_BACKGROUND); @@ -572,7 +571,6 @@ public class NotificationManagerService extends SystemService { private boolean mUseAttentionLight; boolean mHasLight = true; - boolean mLightEnabled; boolean mSystemReady; private boolean mDisableNotificationEffects; @@ -629,7 +627,6 @@ public class NotificationManagerService extends SystemService { ArrayList<String> mLights = new ArrayList<>(); private AppOpsManager mAppOps; - private IAppOpsService mAppOpsService; private UsageStatsManagerInternal mAppUsageStats; private DevicePolicyManagerInternal mDpm; private StatsManager mStatsManager; @@ -926,7 +923,7 @@ public class NotificationManagerService extends SystemService { if (oldFlags != flags) { summary.getSbn().getNotification().flags = flags; mHandler.post(new EnqueueNotificationRunnable(userId, summary, isAppForeground, - SystemClock.elapsedRealtime())); + mPostNotificationTrackerFactory.newTracker())); } } @@ -1459,7 +1456,8 @@ public class NotificationManagerService extends SystemService { // Force isAppForeground true here, because for sysui's purposes we // want to adjust the flag behaviour. mHandler.post(new EnqueueNotificationRunnable(r.getUser().getIdentifier(), - r, true /* isAppForeground*/, SystemClock.elapsedRealtime())); + r, true /* isAppForeground*/, + mPostNotificationTrackerFactory.newTracker())); } } } @@ -1489,7 +1487,8 @@ public class NotificationManagerService extends SystemService { // want to be able to adjust the flag behaviour. mHandler.post( new EnqueueNotificationRunnable(r.getUser().getIdentifier(), r, - true /* isAppForeground */, SystemClock.elapsedRealtime())); + /* foreground= */ true, + mPostNotificationTrackerFactory.newTracker())); } } } @@ -2173,11 +2172,6 @@ public class NotificationManagerService extends SystemService { } @VisibleForTesting - void setPackageManager(IPackageManager packageManager) { - mPackageManager = packageManager; - } - - @VisibleForTesting void setRankingHelper(RankingHelper rankingHelper) { mRankingHelper = rankingHelper; } @@ -2231,15 +2225,15 @@ public class NotificationManagerService extends SystemService { ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am, ActivityTaskManagerInternal atm, UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm, IUriGrantsManager ugm, - UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, IAppOpsService iAppOps, - UserManager userManager, + UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager, NotificationHistoryManager historyManager, StatsManager statsManager, TelephonyManager telephonyManager, ActivityManagerInternal ami, MultiRateLimiter toastRateLimiter, PermissionHelper permissionHelper, UsageStatsManagerInternal usageStatsManagerInternal, TelecomManager telecomManager, NotificationChannelLogger channelLogger, SystemUiSystemPropertiesFlags.FlagResolver flagResolver, - PermissionManager permissionManager) { + PermissionManager permissionManager, + PostNotificationTrackerFactory postNotificationTrackerFactory) { mHandler = handler; Resources resources = getContext().getResources(); mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(), @@ -2261,7 +2255,6 @@ public class NotificationManagerService extends SystemService { mUmInternal = LocalServices.getService(UserManagerInternal.class); mUsageStatsManagerInternal = usageStatsManagerInternal; mAppOps = appOps; - mAppOpsService = iAppOps; mAppUsageStats = appUsageStats; mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE); mCompanionManager = companionManager; @@ -2271,11 +2264,11 @@ public class NotificationManagerService extends SystemService { mDpm = dpm; mUm = userManager; mTelecomManager = telecomManager; + mPostNotificationTrackerFactory = postNotificationTrackerFactory; mPlatformCompat = IPlatformCompat.Stub.asInterface( ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); mStrongAuthTracker = new StrongAuthTracker(getContext()); - mUiHandler = new Handler(UiThread.get().getLooper()); String[] extractorNames; try { extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors); @@ -2560,7 +2553,6 @@ public class NotificationManagerService extends SystemService { UriGrantsManager.getService(), LocalServices.getService(UriGrantsManagerInternal.class), getContext().getSystemService(AppOpsManager.class), - IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE)), getContext().getSystemService(UserManager.class), new NotificationHistoryManager(getContext(), handler), mStatsManager = (StatsManager) getContext().getSystemService( @@ -2573,7 +2565,8 @@ public class NotificationManagerService extends SystemService { LocalServices.getService(UsageStatsManagerInternal.class), getContext().getSystemService(TelecomManager.class), new NotificationChannelLoggerImpl(), SystemUiSystemPropertiesFlags.getResolver(), - getContext().getSystemService(PermissionManager.class)); + getContext().getSystemService(PermissionManager.class), + new PostNotificationTrackerFactory() {}); publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL); @@ -2689,7 +2682,7 @@ public class NotificationManagerService extends SystemService { final boolean isAppForeground = mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND; mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground, - SystemClock.elapsedRealtime())); + mPostNotificationTrackerFactory.newTracker())); } } @@ -6562,6 +6555,26 @@ public class NotificationManagerService extends SystemService { void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, final int callingPid, final String tag, final int id, final Notification notification, int incomingUserId, boolean postSilently) { + PostNotificationTracker tracker = mPostNotificationTrackerFactory.newTracker(); + boolean enqueued = false; + try { + enqueued = enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, + notification, incomingUserId, postSilently, tracker); + } finally { + if (!enqueued) { + tracker.cancel(); + } + } + } + + /** + * @return True if we successfully processed the notification and handed off the task of + * enqueueing it to a background thread; false otherwise. + */ + private boolean enqueueNotificationInternal(final String pkg, final String opPkg, + final int callingUid, final int callingPid, final String tag, final int id, + final Notification notification, int incomingUserId, boolean postSilently, + PostNotificationTracker tracker) { if (DBG) { Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification); @@ -6610,7 +6623,7 @@ public class NotificationManagerService extends SystemService { throw new SecurityException("Invalid FGS notification", e); } Slog.e(TAG, "Cannot fix notification", e); - return; + return false; } if (policy == ServiceNotificationPolicy.UPDATE_ONLY) { @@ -6619,7 +6632,7 @@ public class NotificationManagerService extends SystemService { // handling. if (!isNotificationShownInternal(pkg, tag, id, userId)) { reportForegroundServiceUpdate(false, notification, id, pkg, userId); - return; + return false; } } @@ -6660,7 +6673,7 @@ public class NotificationManagerService extends SystemService { "Failed to post notification on channel \"" + channelId + "\"\n" + "See log for more details"); } - return; + return false; } final NotificationRecord r = new NotificationRecord(getContext(), n, channel); @@ -6707,7 +6720,7 @@ public class NotificationManagerService extends SystemService { if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r, r.getSbn().getOverrideGroupKey() != null)) { - return; + return false; } if (info != null) { @@ -6748,8 +6761,8 @@ public class NotificationManagerService extends SystemService { } finally { Binder.restoreCallingIdentity(token); } - mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground, - SystemClock.elapsedRealtime())); + mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground, tracker)); + return true; } private void onConversationRemovedInternal(String pkg, int uid, Set<String> shortcuts) { @@ -7069,7 +7082,7 @@ public class NotificationManagerService extends SystemService { mHandler.post( new NotificationManagerService.EnqueueNotificationRunnable( r.getUser().getIdentifier(), r, isAppForeground, - SystemClock.elapsedRealtime())); + mPostNotificationTrackerFactory.newTracker())); } } } @@ -7213,12 +7226,12 @@ public class NotificationManagerService extends SystemService { } if (n.isStyle(Notification.CallStyle.class)) { - boolean isForegroundService = (n.flags & FLAG_FOREGROUND_SERVICE) != 0; boolean hasFullScreenIntent = n.fullScreenIntent != null; - if (!isForegroundService && !hasFullScreenIntent) { + boolean requestedFullScreenIntent = (n.flags & FLAG_FSI_REQUESTED_BUT_DENIED) != 0; + if (!n.isFgsOrUij() && !hasFullScreenIntent && !requestedFullScreenIntent) { throw new IllegalArgumentException(r.getKey() + " Not posted." - + " CallStyle notifications must either be for a foreground Service or" - + " use a fullScreenIntent."); + + " CallStyle notifications must be for a foreground service or" + + " user initated job or use a fullScreenIntent."); } } @@ -7410,7 +7423,6 @@ public class NotificationManagerService extends SystemService { } else { Log.w(TAG, "Cannot snooze " + r.getKey() + ": too many snoozed notifications"); } - } @GuardedBy("mNotificationLock") @@ -7429,14 +7441,25 @@ public class NotificationManagerService extends SystemService { cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null, SystemClock.elapsedRealtime()); updateLightsLocked(); - if (mSnoozeCriterionId != null) { - mAssistants.notifyAssistantSnoozedLocked(r, mSnoozeCriterionId); - mSnoozeHelper.snooze(r, mSnoozeCriterionId); - } else { - mSnoozeHelper.snooze(r, mDuration); + if (isSnoozable(r)) { + if (mSnoozeCriterionId != null) { + mAssistants.notifyAssistantSnoozedLocked(r, mSnoozeCriterionId); + mSnoozeHelper.snooze(r, mSnoozeCriterionId); + } else { + mSnoozeHelper.snooze(r, mDuration); + } + r.recordSnoozed(); + handleSavePolicyFile(); } - r.recordSnoozed(); - handleSavePolicyFile(); + } + + /** + * Autogroup summaries are not snoozable + * They will be recreated as needed when the group children are unsnoozed + */ + private boolean isSnoozable(NotificationRecord record) { + return !(record.getNotification().isGroupSummary() && GroupHelper.AUTOGROUP_KEY.equals( + record.getNotification().getGroup())); } } @@ -7607,28 +7630,43 @@ public class NotificationManagerService extends SystemService { private final NotificationRecord r; private final int userId; private final boolean isAppForeground; - private final long enqueueElapsedTimeMs; + private final PostNotificationTracker mTracker; EnqueueNotificationRunnable(int userId, NotificationRecord r, boolean foreground, - @ElapsedRealtimeLong long enqueueElapsedTimeMs) { + PostNotificationTracker tracker) { this.userId = userId; this.r = r; this.isAppForeground = foreground; - this.enqueueElapsedTimeMs = enqueueElapsedTimeMs; + this.mTracker = checkNotNull(tracker); } @Override public void run() { + boolean enqueued = false; + try { + enqueued = enqueueNotification(); + } finally { + if (!enqueued) { + mTracker.cancel(); + } + } + } + + /** + * @return True if we successfully enqueued the notification and handed off the task of + * posting it to a background thread; false otherwise. + */ + private boolean enqueueNotification() { synchronized (mNotificationLock) { - final Long snoozeAt = + final long snoozeAt = mSnoozeHelper.getSnoozeTimeForUnpostedNotification( r.getUser().getIdentifier(), r.getSbn().getPackageName(), r.getSbn().getKey()); final long currentTime = System.currentTimeMillis(); - if (snoozeAt.longValue() > currentTime) { + if (snoozeAt > currentTime) { (new SnoozeNotificationRunnable(r.getSbn().getKey(), - snoozeAt.longValue() - currentTime, null)).snoozeLocked(r); - return; + snoozeAt - currentTime, null)).snoozeLocked(r); + return false; } final String contextId = @@ -7638,7 +7676,7 @@ public class NotificationManagerService extends SystemService { if (contextId != null) { (new SnoozeNotificationRunnable(r.getSbn().getKey(), 0, contextId)).snoozeLocked(r); - return; + return false; } mEnqueuedNotifications.add(r); @@ -7689,12 +7727,14 @@ public class NotificationManagerService extends SystemService { mAssistants.onNotificationEnqueuedLocked(r); mHandler.postDelayed( new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), - r.getUid(), enqueueElapsedTimeMs), + r.getUid(), mTracker), DELAY_FOR_ASSISTANT_TIME); } else { - mHandler.post(new PostNotificationRunnable(r.getKey(), - r.getSbn().getPackageName(), r.getUid(), enqueueElapsedTimeMs)); + mHandler.post( + new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), + r.getUid(), mTracker)); } + return true; } } } @@ -7716,22 +7756,37 @@ public class NotificationManagerService extends SystemService { protected class PostNotificationRunnable implements Runnable { private final String key; - private final long postElapsedTimeMs; private final String pkg; private final int uid; + private final PostNotificationTracker mTracker; - PostNotificationRunnable(String key, String pkg, int uid, - @ElapsedRealtimeLong long postElapsedTimeMs) { + PostNotificationRunnable(String key, String pkg, int uid, PostNotificationTracker tracker) { this.key = key; this.pkg = pkg; this.uid = uid; - this.postElapsedTimeMs = postElapsedTimeMs; + this.mTracker = checkNotNull(tracker); } @Override public void run() { + boolean posted = false; + try { + posted = postNotification(); + } finally { + if (!posted) { + mTracker.cancel(); + } + } + } + + /** + * @return True if we successfully processed the notification and handed off the task of + * notifying all listeners to a background thread; false otherwise. + */ + private boolean postNotification() { boolean appBanned = !areNotificationsEnabledForPackageInt(pkg, uid); boolean isCallNotification = isCallNotification(pkg, uid); + boolean posted = false; synchronized (mNotificationLock) { try { NotificationRecord r = null; @@ -7745,7 +7800,7 @@ public class NotificationManagerService extends SystemService { } if (r == null) { Slog.i(TAG, "Cannot find enqueued record for key: " + key); - return; + return false; } final StatusBarNotification n = r.getSbn(); @@ -7759,7 +7814,7 @@ public class NotificationManagerService extends SystemService { if (DBG) { Slog.e(TAG, "Suppressing notification from package " + pkg); } - return; + return false; } final boolean isPackageSuspended = @@ -7782,7 +7837,7 @@ public class NotificationManagerService extends SystemService { mNotificationList.add(r); mUsageStats.registerPostedByApp(r); mUsageStatsManagerInternal.reportNotificationPosted(r.getSbn().getOpPkg(), - r.getSbn().getUser(), postElapsedTimeMs); + r.getSbn().getUser(), mTracker.getStartTime()); final boolean isInterruptive = isVisuallyInterruptive(null, r); r.setInterruptive(isInterruptive); r.setTextChanged(isInterruptive); @@ -7791,7 +7846,7 @@ public class NotificationManagerService extends SystemService { mNotificationList.set(index, r); mUsageStats.registerUpdatedByApp(r, old); mUsageStatsManagerInternal.reportNotificationUpdated(r.getSbn().getOpPkg(), - r.getSbn().getUser(), postElapsedTimeMs); + r.getSbn().getUser(), mTracker.getStartTime()); // Make sure we don't lose the foreground service state. notification.flags |= old.getNotification().flags & FLAG_FOREGROUND_SERVICE; @@ -7818,8 +7873,14 @@ public class NotificationManagerService extends SystemService { } if (notification.getSmallIcon() != null) { + mTracker.setReport( + mNotificationRecordLogger.prepareToLogNotificationPosted(r, old, + position, buzzBeepBlinkLoggingCode, + getGroupInstanceId(r.getSbn().getGroupKey()))); + notifyListenersPostedAndLogLocked(r, old, mTracker); + posted = true; + StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null; - mListeners.notifyPostedLocked(r, old); if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup()) || oldSbn.getNotification().flags != n.getNotification().flags) { @@ -7860,10 +7921,6 @@ public class NotificationManagerService extends SystemService { maybeRecordInterruptionLocked(r); maybeRegisterMessageSent(r); maybeReportForegroundServiceUpdate(r, true); - - // Log event to statsd - mNotificationRecordLogger.maybeLogNotificationPosted(r, old, position, - buzzBeepBlinkLoggingCode, getGroupInstanceId(r.getSbn().getGroupKey())); } finally { int N = mEnqueuedNotifications.size(); for (int i = 0; i < N; i++) { @@ -7875,6 +7932,7 @@ public class NotificationManagerService extends SystemService { } } } + return posted; } } @@ -10790,6 +10848,34 @@ public class NotificationManagerService extends SystemService { } } + /** + * Asynchronously notify all listeners about a posted (new or updated) notification. This + * should be called from {@link PostNotificationRunnable} to "complete" the post (since SysUI is + * one of the NLSes, and will display it to the user). + * + * <p>This method will call {@link PostNotificationTracker#finish} on the supplied tracker + * when every {@link NotificationListenerService} has received the news. + * + * <p>Also takes care of removing a notification that has been visible to a listener before, + * but isn't anymore. + */ + @GuardedBy("mNotificationLock") + private void notifyListenersPostedAndLogLocked(NotificationRecord r, NotificationRecord old, + @NonNull PostNotificationTracker tracker) { + List<Runnable> listenerCalls = mListeners.prepareNotifyPostedLocked(r, old, true); + mHandler.post(() -> { + for (Runnable listenerCall : listenerCalls) { + listenerCall.run(); + } + + tracker.finish(); + NotificationRecordLogger.NotificationReported report = tracker.getReport(); + if (report != null) { + mNotificationRecordLogger.logNotificationPosted(report); + } + }); + } + public class NotificationListeners extends ManagedServices { static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners"; static final String TAG_REQUESTED_LISTENERS = "request_listeners"; @@ -11160,28 +11246,59 @@ public class NotificationManagerService extends SystemService { } /** - * asynchronously notify all listeners about a new notification + * Asynchronously notify all listeners about a new or updated notification. Note that the + * notification is new or updated from the point of view of the NLS, but might not be + * "strictly new" <em>from the point of view of NMS itself</em> -- for example, this method + * is also invoked after exiting lockdown mode. * * <p> * Also takes care of removing a notification that has been visible to a listener before, * but isn't anymore. */ + @VisibleForTesting @GuardedBy("mNotificationLock") - public void notifyPostedLocked(NotificationRecord r, NotificationRecord old) { + void notifyPostedLocked(NotificationRecord r, NotificationRecord old) { notifyPostedLocked(r, old, true); } /** + * Asynchronously notify all listeners about a new or updated notification. Note that the + * notification is new or updated from the point of view of the NLS, but might not be + * "strictly new" <em>from the point of view of NMS itself</em> -- for example, this method + * is invoked after exiting lockdown mode. + * * @param notifyAllListeners notifies all listeners if true, else only notifies listeners - * targetting <= O_MR1 + * targeting <= O_MR1 */ + @VisibleForTesting @GuardedBy("mNotificationLock") void notifyPostedLocked(NotificationRecord r, NotificationRecord old, boolean notifyAllListeners) { + for (Runnable listenerCall : prepareNotifyPostedLocked(r, old, notifyAllListeners)) { + mHandler.post(listenerCall); + } + } + + /** + * "Prepares" to notify all listeners about the posted notification. + * + * <p>This method <em>does not invoke</em> the listeners; the caller should post each + * returned {@link Runnable} on a suitable thread to do so. + * + * @param notifyAllListeners notifies all listeners if true, else only notifies listeners + * targeting <= O_MR1 + * @return A list of {@link Runnable} operations to notify all listeners about the posted + * notification. + */ + @VisibleForTesting + @GuardedBy("mNotificationLock") + List<Runnable> prepareNotifyPostedLocked(NotificationRecord r, + NotificationRecord old, boolean notifyAllListeners) { if (isInLockDownMode(r.getUser().getIdentifier())) { - return; + return new ArrayList<>(); } + ArrayList<Runnable> listenerCalls = new ArrayList<>(); try { // Lazily initialized snapshots of the notification. StatusBarNotification sbn = r.getSbn(); @@ -11215,7 +11332,7 @@ public class NotificationManagerService extends SystemService { // This notification became invisible -> remove the old one. if (oldSbnVisible && !sbnVisible) { final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight(); - mHandler.post(() -> notifyRemoved( + listenerCalls.add(() -> notifyRemoved( info, oldSbnLightClone, update, null, REASON_USER_STOPPED)); continue; } @@ -11231,11 +11348,12 @@ public class NotificationManagerService extends SystemService { false /* direct */, false /* retainOnUpdate */); final StatusBarNotification sbnToPost = trimCache.ForListener(info); - mHandler.post(() -> notifyPosted(info, sbnToPost, update)); + listenerCalls.add(() -> notifyPosted(info, sbnToPost, update)); } } catch (Exception e) { Slog.e(TAG, "Could not notify listeners for " + r.getKey(), e); } + return listenerCalls; } /** @@ -11417,7 +11535,7 @@ public class NotificationManagerService extends SystemService { int numChangedNotifications = changedNotifications.size(); for (int i = 0; i < numChangedNotifications; i++) { NotificationRecord rec = changedNotifications.get(i); - mListeners.notifyPostedLocked(rec, rec, false); + notifyPostedLocked(rec, rec, false); } } @@ -12016,4 +12134,76 @@ public class NotificationManagerService extends SystemService { && !CompatChanges.isChangeEnabled(NOTIFICATION_TRAMPOLINE_BLOCK, uid); } } + + interface PostNotificationTrackerFactory { + default PostNotificationTracker newTracker() { + return new PostNotificationTracker(); + } + } + + static class PostNotificationTracker { + @ElapsedRealtimeLong private final long mStartTime; + @Nullable private NotificationRecordLogger.NotificationReported mReport; + private boolean mOngoing; + + @VisibleForTesting + PostNotificationTracker() { + // TODO(b/275044361): (Conditionally) receive a wakelock. + mStartTime = SystemClock.elapsedRealtime(); + mOngoing = true; + if (DBG) { + Slog.d(TAG, "PostNotification: Started"); + } + } + + void setReport(@Nullable NotificationRecordLogger.NotificationReported report) { + mReport = report; + } + + NotificationRecordLogger.NotificationReported getReport() { + return mReport; + } + + @ElapsedRealtimeLong + long getStartTime() { + return mStartTime; + } + + @VisibleForTesting + boolean isOngoing() { + return mOngoing; + } + + void cancel() { + if (!isOngoing()) { + Log.wtfStack(TAG, "cancel() called on already-finished tracker"); + return; + } + mOngoing = false; + + // TODO(b/275044361): Release wakelock. + + if (DBG) { + long elapsedTime = SystemClock.elapsedRealtime() - mStartTime; + Slog.d(TAG, TextUtils.formatSimple("PostNotification: Abandoned after %d ms", + elapsedTime)); + } + } + + void finish() { + if (!isOngoing()) { + Log.wtfStack(TAG, "finish() called on already-finished tracker"); + return; + } + mOngoing = false; + + // TODO(b/275044361): Release wakelock. + + long elapsedTime = SystemClock.elapsedRealtime() - mStartTime; + if (DBG) { + Slog.d(TAG, + TextUtils.formatSimple("PostNotification: Finished in %d ms", elapsedTime)); + } + } + } } diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java index 25d619dea296..71ebf7a39610 100644 --- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java +++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java @@ -42,26 +42,45 @@ import java.util.Objects; * in production. Use NotificationRecordLoggerFake for testing. * @hide */ -public interface NotificationRecordLogger { +interface NotificationRecordLogger { // The high-level interface used by clients. /** - * May log a NotificationReported atom reflecting the posting or update of a notification. - * @param r The new NotificationRecord. If null, no action is taken. - * @param old The previous NotificationRecord. Null if there was no previous record. + * Prepare to log an atom reflecting the posting or update of a notification. + * + * The returned {@link NotificationReported} object, if any, should be supplied to + * {@link #logNotificationPosted}. Because only some updates are considered "interesting + * enough" to log, this method may return {@code null}. In that case, the follow-up call + * should not be performed. + * + * @param r The new {@link NotificationRecord}. + * @param old The previous {@link NotificationRecord}. Null if there was no previous record. * @param position The position at which this notification is ranked. * @param buzzBeepBlink Logging code reflecting whether this notification alerted the user. - * @param groupId The instance Id of the group summary notification, or null. + * @param groupId The {@link InstanceId} of the group summary notification, or null. */ - void maybeLogNotificationPosted(@Nullable NotificationRecord r, + @Nullable + default NotificationReported prepareToLogNotificationPosted(@Nullable NotificationRecord r, @Nullable NotificationRecord old, int position, int buzzBeepBlink, - InstanceId groupId); + InstanceId groupId) { + NotificationRecordPair p = new NotificationRecordPair(r, old); + if (!p.shouldLogReported(buzzBeepBlink)) { + return null; + } + return new NotificationReported(p, NotificationReportedEvent.fromRecordPair(p), position, + buzzBeepBlink, groupId); + } + + /** + * Log a NotificationReported atom reflecting the posting or update of a notification. + */ + void logNotificationPosted(NotificationReported nr); /** * Logs a NotificationReported atom reflecting an adjustment to a notification. - * Unlike maybeLogNotificationPosted, this method is guaranteed to log a notification update, + * Unlike for posted notifications, this method is guaranteed to log a notification update, * so the caller must take responsibility for checking that that logging update is necessary, * and that the notification is meaningfully changed. * @param r The NotificationRecord. If null, no action is taken. @@ -125,7 +144,7 @@ public interface NotificationRecordLogger { public static NotificationReportedEvent fromRecordPair(NotificationRecordPair p) { return (p.old != null) ? NotificationReportedEvent.NOTIFICATION_UPDATED : - NotificationReportedEvent.NOTIFICATION_POSTED; + NotificationReportedEvent.NOTIFICATION_POSTED; } } @@ -450,6 +469,68 @@ public interface NotificationRecordLogger { } + /** Data object corresponding to a NotificationReported atom. + * + * Fields must be kept in sync with frameworks/proto_logging/stats/atoms.proto. + */ + class NotificationReported { + final int event_id; + final int uid; + final String package_name; + final int instance_id; + final int notification_id_hash; + final int channel_id_hash; + final int group_id_hash; + final int group_instance_id; + final boolean is_group_summary; + final String category; + final int style; + final int num_people; + final int position; + final int importance; + final int alerting; + final int importance_source; + final int importance_initial; + final int importance_initial_source; + final int importance_asst; + final int assistant_hash; + final float assistant_ranking_score; + final boolean is_ongoing; + final boolean is_foreground_service; + final long timeout_millis; + final boolean is_non_dismissible; + + NotificationReported(NotificationRecordPair p, + NotificationReportedEvent eventType, int position, int buzzBeepBlink, + InstanceId groupId) { + this.event_id = eventType.getId(); + this.uid = p.r.getUid(); + this.package_name = p.r.getSbn().getPackageName(); + this.instance_id = p.getInstanceId(); + this.notification_id_hash = p.getNotificationIdHash(); + this.channel_id_hash = p.getChannelIdHash(); + this.group_id_hash = p.getGroupIdHash(); + this.group_instance_id = (groupId == null) ? 0 : groupId.getId(); + this.is_group_summary = p.r.getSbn().getNotification().isGroupSummary(); + this.category = p.r.getSbn().getNotification().category; + this.style = p.getStyle(); + this.num_people = p.getNumPeople(); + this.position = position; + this.importance = NotificationRecordLogger.getLoggingImportance(p.r); + this.alerting = buzzBeepBlink; + this.importance_source = p.r.getImportanceExplanationCode(); + this.importance_initial = p.r.getInitialImportance(); + this.importance_initial_source = p.r.getInitialImportanceExplanationCode(); + this.importance_asst = p.r.getAssistantImportance(); + this.assistant_hash = p.getAssistantHash(); + this.assistant_ranking_score = p.r.getRankingScore(); + this.is_ongoing = p.r.getSbn().isOngoing(); + this.is_foreground_service = NotificationRecordLogger.isForegroundService(p.r); + this.timeout_millis = p.r.getSbn().getNotification().getTimeoutAfter(); + this.is_non_dismissible = NotificationRecordLogger.isNonDismissible(p.r); + } + } + /** * @param r NotificationRecord * @return Logging importance of record, taking important conversation channels into account. diff --git a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java index 9a1f19d0c514..cd457b793390 100644 --- a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java +++ b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java @@ -27,20 +27,13 @@ import com.android.internal.util.FrameworkStatsLog; * Standard implementation of NotificationRecordLogger interface. * @hide */ -public class NotificationRecordLoggerImpl implements NotificationRecordLogger { +class NotificationRecordLoggerImpl implements NotificationRecordLogger { private UiEventLogger mUiEventLogger = new UiEventLoggerImpl(); @Override - public void maybeLogNotificationPosted(NotificationRecord r, NotificationRecord old, - int position, int buzzBeepBlink, - InstanceId groupId) { - NotificationRecordPair p = new NotificationRecordPair(r, old); - if (!p.shouldLogReported(buzzBeepBlink)) { - return; - } - writeNotificationReportedAtom(p, NotificationReportedEvent.fromRecordPair(p), - position, buzzBeepBlink, groupId); + public void logNotificationPosted(NotificationReported nr) { + writeNotificationReportedAtom(nr); } @Override @@ -48,48 +41,40 @@ public class NotificationRecordLoggerImpl implements NotificationRecordLogger { int position, int buzzBeepBlink, InstanceId groupId) { NotificationRecordPair p = new NotificationRecordPair(r, null); - writeNotificationReportedAtom(p, NotificationReportedEvent.NOTIFICATION_ADJUSTED, - position, buzzBeepBlink, groupId); + writeNotificationReportedAtom( + new NotificationReported(p, NotificationReportedEvent.NOTIFICATION_ADJUSTED, + position, buzzBeepBlink, groupId)); } - private void writeNotificationReportedAtom(NotificationRecordPair p, - NotificationReportedEvent eventType, int position, int buzzBeepBlink, - InstanceId groupId) { - FrameworkStatsLog.write(FrameworkStatsLog.NOTIFICATION_REPORTED, - /* int32 event_id = 1 */ eventType.getId(), - /* int32 uid = 2 */ p.r.getUid(), - /* string package_name = 3 */ p.r.getSbn().getPackageName(), - /* int32 instance_id = 4 */ p.getInstanceId(), - /* int32 notification_id_hash = 5 */ p.getNotificationIdHash(), - /* int32 channel_id_hash = 6 */ p.getChannelIdHash(), - /* string group_id_hash = 7 */ p.getGroupIdHash(), - /* int32 group_instance_id = 8 */ (groupId == null) ? 0 : groupId.getId(), - /* bool is_group_summary = 9 */ p.r.getSbn().getNotification().isGroupSummary(), - /* string category = 10 */ p.r.getSbn().getNotification().category, - /* int32 style = 11 */ p.getStyle(), - /* int32 num_people = 12 */ p.getNumPeople(), - /* int32 position = 13 */ position, - /* android.stats.sysui.NotificationImportance importance = 14 */ - NotificationRecordLogger.getLoggingImportance(p.r), - /* int32 alerting = 15 */ buzzBeepBlink, - /* NotificationImportanceExplanation importance_source = 16 */ - p.r.getImportanceExplanationCode(), - /* android.stats.sysui.NotificationImportance importance_initial = 17 */ - p.r.getInitialImportance(), - /* NotificationImportanceExplanation importance_initial_source = 18 */ - p.r.getInitialImportanceExplanationCode(), - /* android.stats.sysui.NotificationImportance importance_asst = 19 */ - p.r.getAssistantImportance(), - /* int32 assistant_hash = 20 */ p.getAssistantHash(), - /* float assistant_ranking_score = 21 */ p.r.getRankingScore(), - /* bool is_ongoing = 22 */ p.r.getSbn().isOngoing(), - /* bool is_foreground_service = 23 */ - NotificationRecordLogger.isForegroundService(p.r), - /* optional int64 timeout_millis = 24 */ - p.r.getSbn().getNotification().getTimeoutAfter(), - /* bool is_nondismissible = 25 */ - NotificationRecordLogger.isNonDismissible(p.r) - ); + private void writeNotificationReportedAtom( + NotificationReported notificationReported) { + FrameworkStatsLog.write( + FrameworkStatsLog.NOTIFICATION_REPORTED, + notificationReported.event_id, + notificationReported.uid, + notificationReported.package_name, + notificationReported.instance_id, + notificationReported.notification_id_hash, + notificationReported.channel_id_hash, + notificationReported.group_id_hash, + notificationReported.group_instance_id, + notificationReported.is_group_summary, + notificationReported.category, + notificationReported.style, + notificationReported.num_people, + notificationReported.position, + notificationReported.importance, + notificationReported.alerting, + notificationReported.importance_source, + notificationReported.importance_initial, + notificationReported.importance_initial_source, + notificationReported.importance_asst, + notificationReported.assistant_hash, + notificationReported.assistant_ranking_score, + notificationReported.is_ongoing, + notificationReported.is_foreground_service, + notificationReported.timeout_millis, + notificationReported.is_non_dismissible); } @Override 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/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/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java index e447049a7362..1a3d6730fe20 100644 --- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java +++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java @@ -452,6 +452,9 @@ public class BackgroundActivityStartController { // If we are here, it means all exemptions not based on PI sender failed, so we'll block // unless resultIfPiSenderAllowsBal is an allow and the PI sender allows BAL + String realCallingPackage = callingUid == realCallingUid ? callingPackage : + mService.mContext.getPackageManager().getNameForUid(realCallingUid); + String stateDumpLog = " [callingPackage: " + callingPackage + "; callingUid: " + callingUid + "; appSwitchState: " + appSwitchState @@ -460,6 +463,7 @@ public class BackgroundActivityStartController { ActivityManager.class, "PROCESS_STATE_", callingUidProcState) + "; isCallingUidPersistentSystemProcess: " + isCallingUidPersistentSystemProcess + "; balAllowedByPiSender: " + balAllowedByPiSender + + "; realCallingPackage: " + realCallingPackage + "; realCallingUid: " + realCallingUid + "; realCallingUidHasAnyVisibleWindow: " + realCallingUidHasAnyVisibleWindow + "; realCallingUidProcState: " + DebugUtils.valueToString( diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 8bfa4269af1c..ef38e8962599 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -2190,6 +2190,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } mWmService.mDisplayManagerInternal.performTraversal(transaction); + if (shellTransitions) { + // Before setDisplayProjection is applied by the start transaction of transition, + // set the transform hint to avoid using surface in old rotation. + getPendingTransaction().setFixedTransformHint(mSurfaceControl, rotation); + // The sync transaction should already contains setDisplayProjection, so unset the + // hint to restore the natural state when the transaction is applied. + transaction.unsetFixedTransformHint(mSurfaceControl); + } scheduleAnimation(); mWmService.mRotationWatcherController.dispatchDisplayRotationChange(mDisplayId, rotation); 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 54dfdd93b26c..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). */ @@ -865,6 +875,13 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { if (c.getSnapshot() != null) { t.reparent(c.getSnapshot(), null); } + // The fixed transform hint was set in DisplayContent#applyRotation(). Make sure to + // clear the hint in case the start transaction is not applied. + if (c.hasFlags(FLAG_IS_DISPLAY) && c.getStartRotation() != c.getEndRotation() + && c.getContainer() != null) { + t.unsetFixedTransformHint(WindowContainer.fromBinder(c.getContainer().asBinder()) + .asDisplayContent().mSurfaceControl); + } } for (int i = info.getRootCount() - 1; i >= 0; --i) { final SurfaceControl leash = info.getRoot(i).getLeash(); @@ -959,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); @@ -1016,6 +1035,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } ar.commitVisibility(false /* visible */, false /* performLayout */, true /* fromTransition */); + committedSomeInvisible = true; } else { enterAutoPip = true; } @@ -1074,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. @@ -1286,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. @@ -1799,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 8af037be8d06..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 */ @@ -823,6 +823,17 @@ class TransitionController { // Can reset track-count now that everything is idle. mTrackCount = 0; validateStates(); + mAtm.mWindowManager.onAnimationFinished(); + } + } + + /** 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; } } @@ -963,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/TransitionTracer.java b/services/core/java/com/android/server/wm/TransitionTracer.java index 6597d4c7f916..6aac81bc3b6c 100644 --- a/services/core/java/com/android/server/wm/TransitionTracer.java +++ b/services/core/java/com/android/server/wm/TransitionTracer.java @@ -21,6 +21,7 @@ import static android.os.Build.IS_USER; import static com.android.server.wm.shell.TransitionTraceProto.MAGIC_NUMBER; import static com.android.server.wm.shell.TransitionTraceProto.MAGIC_NUMBER_H; import static com.android.server.wm.shell.TransitionTraceProto.MAGIC_NUMBER_L; +import static com.android.server.wm.shell.TransitionTraceProto.REAL_TO_ELAPSED_TIME_OFFSET_NANOS; import android.annotation.NonNull; import android.annotation.Nullable; @@ -37,6 +38,7 @@ import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.concurrent.TimeUnit; /** * Helper class to collect and dump transition traces. @@ -395,6 +397,10 @@ public class TransitionTracer { try { ProtoOutputStream proto = new ProtoOutputStream(); proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE); + long timeOffsetNs = + TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis()) + - SystemClock.elapsedRealtimeNanos(); + proto.write(REAL_TO_ELAPSED_TIME_OFFSET_NANOS, timeOffsetNs); int pid = android.os.Process.myPid(); LogAndPrintln.i(pw, "Writing file to " + file.getAbsolutePath() + " from process " + pid); 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 40024f1f0be3..0a4cd7a9a8a4 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -7721,7 +7721,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, @@ -12214,17 +12214,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 +12277,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 +12306,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 +12359,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); } } @@ -20215,9 +20248,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private boolean isLockTaskFeatureEnabled(int lockTaskFeature) throws RemoteException { - //TODO(b/175285301): Explicitly get the user's identity to check. - int lockTaskFeatures = - getUserData(getCurrentForegroundUserId()).mLockTaskFeatures; + int lockTaskFeatures = 0; + if (isPolicyEngineForFinanceFlagEnabled()) { + LockTaskPolicy policy = mDevicePolicyEngine.getResolvedPolicy( + PolicyDefinition.LOCK_TASK, getCurrentForegroundUserId()); + lockTaskFeatures = policy == null + // We default on the power button menu, in order to be consistent with pre-P + // behaviour. + ? DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS + : policy.getFlags(); + } else { + //TODO(b/175285301): Explicitly get the user's identity to check. + lockTaskFeatures = + getUserData(getCurrentForegroundUserId()).mLockTaskFeatures; + } return (lockTaskFeatures & lockTaskFeature) == lockTaskFeature; } @@ -21602,7 +21646,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } copyAccount(targetUser, sourceUser, accountToMigrate, callerPackage); if (!keepAccountMigrated) { - removeAccount(accountToMigrate); + removeAccount(accountToMigrate, sourceUserId); } } @@ -21646,9 +21690,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 { @@ -23709,15 +23754,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); } @@ -23782,6 +23826,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/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/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/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 5dbc6ab4a6d0..e31eed2be367 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -94,6 +94,7 @@ import static junit.framework.Assert.assertSame; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; +import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyLong; @@ -212,7 +213,6 @@ import android.widget.RemoteViews; import androidx.test.InstrumentationRegistry; -import com.android.internal.app.IAppOpsService; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.Flag; import com.android.internal.config.sysui.TestableFlagResolver; @@ -232,6 +232,8 @@ import com.android.server.lights.LightsManager; import com.android.server.lights.LogicalLight; import com.android.server.notification.NotificationManagerService.NotificationAssistants; import com.android.server.notification.NotificationManagerService.NotificationListeners; +import com.android.server.notification.NotificationManagerService.PostNotificationTracker; +import com.android.server.notification.NotificationManagerService.PostNotificationTrackerFactory; import com.android.server.pm.PackageManagerService; import com.android.server.pm.UserManagerInternal; import com.android.server.policy.PermissionPolicyInternal; @@ -345,6 +347,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { private PermissionManager mPermissionManager; @Mock private DevicePolicyManagerInternal mDevicePolicyManager; + private final TestPostNotificationTrackerFactory mPostNotificationTrackerFactory = + new TestPostNotificationTrackerFactory(); @Mock IIntentSender pi1; @@ -381,8 +385,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Mock AppOpsManager mAppOpsManager; @Mock - IAppOpsService mAppOpsService; - @Mock private TestableNotificationManagerService.NotificationAssistantAccessGrantedCallback mNotificationAssistantAccessGrantedCallback; @Mock @@ -420,6 +422,18 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } } + private class TestPostNotificationTrackerFactory implements PostNotificationTrackerFactory { + + private final List<PostNotificationTracker> mCreatedTrackers = new ArrayList<>(); + + @Override + public PostNotificationTracker newTracker() { + PostNotificationTracker tracker = PostNotificationTrackerFactory.super.newTracker(); + mCreatedTrackers.add(tracker); + return tracker; + } + } + @Before public void setUp() throws Exception { // Shell permisssions will override permissions of our app, so add all necessary permissions @@ -557,10 +571,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mockLightsManager, mListeners, mAssistants, mConditionProviders, mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager, mGroupHelper, mAm, mAtm, mAppUsageStats, mDevicePolicyManager, mUgm, mUgmInternal, - mAppOpsManager, mAppOpsService, mUm, mHistoryManager, mStatsManager, + mAppOpsManager, mUm, mHistoryManager, mStatsManager, mock(TelephonyManager.class), mAmi, mToastRateLimiter, mPermissionHelper, mock(UsageStatsManagerInternal.class), - mTelecomManager, mLogger, mTestFlagResolver, mPermissionManager); + mTelecomManager, mLogger, mTestFlagResolver, mPermissionManager, + mPostNotificationTrackerFactory); // Return first true for RoleObserver main-thread check when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false); mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper); @@ -643,11 +658,22 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @After public void assertNotificationRecordLoggerCallsValid() { + waitForIdle(); // Finish async work, including all logging calls done by Runnables. for (NotificationRecordLoggerFake.CallRecord call : mNotificationRecordLogger.getCalls()) { if (call.wasLogged) { assertNotNull(call.event); } } + assertThat(mNotificationRecordLogger.getPendingLogs()).isEmpty(); + } + + @After + public void assertAllTrackersFinishedOrCancelled() { + // Verify that no trackers were left dangling. + for (PostNotificationTracker tracker : mPostNotificationTrackerFactory.mCreatedTrackers) { + assertThat(tracker.isOngoing()).isFalse(); + } + mPostNotificationTrackerFactory.mCreatedTrackers.clear(); } @After @@ -1451,7 +1477,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { NotificationManagerService.PostNotificationRunnable runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), - r.getUid(), SystemClock.elapsedRealtime()); + r.getUid(), mPostNotificationTrackerFactory.newTracker()); runnable.run(); waitForIdle(); @@ -1472,7 +1498,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { NotificationManagerService.PostNotificationRunnable runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), - r.getUid(), SystemClock.elapsedRealtime()); + r.getUid(), mPostNotificationTrackerFactory.newTracker()); runnable.run(); waitForIdle(); @@ -1712,6 +1738,68 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void enqueueNotificationWithTag_usesAndFinishesTracker() throws Exception { + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, + generateNotificationRecord(null).getNotification(), 0); + + assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); + assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isTrue(); + + waitForIdle(); + + assertThat(mBinderService.getActiveNotifications(PKG)).hasLength(1); + assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); + assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse(); + } + + @Test + public void enqueueNotificationWithTag_throws_usesAndCancelsTracker() throws Exception { + // Simulate not enqueued due to rejected inputs. + assertThrows(Exception.class, + () -> mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, + /* notification= */ null, 0)); + + waitForIdle(); + + assertThat(mBinderService.getActiveNotifications(PKG)).hasLength(0); + assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); + assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse(); + } + + @Test + public void enqueueNotificationWithTag_notEnqueued_usesAndCancelsTracker() throws Exception { + // Simulate not enqueued due to snoozing inputs. + when(mSnoozeHelper.getSnoozeContextForUnpostedNotification(anyInt(), any(), any())) + .thenReturn("zzzzzzz"); + + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, + generateNotificationRecord(null).getNotification(), 0); + waitForIdle(); + + assertThat(mBinderService.getActiveNotifications(PKG)).hasLength(0); + assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); + assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse(); + } + + @Test + public void enqueueNotificationWithTag_notPosted_usesAndCancelsTracker() throws Exception { + // Simulate not posted due to blocked app. + when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false); + + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, + generateNotificationRecord(null).getNotification(), 0); + waitForIdle(); + + assertThat(mBinderService.getActiveNotifications(PKG)).hasLength(0); + assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); + assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse(); + } + + @Test public void testCancelNonexistentNotification() throws Exception { mBinderService.cancelNotificationWithTag(PKG, PKG, "testCancelNonexistentNotification", 0, 0); @@ -1908,8 +1996,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.mSummaryByGroupKey.put("pkg", summary); mService.mAutobundledSummaries.put(0, new ArrayMap<>()); mService.mAutobundledSummaries.get(0).put("pkg", summary.getKey()); + mService.updateAutobundledSummaryFlags( 0, "pkg", GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, false); + waitForIdle(); assertTrue(summary.getSbn().isOngoing()); } @@ -1926,6 +2016,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.mSummaryByGroupKey.put("pkg", summary); mService.updateAutobundledSummaryFlags(0, "pkg", GroupHelper.BASE_FLAGS, false); + waitForIdle(); assertFalse(summary.getSbn().isOngoing()); } @@ -3775,6 +3866,37 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testSnoozeRunnable_snoozeAutoGroupChild_summaryNotSnoozed() throws Exception { + final NotificationRecord parent = generateNotificationRecord( + mTestNotificationChannel, 1, GroupHelper.AUTOGROUP_KEY, true); + final NotificationRecord child = generateNotificationRecord( + mTestNotificationChannel, 2, GroupHelper.AUTOGROUP_KEY, false); + mService.addNotification(parent); + mService.addNotification(child); + when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); + + // snooze child only + NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = + mService.new SnoozeNotificationRunnable( + child.getKey(), 100, null); + snoozeNotificationRunnable.run(); + + // only child should be snoozed + verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong()); + + // both group summary and child should be cancelled + assertNull(mService.getNotificationRecord(parent.getKey())); + assertNull(mService.getNotificationRecord(child.getKey())); + + assertEquals(4, mNotificationRecordLogger.numCalls()); + assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, + mNotificationRecordLogger.event(0)); + assertEquals( + NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED, + mNotificationRecordLogger.event(1)); + } + + @Test public void testPostGroupChild_unsnoozeParent() throws Exception { final NotificationRecord child = generateNotificationRecord( mTestNotificationChannel, 2, "group", false); @@ -4228,7 +4350,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.addEnqueuedNotification(r); NotificationManagerService.PostNotificationRunnable runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), - r.getUid(), SystemClock.elapsedRealtime()); + r.getUid(), mPostNotificationTrackerFactory.newTracker()); runnable.run(); waitForIdle(); @@ -4247,7 +4369,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { NotificationManagerService.PostNotificationRunnable runnable = mService.new PostNotificationRunnable(update.getKey(), update.getSbn().getPackageName(), update.getUid(), - SystemClock.elapsedRealtime()); + mPostNotificationTrackerFactory.newTracker()); runnable.run(); waitForIdle(); @@ -4267,7 +4389,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { NotificationManagerService.PostNotificationRunnable runnable = mService.new PostNotificationRunnable(update.getKey(), update.getSbn().getPackageName(), update.getUid(), - SystemClock.elapsedRealtime()); + mPostNotificationTrackerFactory.newTracker()); runnable.run(); waitForIdle(); @@ -4287,7 +4409,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { NotificationManagerService.PostNotificationRunnable runnable = mService.new PostNotificationRunnable(update.getKey(), update.getSbn().getPackageName(), - update.getUid(), SystemClock.elapsedRealtime()); + update.getUid(), mPostNotificationTrackerFactory.newTracker()); runnable.run(); waitForIdle(); @@ -4301,13 +4423,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.addEnqueuedNotification(r); NotificationManagerService.PostNotificationRunnable runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), - r.getUid(), SystemClock.elapsedRealtime()); + r.getUid(), mPostNotificationTrackerFactory.newTracker()); runnable.run(); r = generateNotificationRecord(mTestNotificationChannel, 1, null, false); r.setCriticality(CriticalNotificationExtractor.CRITICAL); runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), - r.getUid(), SystemClock.elapsedRealtime()); + r.getUid(), mPostNotificationTrackerFactory.newTracker()); mService.addEnqueuedNotification(r); runnable.run(); @@ -4956,7 +5078,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.new PostNotificationRunnable(original.getKey(), original.getSbn().getPackageName(), original.getUid(), - SystemClock.elapsedRealtime()); + mPostNotificationTrackerFactory.newTracker()); runnable.run(); waitForIdle(); @@ -4980,7 +5102,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.new PostNotificationRunnable(update.getKey(), update.getSbn().getPackageName(), update.getUid(), - SystemClock.elapsedRealtime()); + mPostNotificationTrackerFactory.newTracker()); runnable.run(); waitForIdle(); @@ -7286,8 +7408,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { NotificationManagerService.PostNotificationRunnable runnable = mService.new PostNotificationRunnable(update.getKey(), r.getSbn().getPackageName(), - r.getUid(), - SystemClock.elapsedRealtime()); + r.getUid(), mPostNotificationTrackerFactory.newTracker()); runnable.run(); waitForIdle(); @@ -7595,13 +7716,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void clearDefaultDnDPackageShouldEnableIt() throws RemoteException { - ComponentName deviceConfig = new ComponentName("device", "config"); ArrayMap<Boolean, ArrayList<ComponentName>> changed = generateResetComponentValues(); when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changed); when(mListeners.resetComponents(anyString(), anyInt())).thenReturn(changed); - mService.getBinderService().clearData("device", 0, false); + mService.getBinderService().clearData("pkgName", 0, false); verify(mConditionProviders, times(1)).resetPackage( - eq("device"), eq(0)); + eq("pkgName"), eq(0)); } @Test @@ -8445,7 +8565,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals(0, notifsBefore.length); Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); - int uid = 0; // sysui on primary user mService.mNotificationDelegate.grantInlineReplyUriPermission( nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(), @@ -8578,7 +8697,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { reset(mPackageManager); Uri uri1 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); - Uri uri2 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 2); // create an inline record a uri in it mService.mNotificationDelegate.grantInlineReplyUriPermission( @@ -9982,7 +10100,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.addEnqueuedNotification(r); NotificationManagerService.PostNotificationRunnable runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), - r.getUid(), SystemClock.elapsedRealtime()); + r.getUid(), mPostNotificationTrackerFactory.newTracker()); runnable.run(); waitForIdle(); @@ -9999,7 +10117,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.addEnqueuedNotification(r); runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), - r.getUid(), SystemClock.elapsedRealtime()); + r.getUid(), mPostNotificationTrackerFactory.newTracker()); runnable.run(); waitForIdle(); @@ -10016,7 +10134,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.addEnqueuedNotification(r); runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), - r.getUid(), SystemClock.elapsedRealtime()); + r.getUid(), mPostNotificationTrackerFactory.newTracker()); runnable.run(); waitForIdle(); @@ -10108,10 +10226,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // normal blocked notifications - blocked mService.addEnqueuedNotification(r); - NotificationManagerService.PostNotificationRunnable runnable = - mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), - r.getUid(), SystemClock.elapsedRealtime()); - runnable.run(); + mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), + mPostNotificationTrackerFactory.newTracker()).run(); waitForIdle(); verify(mUsageStats).registerBlocked(any()); @@ -10128,9 +10244,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); mService.addEnqueuedNotification(r); - runnable = mService.new PostNotificationRunnable( - r.getKey(), r.getSbn().getPackageName(), r.getUid(), SystemClock.elapsedRealtime()); - runnable.run(); + mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), + mPostNotificationTrackerFactory.newTracker()).run(); waitForIdle(); verify(mUsageStats).registerBlocked(any()); @@ -10142,7 +10257,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mTelecomManager.isInManagedCall()).thenReturn(true); mService.addEnqueuedNotification(r); - runnable.run(); + mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), + mPostNotificationTrackerFactory.newTracker()).run(); waitForIdle(); verify(mUsageStats, never()).registerBlocked(any()); @@ -10155,7 +10271,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .thenReturn(true); mService.addEnqueuedNotification(r); - runnable.run(); + mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), + mPostNotificationTrackerFactory.newTracker()).run(); waitForIdle(); verify(mUsageStats, never()).registerBlocked(any()); @@ -10168,7 +10285,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.setTelecomManager(null); mService.addEnqueuedNotification(r); - runnable.run(); + mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), + mPostNotificationTrackerFactory.newTracker()).run(); waitForIdle(); verify(mUsageStats).registerBlocked(any()); @@ -10182,7 +10300,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.setTelecomManager(null); mService.addEnqueuedNotification(r); - runnable.run(); + mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), + mPostNotificationTrackerFactory.newTracker()).run(); waitForIdle(); verify(mUsageStats).registerBlocked(any()); @@ -10194,7 +10313,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { reset(mUsageStats); mService.addEnqueuedNotification(r); - runnable.run(); + mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), + mPostNotificationTrackerFactory.newTracker()).run(); waitForIdle(); verify(mUsageStats).registerBlocked(any()); @@ -10592,6 +10712,90 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void checkCallStyleNotification_withoutAnyValidUseCase_throws() throws Exception { + Person person = new Person.Builder().setName("caller").build(); + Notification n = new Notification.Builder(mContext, "test") + .setStyle(Notification.CallStyle.forOngoingCall( + person, mock(PendingIntent.class))) + .build(); + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + try { + mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), + r.getSbn().getId(), r.getSbn().getTag(), r, false); + assertFalse("CallStyle should not be allowed without a valid use case", true); + } catch (IllegalArgumentException error) { + assertThat(error.getMessage()).contains("CallStyle"); + } + } + + @Test + public void checkCallStyleNotification_allowedForFgs() throws Exception { + Person person = new Person.Builder().setName("caller").build(); + Notification n = new Notification.Builder(mContext, "test") + .setFlag(FLAG_FOREGROUND_SERVICE, true) + .setStyle(Notification.CallStyle.forOngoingCall( + person, mock(PendingIntent.class))) + .build(); + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), + r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue(); + } + + @Test + public void checkCallStyleNotification_allowedForUij() throws Exception { + Person person = new Person.Builder().setName("caller").build(); + Notification n = new Notification.Builder(mContext, "test") + .setFlag(FLAG_USER_INITIATED_JOB, true) + .setStyle(Notification.CallStyle.forOngoingCall( + person, mock(PendingIntent.class))) + .build(); + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), + r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue(); + } + + @Test + public void checkCallStyleNotification_allowedForFsiAllowed() throws Exception { + Person person = new Person.Builder().setName("caller").build(); + Notification n = new Notification.Builder(mContext, "test") + .setFullScreenIntent(mock(PendingIntent.class), true) + .setStyle(Notification.CallStyle.forOngoingCall( + person, mock(PendingIntent.class))) + .build(); + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), + r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue(); + } + + @Test + public void checkCallStyleNotification_allowedForFsiDenied() throws Exception { + Person person = new Person.Builder().setName("caller").build(); + Notification n = new Notification.Builder(mContext, "test") + .setFlag(Notification.FLAG_FSI_REQUESTED_BUT_DENIED, true) + .setStyle(Notification.CallStyle.forOngoingCall( + person, mock(PendingIntent.class))) + .build(); + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), + r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue(); + } + + @Test public void fixSystemNotification_withOnGoingFlag_shouldBeDismissible() throws Exception { final ApplicationInfo ai = new ApplicationInfo(); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java index 8a11798bbf19..1bb35021d76c 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java @@ -16,11 +16,15 @@ package com.android.server.notification; +import androidx.annotation.Nullable; + import com.android.internal.logging.InstanceId; import com.android.internal.logging.UiEventLogger; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * Fake implementation of NotificationRecordLogger, for testing. @@ -60,7 +64,8 @@ class NotificationRecordLoggerFake implements NotificationRecordLogger { this.event = event; } } - private List<CallRecord> mCalls = new ArrayList<>(); + private final List<CallRecord> mCalls = new ArrayList<>(); + private final Map<NotificationReported, CallRecord> mPendingLogs = new HashMap<>(); public int numCalls() { return mCalls.size(); @@ -70,6 +75,10 @@ class NotificationRecordLoggerFake implements NotificationRecordLogger { return mCalls; } + List<NotificationReported> getPendingLogs() { + return new ArrayList<>(mPendingLogs.keySet()); + } + CallRecord get(int index) { return mCalls.get(index); } @@ -77,10 +86,31 @@ class NotificationRecordLoggerFake implements NotificationRecordLogger { return mCalls.get(index).event; } + @Nullable + @Override + public NotificationReported prepareToLogNotificationPosted(@Nullable NotificationRecord r, + @Nullable NotificationRecord old, int position, int buzzBeepBlink, InstanceId groupId) { + NotificationReported nr = NotificationRecordLogger.super.prepareToLogNotificationPosted(r, + old, position, buzzBeepBlink, groupId); + CallRecord callRecord = new CallRecord(r, old, position, buzzBeepBlink, groupId); + callRecord.wasLogged = false; + mCalls.add(callRecord); + if (nr != null) { + mPendingLogs.put(nr, callRecord); + } + return nr; + } + @Override - public void maybeLogNotificationPosted(NotificationRecord r, NotificationRecord old, - int position, int buzzBeepBlink, InstanceId groupId) { - mCalls.add(new CallRecord(r, old, position, buzzBeepBlink, groupId)); + public void logNotificationPosted(NotificationReported nr) { + CallRecord callRecord = mPendingLogs.get(nr); + if (callRecord == null) { + throw new IllegalStateException( + "Didn't find corresponding CallRecord in mPreparedCalls. Did you call " + + "logNotificationPosted() twice!?"); + } + mPendingLogs.remove(nr); + callRecord.wasLogged = true; } @Override diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java index 34bb664c9598..d4a2e9aa4f5b 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java @@ -28,7 +28,6 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -56,7 +55,6 @@ import android.telecom.TelecomManager; import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; -import android.testing.TestableContext; import android.testing.TestableLooper.RunWithLooper; import android.util.ArraySet; import android.util.AtomicFile; @@ -64,7 +62,6 @@ import android.util.Pair; import androidx.test.InstrumentationRegistry; -import com.android.internal.app.IAppOpsService; import com.android.internal.config.sysui.TestableFlagResolver; import com.android.internal.logging.InstanceIdSequence; import com.android.internal.logging.InstanceIdSequenceFake; @@ -162,14 +159,14 @@ public class RoleObserverTest extends UiServiceTestCase { mock(UsageStatsManagerInternal.class), mock(DevicePolicyManagerInternal.class), mock(IUriGrantsManager.class), mock(UriGrantsManagerInternal.class), - mock(AppOpsManager.class), mock(IAppOpsService.class), - mUm, mock(NotificationHistoryManager.class), + mock(AppOpsManager.class), mUm, mock(NotificationHistoryManager.class), mock(StatsManager.class), mock(TelephonyManager.class), mock(ActivityManagerInternal.class), mock(MultiRateLimiter.class), mock(PermissionHelper.class), - mock(UsageStatsManagerInternal.class), mock (TelecomManager.class), + mock(UsageStatsManagerInternal.class), mock(TelecomManager.class), mock(NotificationChannelLogger.class), new TestableFlagResolver(), - mock(PermissionManager.class)); + mock(PermissionManager.class), + new NotificationManagerService.PostNotificationTrackerFactory() {}); } catch (SecurityException e) { if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) { throw e; diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index b2a54010e75e..cb41769c3619 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -55,14 +55,13 @@ import static junit.framework.TestCase.fail; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.notNull; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -149,7 +148,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Mock PackageManager mPackageManager; private Resources mResources; private TestableLooper mTestableLooper; - private ZenModeHelper mZenModeHelperSpy; + private ZenModeHelper mZenModeHelper; private ContentResolver mContentResolver; @Mock AppOpsManager mAppOps; private WrappedSysUiStatsEvent.WrappedBuilderFactory mStatsEventBuilderFactory; @@ -176,8 +175,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { mConditionProviders = new ConditionProviders(mContext, new UserProfiles(), AppGlobals.getPackageManager()); mConditionProviders.addSystemProvider(new CountdownConditionProvider()); - mZenModeHelperSpy = spy(new ZenModeHelper(mContext, mTestableLooper.getLooper(), - mConditionProviders, mStatsEventBuilderFactory)); + mZenModeHelper = new ZenModeHelper(mContext, mTestableLooper.getLooper(), + mConditionProviders, mStatsEventBuilderFactory); ResolveInfo ri = new ResolveInfo(); ri.activityInfo = new ActivityInfo(); @@ -187,7 +186,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { .thenReturn(CUSTOM_PKG_UID); when(mPackageManager.getPackagesForUid(anyInt())).thenReturn( new String[] {pkg}); - mZenModeHelperSpy.mPm = mPackageManager; + mZenModeHelper.mPm = mPackageManager; } private XmlResourceParser getDefaultConfigParser() throws IOException, XmlPullParserException { @@ -221,10 +220,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { ByteArrayOutputStream baos = new ByteArrayOutputStream(); serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); serializer.startDocument(null, true); - mZenModeHelperSpy.writeXml(serializer, false, version, UserHandle.USER_ALL); + mZenModeHelper.writeXml(serializer, false, version, UserHandle.USER_ALL); serializer.endDocument(); serializer.flush(); - mZenModeHelperSpy.setConfig(new ZenModeConfig(), null, "writing xml"); + mZenModeHelper.setConfig(new ZenModeConfig(), null, "writing xml"); return baos; } @@ -234,12 +233,12 @@ public class ZenModeHelperTest extends UiServiceTestCase { ByteArrayOutputStream baos = new ByteArrayOutputStream(); serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); serializer.startDocument(null, true); - mZenModeHelperSpy.writeXml(serializer, true, version, userId); + mZenModeHelper.writeXml(serializer, true, version, userId); serializer.endDocument(); serializer.flush(); ZenModeConfig newConfig = new ZenModeConfig(); newConfig.user = userId; - mZenModeHelperSpy.setConfig(newConfig, null, "writing xml"); + mZenModeHelper.setConfig(newConfig, null, "writing xml"); return baos; } @@ -277,209 +276,209 @@ public class ZenModeHelperTest extends UiServiceTestCase { return customRule; } + // Verify that the appropriate appOpps operations are called for the restrictions requested. + // Note that this method assumes that priority only DND exempt packages is set to something + // in order to be able to distinguish it from the null case, so callers should make sure + // setPriorityOnlyDndExemptPackages has been called bofre this verify statement. + private void verifyApplyRestrictions(boolean zenPriorityOnly, boolean mute, int usage) { + int expectedMode = mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED; + verify(mAppOps, atLeastOnce()).setRestriction(eq(AppOpsManager.OP_VIBRATE), eq(usage), + eq(expectedMode), zenPriorityOnly ? notNull() : eq(null)); + verify(mAppOps, atLeastOnce()).setRestriction(eq(AppOpsManager.OP_PLAY_AUDIO), eq(usage), + eq(expectedMode), zenPriorityOnly ? notNull() : eq(null)); + } + @Test public void testZenOff_NoMuteApplied() { - mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_OFF; - mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | - PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0); - mZenModeHelperSpy.applyRestrictions(); + mZenModeHelper.mZenMode = Settings.Global.ZEN_MODE_OFF; + mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); + mZenModeHelper.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS + | PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0); + mZenModeHelper.applyRestrictions(); - doNothing().when(mZenModeHelperSpy).applyRestrictions(eq(false), anyBoolean(), anyInt()); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, - AudioAttributes.USAGE_ALARM); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, - AudioAttributes.USAGE_MEDIA); + // Check that we call through to applyRestrictions with usages USAGE_ALARM and USAGE_MEDIA + verifyApplyRestrictions(false, false, AudioAttributes.USAGE_ALARM); + verifyApplyRestrictions(false, false, AudioAttributes.USAGE_MEDIA); } @Test public void testZenOn_NotificationApplied() { - mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); // The most permissive policy - mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | - PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES + mZenModeHelper.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS + | PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES | PRIORITY_CATEGORY_CONVERSATIONS | PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_ALARMS | PRIORITY_CATEGORY_EVENTS | PRIORITY_CATEGORY_REMINDERS | PRIORITY_CATEGORY_REPEAT_CALLERS | PRIORITY_CATEGORY_SYSTEM, PRIORITY_SENDERS_ANY, PRIORITY_SENDERS_ANY, 0, CONVERSATION_SENDERS_ANYONE); - mZenModeHelperSpy.applyRestrictions(); - - doNothing().when(mZenModeHelperSpy).applyRestrictions(anyBoolean(), anyBoolean(), anyInt()); - verify(mZenModeHelperSpy).applyRestrictions(true, true, - AudioAttributes.USAGE_NOTIFICATION); - verify(mZenModeHelperSpy).applyRestrictions(true, true, - AudioAttributes.USAGE_NOTIFICATION_EVENT); - verify(mZenModeHelperSpy).applyRestrictions(true, true, + mZenModeHelper.applyRestrictions(); + + verifyApplyRestrictions(true, true, AudioAttributes.USAGE_NOTIFICATION); + verifyApplyRestrictions(true, true, AudioAttributes.USAGE_NOTIFICATION_EVENT); + verifyApplyRestrictions(true, true, AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED); - verify(mZenModeHelperSpy).applyRestrictions(true, true, + verifyApplyRestrictions(true, true, AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT); } @Test public void testZenOn_StarredCallers_CallTypesBlocked() { - mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); // The most permissive policy - mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | - PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES + mZenModeHelper.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS + | PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES | PRIORITY_CATEGORY_CONVERSATIONS | PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_ALARMS | PRIORITY_CATEGORY_EVENTS | PRIORITY_CATEGORY_REMINDERS | PRIORITY_CATEGORY_SYSTEM, PRIORITY_SENDERS_STARRED, PRIORITY_SENDERS_ANY, 0, CONVERSATION_SENDERS_ANYONE); - mZenModeHelperSpy.applyRestrictions(); + mZenModeHelper.applyRestrictions(); - doNothing().when(mZenModeHelperSpy).applyRestrictions(anyBoolean(), anyBoolean(), anyInt()); - verify(mZenModeHelperSpy).applyRestrictions(true, true, + verifyApplyRestrictions(true, true, AudioAttributes.USAGE_NOTIFICATION_RINGTONE); - verify(mZenModeHelperSpy).applyRestrictions(true, true, + verifyApplyRestrictions(true, true, AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST); } @Test public void testZenOn_AllCallers_CallTypesAllowed() { - mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); // The most permissive policy - mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | - PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES + mZenModeHelper.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS + | PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES | PRIORITY_CATEGORY_CONVERSATIONS | PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_ALARMS | PRIORITY_CATEGORY_EVENTS | PRIORITY_CATEGORY_REMINDERS | PRIORITY_CATEGORY_REPEAT_CALLERS | PRIORITY_CATEGORY_SYSTEM, PRIORITY_SENDERS_ANY, PRIORITY_SENDERS_ANY, 0, CONVERSATION_SENDERS_ANYONE); - mZenModeHelperSpy.applyRestrictions(); + mZenModeHelper.applyRestrictions(); - doNothing().when(mZenModeHelperSpy).applyRestrictions(anyBoolean(), anyBoolean(), anyInt()); - verify(mZenModeHelperSpy).applyRestrictions(true, false, - AudioAttributes.USAGE_NOTIFICATION_RINGTONE); - verify(mZenModeHelperSpy).applyRestrictions(true, false, + verifyApplyRestrictions(true, false, AudioAttributes.USAGE_NOTIFICATION_RINGTONE); + verifyApplyRestrictions(true, false, AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST); } @Test public void testZenOn_AllowAlarmsMedia_NoAlarmMediaMuteApplied() { - mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; - mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | - PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0); + mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); + mZenModeHelper.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS + | PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0); - mZenModeHelperSpy.applyRestrictions(); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, false, - AudioAttributes.USAGE_ALARM); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, false, - AudioAttributes.USAGE_MEDIA); + mZenModeHelper.applyRestrictions(); + verifyApplyRestrictions(true, false, AudioAttributes.USAGE_ALARM); + verifyApplyRestrictions(true, false, AudioAttributes.USAGE_MEDIA); } @Test public void testZenOn_DisallowAlarmsMedia_AlarmMediaMuteApplied() { - mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; - mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); - mZenModeHelperSpy.applyRestrictions(); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true, - AudioAttributes.USAGE_ALARM); + mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); + mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); + mZenModeHelper.applyRestrictions(); + verifyApplyRestrictions(true, true, AudioAttributes.USAGE_ALARM); // Media is a catch-all that includes games - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true, - AudioAttributes.USAGE_MEDIA); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true, - AudioAttributes.USAGE_GAME); + verifyApplyRestrictions(true, true, AudioAttributes.USAGE_MEDIA); + verifyApplyRestrictions(true, true, AudioAttributes.USAGE_GAME); } @Test public void testTotalSilence() { - mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_NO_INTERRUPTIONS; - mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | - PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0); - mZenModeHelperSpy.applyRestrictions(); + mZenModeHelper.mZenMode = Settings.Global.ZEN_MODE_NO_INTERRUPTIONS; + mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); + mZenModeHelper.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS + | PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0); + mZenModeHelper.applyRestrictions(); // Total silence will silence alarms, media and system noises (but not vibrations) - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, - AudioAttributes.USAGE_ALARM); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, - AudioAttributes.USAGE_MEDIA); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, - AudioAttributes.USAGE_GAME); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, - AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.OP_PLAY_AUDIO); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, - AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.OP_VIBRATE); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, - AudioAttributes.USAGE_UNKNOWN); + verifyApplyRestrictions(false, true, AudioAttributes.USAGE_ALARM); + verifyApplyRestrictions(false, true, AudioAttributes.USAGE_MEDIA); + verifyApplyRestrictions(false, true, AudioAttributes.USAGE_GAME); + verify(mAppOps, atLeastOnce()).setRestriction(AppOpsManager.OP_PLAY_AUDIO, + AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.MODE_IGNORED, null); + verify(mAppOps, atLeastOnce()).setRestriction(AppOpsManager.OP_VIBRATE, + AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.MODE_ALLOWED, null); + verifyApplyRestrictions(false, true, AudioAttributes.USAGE_UNKNOWN); } @Test public void testAlarmsOnly_alarmMediaMuteNotApplied() { - mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_ALARMS; - mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); - mZenModeHelperSpy.applyRestrictions(); + mZenModeHelper.mZenMode = Settings.Global.ZEN_MODE_ALARMS; + mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); + mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); + mZenModeHelper.applyRestrictions(); // Alarms only mode will not silence alarms - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, - AudioAttributes.USAGE_ALARM); + verifyApplyRestrictions(false, false, AudioAttributes.USAGE_ALARM); // Alarms only mode will not silence media - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, - AudioAttributes.USAGE_MEDIA); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, - AudioAttributes.USAGE_GAME); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, - AudioAttributes.USAGE_UNKNOWN); + verifyApplyRestrictions(false, false, AudioAttributes.USAGE_MEDIA); + verifyApplyRestrictions(false, false, AudioAttributes.USAGE_GAME); + verifyApplyRestrictions(false, false, AudioAttributes.USAGE_UNKNOWN); // Alarms only will silence system noises (but not vibrations) - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, - AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.OP_PLAY_AUDIO); + verify(mAppOps, atLeastOnce()).setRestriction(AppOpsManager.OP_PLAY_AUDIO, + AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.MODE_IGNORED, null); } @Test public void testAlarmsOnly_callsMuteApplied() { - mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_ALARMS; - mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); - mZenModeHelperSpy.applyRestrictions(); + mZenModeHelper.mZenMode = Settings.Global.ZEN_MODE_ALARMS; + mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); + mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); + mZenModeHelper.applyRestrictions(); // Alarms only mode will silence calls despite priority-mode config - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, - AudioAttributes.USAGE_NOTIFICATION_RINGTONE); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, + verifyApplyRestrictions(false, true, AudioAttributes.USAGE_NOTIFICATION_RINGTONE); + verifyApplyRestrictions(false, true, AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST); } @Test public void testAlarmsOnly_allZenConfigToggledCannotBypass_alarmMuteNotApplied() { // Only audio attributes with SUPPRESIBLE_NEVER can bypass - mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_ALARMS; - mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); - mZenModeHelperSpy.applyRestrictions(); + mZenModeHelper.mZenMode = Settings.Global.ZEN_MODE_ALARMS; + mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); + mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); + mZenModeHelper.applyRestrictions(); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, - AudioAttributes.USAGE_ALARM); + verifyApplyRestrictions(false, false, AudioAttributes.USAGE_ALARM); } @Test public void testZenAllCannotBypass() { // Only audio attributes with SUPPRESIBLE_NEVER can bypass // with special case USAGE_ASSISTANCE_SONIFICATION - mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; - mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); - mZenModeHelperSpy.applyRestrictions(); + mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); + mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); + mZenModeHelper.applyRestrictions(); for (int usage : AudioAttributes.SDK_USAGES) { if (usage == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) { // only mute audio, not vibrations - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true, usage, - AppOpsManager.OP_PLAY_AUDIO); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, false, usage, - AppOpsManager.OP_VIBRATE); + verify(mAppOps, atLeastOnce()).setRestriction(eq(AppOpsManager.OP_PLAY_AUDIO), + eq(usage), eq(AppOpsManager.MODE_IGNORED), notNull()); + verify(mAppOps, atLeastOnce()).setRestriction(eq(AppOpsManager.OP_VIBRATE), + eq(usage), eq(AppOpsManager.MODE_ALLOWED), notNull()); } else { boolean shouldMute = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage) != AudioAttributes.SUPPRESSIBLE_NEVER; - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, shouldMute, usage); + verifyApplyRestrictions(true, shouldMute, usage); } } } @Test public void testApplyRestrictions_whitelist_priorityOnlyMode() { - mZenModeHelperSpy.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); - mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; - mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); - mZenModeHelperSpy.applyRestrictions(); + mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); + mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); + mZenModeHelper.applyRestrictions(); for (int usage : AudioAttributes.SDK_USAGES) { verify(mAppOps).setRestriction( @@ -491,10 +490,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test public void testApplyRestrictions_whitelist_alarmsOnlyMode() { - mZenModeHelperSpy.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); - mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_ALARMS; - mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); - mZenModeHelperSpy.applyRestrictions(); + mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); + mZenModeHelper.mZenMode = Global.ZEN_MODE_ALARMS; + mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); + mZenModeHelper.applyRestrictions(); for (int usage : AudioAttributes.SDK_USAGES) { verify(mAppOps).setRestriction( @@ -506,10 +505,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test public void testApplyRestrictions_whitelist_totalSilenceMode() { - mZenModeHelperSpy.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); - mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_NO_INTERRUPTIONS; - mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); - mZenModeHelperSpy.applyRestrictions(); + mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); + mZenModeHelper.mZenMode = Global.ZEN_MODE_NO_INTERRUPTIONS; + mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); + mZenModeHelper.applyRestrictions(); for (int usage : AudioAttributes.SDK_USAGES) { verify(mAppOps).setRestriction( @@ -533,11 +532,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { // and we're setting zen mode on Settings.Secure.putInt(mContentResolver, Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 1); Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_SETTINGS_UPDATED, 0); - mZenModeHelperSpy.mIsBootComplete = true; - mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); - mZenModeHelperSpy.setZenModeSetting(ZEN_MODE_IMPORTANT_INTERRUPTIONS); + mZenModeHelper.mIsBootComplete = true; + mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); + mZenModeHelper.setZenModeSetting(ZEN_MODE_IMPORTANT_INTERRUPTIONS); - verify(mZenModeHelperSpy, times(1)).createZenUpgradeNotification(); verify(mNotificationManager, times(1)).notify(eq(ZenModeHelper.TAG), eq(SystemMessage.NOTE_ZEN_UPGRADE), any()); assertEquals(0, Settings.Secure.getInt(mContentResolver, @@ -549,10 +547,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { // doesn't show upgrade notification if stored settings says don't show Settings.Secure.putInt(mContentResolver, Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0); Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_SETTINGS_UPDATED, 0); - mZenModeHelperSpy.mIsBootComplete = true; - mZenModeHelperSpy.setZenModeSetting(ZEN_MODE_IMPORTANT_INTERRUPTIONS); + mZenModeHelper.mIsBootComplete = true; + mZenModeHelper.setZenModeSetting(ZEN_MODE_IMPORTANT_INTERRUPTIONS); - verify(mZenModeHelperSpy, never()).createZenUpgradeNotification(); verify(mNotificationManager, never()).notify(eq(ZenModeHelper.TAG), eq(SystemMessage.NOTE_ZEN_UPGRADE), any()); } @@ -562,10 +559,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { // doesn't show upgrade notification since zen was already updated Settings.Secure.putInt(mContentResolver, Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0); Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_SETTINGS_UPDATED, 1); - mZenModeHelperSpy.mIsBootComplete = true; - mZenModeHelperSpy.setZenModeSetting(ZEN_MODE_IMPORTANT_INTERRUPTIONS); + mZenModeHelper.mIsBootComplete = true; + mZenModeHelper.setZenModeSetting(ZEN_MODE_IMPORTANT_INTERRUPTIONS); - verify(mZenModeHelperSpy, never()).createZenUpgradeNotification(); verify(mNotificationManager, never()).notify(eq(ZenModeHelper.TAG), eq(SystemMessage.NOTE_ZEN_UPGRADE), any()); } @@ -573,41 +569,41 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test public void testZenSetInternalRinger_AllPriorityNotificationSoundsMuted() { AudioManagerInternal mAudioManager = mock(AudioManagerInternal.class); - mZenModeHelperSpy.mAudioManager = mAudioManager; + mZenModeHelper.mAudioManager = mAudioManager; Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL, Integer.toString(AudioManager.RINGER_MODE_NORMAL)); // 1. Current ringer is normal when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); // Set zen to priority-only with all notification sounds muted (so ringer will be muted) - mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; - mZenModeHelperSpy.mConfig.allowReminders = false; - mZenModeHelperSpy.mConfig.allowCalls = false; - mZenModeHelperSpy.mConfig.allowMessages = false; - mZenModeHelperSpy.mConfig.allowEvents = false; - mZenModeHelperSpy.mConfig.allowRepeatCallers = false; - mZenModeHelperSpy.mConfig.allowConversations = false; + mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.mConfig.allowReminders = false; + mZenModeHelper.mConfig.allowCalls = false; + mZenModeHelper.mConfig.allowMessages = false; + mZenModeHelper.mConfig.allowEvents = false; + mZenModeHelper.mConfig.allowRepeatCallers = false; + mZenModeHelper.mConfig.allowConversations = false; // 2. apply priority only zen - verify ringer is unchanged - mZenModeHelperSpy.applyZenToRingerMode(); + mZenModeHelper.applyZenToRingerMode(); verify(mAudioManager, never()).setRingerModeInternal(AudioManager.RINGER_MODE_SILENT, - mZenModeHelperSpy.TAG); + mZenModeHelper.TAG); // 3. apply zen off - verify zen is set to previous ringer (normal) when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); - mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_OFF; - mZenModeHelperSpy.applyZenToRingerMode(); + mZenModeHelper.mZenMode = Global.ZEN_MODE_OFF; + mZenModeHelper.applyZenToRingerMode(); verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL, - mZenModeHelperSpy.TAG); + mZenModeHelper.TAG); } @Test public void testRingerAffectedStreamsTotalSilence() { // in total silence: // ringtone, notification, system, alarm, streams, music are affected by ringer mode - mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_NO_INTERRUPTIONS; + mZenModeHelper.mZenMode = Settings.Global.ZEN_MODE_NO_INTERRUPTIONS; ZenModeHelper.RingerModeDelegate ringerModeDelegate = - mZenModeHelperSpy.new RingerModeDelegate(); + mZenModeHelper.new RingerModeDelegate(); int ringerModeAffectedStreams = ringerModeDelegate.getRingerModeAffectedStreams(0); assertTrue((ringerModeAffectedStreams & (1 << AudioSystem.STREAM_RING)) != 0); assertTrue((ringerModeAffectedStreams & (1 << AudioSystem.STREAM_NOTIFICATION)) @@ -622,11 +618,11 @@ public class ZenModeHelperTest extends UiServiceTestCase { public void testRingerAffectedStreamsPriorityOnly() { // in priority only mode: // ringtone, notification and system streams are affected by ringer mode - mZenModeHelperSpy.mConfig.allowAlarms = true; - mZenModeHelperSpy.mConfig.allowReminders = true; - mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.mConfig.allowAlarms = true; + mZenModeHelper.mConfig.allowReminders = true; + mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; ZenModeHelper.RingerModeDelegate ringerModeDelegateRingerMuted = - mZenModeHelperSpy.new RingerModeDelegate(); + mZenModeHelper.new RingerModeDelegate(); int ringerModeAffectedStreams = ringerModeDelegateRingerMuted.getRingerModeAffectedStreams(0); @@ -640,15 +636,15 @@ public class ZenModeHelperTest extends UiServiceTestCase { // even when ringer is muted (since all ringer sounds cannot bypass DND), // system stream is still affected by ringer mode - mZenModeHelperSpy.mConfig.allowSystem = false; - mZenModeHelperSpy.mConfig.allowReminders = false; - mZenModeHelperSpy.mConfig.allowCalls = false; - mZenModeHelperSpy.mConfig.allowMessages = false; - mZenModeHelperSpy.mConfig.allowEvents = false; - mZenModeHelperSpy.mConfig.allowRepeatCallers = false; - mZenModeHelperSpy.mConfig.allowConversations = false; + mZenModeHelper.mConfig.allowSystem = false; + mZenModeHelper.mConfig.allowReminders = false; + mZenModeHelper.mConfig.allowCalls = false; + mZenModeHelper.mConfig.allowMessages = false; + mZenModeHelper.mConfig.allowEvents = false; + mZenModeHelper.mConfig.allowRepeatCallers = false; + mZenModeHelper.mConfig.allowConversations = false; ZenModeHelper.RingerModeDelegate ringerModeDelegateRingerNotMuted = - mZenModeHelperSpy.new RingerModeDelegate(); + mZenModeHelper.new RingerModeDelegate(); int ringerMutedRingerModeAffectedStreams = ringerModeDelegateRingerNotMuted.getRingerModeAffectedStreams(0); @@ -665,74 +661,74 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test public void testZenSetInternalRinger_NotAllPriorityNotificationSoundsMuted_StartNormal() { AudioManagerInternal mAudioManager = mock(AudioManagerInternal.class); - mZenModeHelperSpy.mAudioManager = mAudioManager; + mZenModeHelper.mAudioManager = mAudioManager; Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL, Integer.toString(AudioManager.RINGER_MODE_NORMAL)); // 1. Current ringer is normal when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); - mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; - mZenModeHelperSpy.mConfig.allowReminders = true; + mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.mConfig.allowReminders = true; // 2. apply priority only zen - verify ringer is normal - mZenModeHelperSpy.applyZenToRingerMode(); + mZenModeHelper.applyZenToRingerMode(); verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL, - mZenModeHelperSpy.TAG); + mZenModeHelper.TAG); // 3. apply zen off - verify ringer remains normal when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); - mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_OFF; - mZenModeHelperSpy.applyZenToRingerMode(); + mZenModeHelper.mZenMode = Global.ZEN_MODE_OFF; + mZenModeHelper.applyZenToRingerMode(); verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL, - mZenModeHelperSpy.TAG); + mZenModeHelper.TAG); } @Test public void testZenSetInternalRinger_NotAllPriorityNotificationSoundsMuted_StartSilent() { AudioManagerInternal mAudioManager = mock(AudioManagerInternal.class); - mZenModeHelperSpy.mAudioManager = mAudioManager; + mZenModeHelper.mAudioManager = mAudioManager; Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL, Integer.toString(AudioManager.RINGER_MODE_SILENT)); // 1. Current ringer is silent when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); - mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; - mZenModeHelperSpy.mConfig.allowReminders = true; + mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.mConfig.allowReminders = true; // 2. apply priority only zen - verify ringer is silent - mZenModeHelperSpy.applyZenToRingerMode(); + mZenModeHelper.applyZenToRingerMode(); verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_SILENT, - mZenModeHelperSpy.TAG); + mZenModeHelper.TAG); // 3. apply zen-off - verify ringer is still silent when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); - mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_OFF; - mZenModeHelperSpy.applyZenToRingerMode(); + mZenModeHelper.mZenMode = Global.ZEN_MODE_OFF; + mZenModeHelper.applyZenToRingerMode(); verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_SILENT, - mZenModeHelperSpy.TAG); + mZenModeHelper.TAG); } @Test public void testZenSetInternalRinger_NotAllPriorityNotificationSoundsMuted_RingerChanges() { AudioManagerInternal mAudioManager = mock(AudioManagerInternal.class); - mZenModeHelperSpy.mAudioManager = mAudioManager; + mZenModeHelper.mAudioManager = mAudioManager; Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL, Integer.toString(AudioManager.RINGER_MODE_NORMAL)); // 1. Current ringer is normal when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); // Set zen to priority-only with all notification sounds muted (so ringer will be muted) - mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; - mZenModeHelperSpy.mConfig.allowReminders = true; + mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.mConfig.allowReminders = true; // 2. apply priority only zen - verify zen will still be normal - mZenModeHelperSpy.applyZenToRingerMode(); + mZenModeHelper.applyZenToRingerMode(); verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL, - mZenModeHelperSpy.TAG); + mZenModeHelper.TAG); // 3. change ringer from normal to silent, verify previous ringer set to new ringer (silent) ZenModeHelper.RingerModeDelegate ringerModeDelegate = - mZenModeHelperSpy.new RingerModeDelegate(); + mZenModeHelper.new RingerModeDelegate(); ringerModeDelegate.onSetRingerModeInternal(AudioManager.RINGER_MODE_NORMAL, AudioManager.RINGER_MODE_SILENT, "test", AudioManager.RINGER_MODE_NORMAL, VolumePolicy.DEFAULT); @@ -741,41 +737,40 @@ public class ZenModeHelperTest extends UiServiceTestCase { // 4. apply zen off - verify ringer still silenced when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); - mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_OFF; - mZenModeHelperSpy.applyZenToRingerMode(); + mZenModeHelper.mZenMode = Global.ZEN_MODE_OFF; + mZenModeHelper.applyZenToRingerMode(); verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_SILENT, - mZenModeHelperSpy.TAG); + mZenModeHelper.TAG); } @Test public void testSilentRingerSavedInZenOff_startsZenOff() { AudioManagerInternal mAudioManager = mock(AudioManagerInternal.class); - mZenModeHelperSpy.mConfig = new ZenModeConfig(); - mZenModeHelperSpy.mAudioManager = mAudioManager; + mZenModeHelper.mConfig = new ZenModeConfig(); + mZenModeHelper.mAudioManager = mAudioManager; // apply zen off multiple times - verify ringer is not set to normal when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); - mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_OFF; - mZenModeHelperSpy.mConfig = null; // will evaluate config to zen mode off + mZenModeHelper.mZenMode = Global.ZEN_MODE_OFF; + mZenModeHelper.mConfig = null; // will evaluate config to zen mode off for (int i = 0; i < 3; i++) { // if zen doesn't change, zen should not reapply itself to the ringer - mZenModeHelperSpy.evaluateZenMode("test", true); + mZenModeHelper.evaluateZenMode("test", true); } - verify(mZenModeHelperSpy, never()).applyZenToRingerMode(); verify(mAudioManager, never()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL, - mZenModeHelperSpy.TAG); + mZenModeHelper.TAG); } @Test public void testSilentRingerSavedOnZenOff_startsZenOn() { AudioManagerInternal mAudioManager = mock(AudioManagerInternal.class); - mZenModeHelperSpy.mAudioManager = mAudioManager; - mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_OFF; - mZenModeHelperSpy.mConfig = new ZenModeConfig(); + mZenModeHelper.mAudioManager = mAudioManager; + mZenModeHelper.mZenMode = Global.ZEN_MODE_OFF; + mZenModeHelper.mConfig = new ZenModeConfig(); // previously set silent ringer ZenModeHelper.RingerModeDelegate ringerModeDelegate = - mZenModeHelperSpy.new RingerModeDelegate(); + mZenModeHelper.new RingerModeDelegate(); ringerModeDelegate.onSetRingerModeInternal(AudioManager.RINGER_MODE_NORMAL, AudioManager.RINGER_MODE_SILENT, "test", AudioManager.RINGER_MODE_NORMAL, VolumePolicy.DEFAULT); @@ -784,26 +779,25 @@ public class ZenModeHelperTest extends UiServiceTestCase { // apply zen off multiple times - verify ringer is not set to normal when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); - mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; for (int i = 0; i < 3; i++) { // if zen doesn't change, zen should not reapply itself to the ringer - mZenModeHelperSpy.evaluateZenMode("test", true); + mZenModeHelper.evaluateZenMode("test", true); } - verify(mZenModeHelperSpy, times(1)).applyZenToRingerMode(); verify(mAudioManager, never()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL, - mZenModeHelperSpy.TAG); + mZenModeHelper.TAG); } @Test public void testVibrateRingerSavedOnZenOff_startsZenOn() { AudioManagerInternal mAudioManager = mock(AudioManagerInternal.class); - mZenModeHelperSpy.mAudioManager = mAudioManager; - mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_OFF; - mZenModeHelperSpy.mConfig = new ZenModeConfig(); + mZenModeHelper.mAudioManager = mAudioManager; + mZenModeHelper.mZenMode = Global.ZEN_MODE_OFF; + mZenModeHelper.mConfig = new ZenModeConfig(); // previously set silent ringer ZenModeHelper.RingerModeDelegate ringerModeDelegate = - mZenModeHelperSpy.new RingerModeDelegate(); + mZenModeHelper.new RingerModeDelegate(); ringerModeDelegate.onSetRingerModeInternal(AudioManager.RINGER_MODE_NORMAL, AudioManager.RINGER_MODE_VIBRATE, "test", AudioManager.RINGER_MODE_NORMAL, VolumePolicy.DEFAULT); @@ -812,89 +806,88 @@ public class ZenModeHelperTest extends UiServiceTestCase { // apply zen off multiple times - verify ringer is not set to normal when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE); - mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; for (int i = 0; i < 3; i++) { // if zen doesn't change, zen should not reapply itself to the ringer - mZenModeHelperSpy.evaluateZenMode("test", true); + mZenModeHelper.evaluateZenMode("test", true); } - verify(mZenModeHelperSpy, times(1)).applyZenToRingerMode(); verify(mAudioManager, never()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL, - mZenModeHelperSpy.TAG); + mZenModeHelper.TAG); } @Test public void testParcelConfig() { - mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; - mZenModeHelperSpy.mConfig.allowAlarms = false; - mZenModeHelperSpy.mConfig.allowMedia = false; - mZenModeHelperSpy.mConfig.allowSystem = false; - mZenModeHelperSpy.mConfig.allowReminders = true; - mZenModeHelperSpy.mConfig.allowCalls = true; - mZenModeHelperSpy.mConfig.allowMessages = true; - mZenModeHelperSpy.mConfig.allowEvents = true; - mZenModeHelperSpy.mConfig.allowRepeatCallers = true; - mZenModeHelperSpy.mConfig.allowConversations = true; - mZenModeHelperSpy.mConfig.allowConversationsFrom = ZenPolicy.CONVERSATION_SENDERS_ANYONE; - mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE; - mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule(); - mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("a", "a"); - mZenModeHelperSpy.mConfig.manualRule.enabled = true; - mZenModeHelperSpy.mConfig.manualRule.snoozing = true; - - ZenModeConfig actual = mZenModeHelperSpy.mConfig.copy(); - - assertEquals(mZenModeHelperSpy.mConfig, actual); + mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.mConfig.allowAlarms = false; + mZenModeHelper.mConfig.allowMedia = false; + mZenModeHelper.mConfig.allowSystem = false; + mZenModeHelper.mConfig.allowReminders = true; + mZenModeHelper.mConfig.allowCalls = true; + mZenModeHelper.mConfig.allowMessages = true; + mZenModeHelper.mConfig.allowEvents = true; + mZenModeHelper.mConfig.allowRepeatCallers = true; + mZenModeHelper.mConfig.allowConversations = true; + mZenModeHelper.mConfig.allowConversationsFrom = ZenPolicy.CONVERSATION_SENDERS_ANYONE; + mZenModeHelper.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE; + mZenModeHelper.mConfig.manualRule = new ZenModeConfig.ZenRule(); + mZenModeHelper.mConfig.manualRule.component = new ComponentName("a", "a"); + mZenModeHelper.mConfig.manualRule.enabled = true; + mZenModeHelper.mConfig.manualRule.snoozing = true; + + ZenModeConfig actual = mZenModeHelper.mConfig.copy(); + + assertEquals(mZenModeHelper.mConfig, actual); } @Test public void testWriteXml() throws Exception { - mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; - mZenModeHelperSpy.mConfig.allowAlarms = false; - mZenModeHelperSpy.mConfig.allowMedia = false; - mZenModeHelperSpy.mConfig.allowSystem = false; - mZenModeHelperSpy.mConfig.allowReminders = true; - mZenModeHelperSpy.mConfig.allowCalls = true; - mZenModeHelperSpy.mConfig.allowMessages = true; - mZenModeHelperSpy.mConfig.allowEvents = true; - mZenModeHelperSpy.mConfig.allowRepeatCallers = true; - mZenModeHelperSpy.mConfig.allowConversations = true; - mZenModeHelperSpy.mConfig.allowConversationsFrom = ZenPolicy.CONVERSATION_SENDERS_ANYONE; - mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE; - mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule(); - mZenModeHelperSpy.mConfig.manualRule.zenMode = + mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.mConfig.allowAlarms = false; + mZenModeHelper.mConfig.allowMedia = false; + mZenModeHelper.mConfig.allowSystem = false; + mZenModeHelper.mConfig.allowReminders = true; + mZenModeHelper.mConfig.allowCalls = true; + mZenModeHelper.mConfig.allowMessages = true; + mZenModeHelper.mConfig.allowEvents = true; + mZenModeHelper.mConfig.allowRepeatCallers = true; + mZenModeHelper.mConfig.allowConversations = true; + mZenModeHelper.mConfig.allowConversationsFrom = ZenPolicy.CONVERSATION_SENDERS_ANYONE; + mZenModeHelper.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE; + mZenModeHelper.mConfig.manualRule = new ZenModeConfig.ZenRule(); + mZenModeHelper.mConfig.manualRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; - mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("a", "a"); - mZenModeHelperSpy.mConfig.manualRule.pkg = "a"; - mZenModeHelperSpy.mConfig.manualRule.enabled = true; + mZenModeHelper.mConfig.manualRule.component = new ComponentName("a", "a"); + mZenModeHelper.mConfig.manualRule.pkg = "a"; + mZenModeHelper.mConfig.manualRule.enabled = true; - ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy(); + ZenModeConfig expected = mZenModeHelper.mConfig.copy(); ByteArrayOutputStream baos = writeXmlAndPurge(null); TypedXmlPullParser parser = getParserForByteStream(baos); - mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL); + mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL); assertEquals("Config mismatch: current vs expected: " - + new ZenModeDiff.ConfigDiff(mZenModeHelperSpy.mConfig, expected), expected, - mZenModeHelperSpy.mConfig); + + new ZenModeDiff.ConfigDiff(mZenModeHelper.mConfig, expected), expected, + mZenModeHelper.mConfig); } @Test public void testProto() { - mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; // existence of manual rule means it should be in output - mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule(); - mZenModeHelperSpy.mConfig.manualRule.pkg = "android"; // system + mZenModeHelper.mConfig.manualRule = new ZenModeConfig.ZenRule(); + mZenModeHelper.mConfig.manualRule.pkg = "android"; // system - int n = mZenModeHelperSpy.mConfig.automaticRules.size(); + int n = mZenModeHelper.mConfig.automaticRules.size(); List<String> ids = new ArrayList<>(n); - for (ZenModeConfig.ZenRule rule : mZenModeHelperSpy.mConfig.automaticRules.values()) { + for (ZenModeConfig.ZenRule rule : mZenModeHelper.mConfig.automaticRules.values()) { ids.add(rule.id); } ids.add(ZenModeConfig.MANUAL_RULE_ID); ids.add(""); // for ROOT_CONFIG, logged with empty string as id List<StatsEvent> events = new LinkedList<>(); - mZenModeHelperSpy.pullRules(events); + mZenModeHelper.pullRules(events); assertEquals(n + 2, events.size()); // automatic rules + manual rule + root config for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) { if (builder.getAtomId() == DND_MODE_RULE) { @@ -918,10 +911,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { public void testProtoWithAutoRule() throws Exception { setupZenConfig(); // one enabled automatic rule - mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules(ZEN_MODE_FOR_TESTING); + mZenModeHelper.mConfig.automaticRules = getCustomAutomaticRules(ZEN_MODE_FOR_TESTING); List<StatsEvent> events = new LinkedList<>(); - mZenModeHelperSpy.pullRules(events); + mZenModeHelper.pullRules(events); boolean foundCustomEvent = false; for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) { @@ -942,23 +935,23 @@ public class ZenModeHelperTest extends UiServiceTestCase { public void ruleUidsCached() throws Exception { setupZenConfig(); // one enabled automatic rule - mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules(); + mZenModeHelper.mConfig.automaticRules = getCustomAutomaticRules(); List<StatsEvent> events = new LinkedList<>(); // first time retrieving uid: - mZenModeHelperSpy.pullRules(events); + mZenModeHelper.pullRules(events); verify(mPackageManager, atLeastOnce()).getPackageUidAsUser(anyString(), anyInt()); // second time retrieving uid: reset(mPackageManager); - mZenModeHelperSpy.pullRules(events); + mZenModeHelper.pullRules(events); verify(mPackageManager, never()).getPackageUidAsUser(anyString(), anyInt()); // new rule from same package + user added reset(mPackageManager); ZenModeConfig.ZenRule rule = createCustomAutomaticRule(ZEN_MODE_IMPORTANT_INTERRUPTIONS, CUSTOM_RULE_ID + "2"); - mZenModeHelperSpy.mConfig.automaticRules.put(rule.id, rule); - mZenModeHelperSpy.pullRules(events); + mZenModeHelper.mConfig.automaticRules.put(rule.id, rule); + mZenModeHelper.pullRules(events); verify(mPackageManager, never()).getPackageUidAsUser(anyString(), anyInt()); } @@ -969,23 +962,23 @@ public class ZenModeHelperTest extends UiServiceTestCase { setupZenConfig(); // one enabled automatic rule - mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules(); + mZenModeHelper.mConfig.automaticRules = getCustomAutomaticRules(); List<StatsEvent> events = new LinkedList<>(); - mZenModeHelperSpy.pullRules(events); - mZenModeHelperSpy.removeAutomaticZenRule(CUSTOM_RULE_ID, "test"); + mZenModeHelper.pullRules(events); + mZenModeHelper.removeAutomaticZenRule(CUSTOM_RULE_ID, "test"); assertTrue(-1 - == mZenModeHelperSpy.mRulesUidCache.getOrDefault(CUSTOM_PKG_NAME + "|" + 0, -1)); + == mZenModeHelper.mRulesUidCache.getOrDefault(CUSTOM_PKG_NAME + "|" + 0, -1)); } @Test public void testProtoRedactsIds() throws Exception { setupZenConfig(); // one enabled automatic rule - mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules(); + mZenModeHelper.mConfig.automaticRules = getCustomAutomaticRules(); List<StatsEvent> events = new LinkedList<>(); - mZenModeHelperSpy.pullRules(events); + mZenModeHelper.pullRules(events); boolean foundCustomEvent = false; for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) { @@ -999,12 +992,12 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test public void testProtoWithManualRule() throws Exception { setupZenConfig(); - mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules(); - mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule(); - mZenModeHelperSpy.mConfig.manualRule.enabled = true; + mZenModeHelper.mConfig.automaticRules = getCustomAutomaticRules(); + mZenModeHelper.mConfig.manualRule = new ZenModeConfig.ZenRule(); + mZenModeHelper.mConfig.manualRule.enabled = true; List<StatsEvent> events = new LinkedList<>(); - mZenModeHelperSpy.pullRules(events); + mZenModeHelper.pullRules(events); boolean foundManualRule = false; for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) { @@ -1020,50 +1013,50 @@ public class ZenModeHelperTest extends UiServiceTestCase { public void testWriteXml_onlyBackupsTargetUser() throws Exception { // Setup configs for user 10 and 11. setupZenConfig(); - ZenModeConfig config10 = mZenModeHelperSpy.mConfig.copy(); + ZenModeConfig config10 = mZenModeHelper.mConfig.copy(); config10.user = 10; config10.allowAlarms = true; config10.allowMedia = true; - mZenModeHelperSpy.setConfig(config10, null, "writeXml"); - ZenModeConfig config11 = mZenModeHelperSpy.mConfig.copy(); + mZenModeHelper.setConfig(config10, null, "writeXml"); + ZenModeConfig config11 = mZenModeHelper.mConfig.copy(); config11.user = 11; config11.allowAlarms = false; config11.allowMedia = false; - mZenModeHelperSpy.setConfig(config11, null, "writeXml"); + mZenModeHelper.setConfig(config11, null, "writeXml"); // Backup user 10 and reset values. ByteArrayOutputStream baos = writeXmlAndPurgeForUser(null, 10); ZenModeConfig newConfig11 = new ZenModeConfig(); newConfig11.user = 11; - mZenModeHelperSpy.mConfigs.put(11, newConfig11); + mZenModeHelper.mConfigs.put(11, newConfig11); // Parse backup data. TypedXmlPullParser parser = getParserForByteStream(baos); - mZenModeHelperSpy.readXml(parser, true, 10); - mZenModeHelperSpy.readXml(parser, true, 11); + mZenModeHelper.readXml(parser, true, 10); + mZenModeHelper.readXml(parser, true, 11); - ZenModeConfig actual = mZenModeHelperSpy.mConfigs.get(10); + ZenModeConfig actual = mZenModeHelper.mConfigs.get(10); assertEquals( "Config mismatch: current vs expected: " + new ZenModeDiff.ConfigDiff(actual, config10), config10, actual); - assertNotEquals("Expected config mismatch", config11, mZenModeHelperSpy.mConfigs.get(11)); + assertNotEquals("Expected config mismatch", config11, mZenModeHelper.mConfigs.get(11)); } @Test public void testReadXmlRestore_forSystemUser() throws Exception { setupZenConfig(); // one enabled automatic rule - mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules(); - ZenModeConfig original = mZenModeHelperSpy.mConfig.copy(); + mZenModeHelper.mConfig.automaticRules = getCustomAutomaticRules(); + ZenModeConfig original = mZenModeHelper.mConfig.copy(); ByteArrayOutputStream baos = writeXmlAndPurgeForUser(null, UserHandle.USER_SYSTEM); TypedXmlPullParser parser = getParserForByteStream(baos); - mZenModeHelperSpy.readXml(parser, true, UserHandle.USER_SYSTEM); + mZenModeHelper.readXml(parser, true, UserHandle.USER_SYSTEM); assertEquals("Config mismatch: current vs original: " - + new ZenModeDiff.ConfigDiff(mZenModeHelperSpy.mConfig, original), - original, mZenModeHelperSpy.mConfig); - assertEquals(original.hashCode(), mZenModeHelperSpy.mConfig.hashCode()); + + new ZenModeDiff.ConfigDiff(mZenModeHelper.mConfig, original), + original, mZenModeHelper.mConfig); + assertEquals(original.hashCode(), mZenModeHelper.mConfig.hashCode()); } /** Restore should ignore the data's user id and restore for the target user. */ @@ -1071,24 +1064,24 @@ public class ZenModeHelperTest extends UiServiceTestCase { public void testReadXmlRestore_forNonSystemUser() throws Exception { // Setup config. setupZenConfig(); - mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules(); - ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy(); + mZenModeHelper.mConfig.automaticRules = getCustomAutomaticRules(); + ZenModeConfig expected = mZenModeHelper.mConfig.copy(); // Backup data for user 0. ByteArrayOutputStream baos = writeXmlAndPurgeForUser(null, UserHandle.USER_SYSTEM); // Restore data for user 10. TypedXmlPullParser parser = getParserForByteStream(baos); - mZenModeHelperSpy.readXml(parser, true, 10); + mZenModeHelper.readXml(parser, true, 10); - ZenModeConfig actual = mZenModeHelperSpy.mConfigs.get(10); + ZenModeConfig actual = mZenModeHelper.mConfigs.get(10); expected.user = 10; assertEquals("Config mismatch: current vs original: " + new ZenModeDiff.ConfigDiff(actual, expected), expected, actual); assertEquals(expected.hashCode(), actual.hashCode()); expected.user = 0; - assertNotEquals(expected, mZenModeHelperSpy.mConfig); + assertNotEquals(expected, mZenModeHelper.mConfig); } @Test @@ -1119,19 +1112,19 @@ public class ZenModeHelperTest extends UiServiceTestCase { .allowReminders(false) .build(); automaticRules.put("customRule", customRule); - mZenModeHelperSpy.mConfig.automaticRules = automaticRules; + mZenModeHelper.mConfig.automaticRules = automaticRules; - ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy(); + ZenModeConfig expected = mZenModeHelper.mConfig.copy(); ByteArrayOutputStream baos = writeXmlAndPurge(null); TypedXmlPullParser parser = Xml.newFastPullParser(); parser.setInput(new BufferedInputStream( new ByteArrayInputStream(baos.toByteArray())), null); parser.nextTag(); - mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL); + mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL); ZenModeConfig.ZenRule original = expected.automaticRules.get(ruleId); - ZenModeConfig.ZenRule current = mZenModeHelperSpy.mConfig.automaticRules.get(ruleId); + ZenModeConfig.ZenRule current = mZenModeHelper.mConfig.automaticRules.get(ruleId); assertEquals("Automatic rules mismatch", original, current); } @@ -1160,16 +1153,16 @@ public class ZenModeHelperTest extends UiServiceTestCase { .allowReminders(true) .build(); automaticRules.put(ruleId, customRule); - mZenModeHelperSpy.mConfig.automaticRules = automaticRules; + mZenModeHelper.mConfig.automaticRules = automaticRules; - ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy(); + ZenModeConfig expected = mZenModeHelper.mConfig.copy(); ByteArrayOutputStream baos = writeXmlAndPurgeForUser(null, UserHandle.USER_SYSTEM); TypedXmlPullParser parser = getParserForByteStream(baos); - mZenModeHelperSpy.readXml(parser, true, UserHandle.USER_SYSTEM); + mZenModeHelper.readXml(parser, true, UserHandle.USER_SYSTEM); ZenModeConfig.ZenRule original = expected.automaticRules.get(ruleId); - ZenModeConfig.ZenRule current = mZenModeHelperSpy.mConfig.automaticRules.get(ruleId); + ZenModeConfig.ZenRule current = mZenModeHelper.mConfig.automaticRules.get(ruleId); assertEquals("Automatic rules mismatch", original, current); } @@ -1188,7 +1181,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { customRule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights); customRule.component = new ComponentName("android", "ScheduleConditionProvider"); enabledAutoRule.put("customRule", customRule); - mZenModeHelperSpy.mConfig.automaticRules = enabledAutoRule; + mZenModeHelper.mConfig.automaticRules = enabledAutoRule; // set previous version ByteArrayOutputStream baos = writeXmlAndPurge(5); @@ -1196,9 +1189,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { parser.setInput(new BufferedInputStream( new ByteArrayInputStream(baos.toByteArray())), null); parser.nextTag(); - mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL); + mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL); - assertTrue(mZenModeHelperSpy.mConfig.automaticRules.containsKey("customRule")); + assertTrue(mZenModeHelper.mConfig.automaticRules.containsKey("customRule")); setupZenConfigMaintained(); } @@ -1216,9 +1209,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { parser.setInput(new BufferedInputStream( new ByteArrayInputStream(xml.getBytes())), null); parser.nextTag(); - mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL); + mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL); - assertEquals(0, mZenModeHelperSpy.mConfig.suppressedVisualEffects); + assertEquals(0, mZenModeHelper.mConfig.suppressedVisualEffects); xml = "<zen version=\"6\" user=\"0\">\n" + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" " @@ -1232,9 +1225,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { parser.setInput(new BufferedInputStream( new ByteArrayInputStream(xml.getBytes())), null); parser.nextTag(); - mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL); + mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL); - assertEquals(0, mZenModeHelperSpy.mConfig.suppressedVisualEffects); + assertEquals(0, mZenModeHelper.mConfig.suppressedVisualEffects); } @Test @@ -1251,9 +1244,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { parser.setInput(new BufferedInputStream( new ByteArrayInputStream(xml.getBytes())), null); parser.nextTag(); - mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL); + mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL); - assertEquals(0, mZenModeHelperSpy.mConfig.suppressedVisualEffects); + assertEquals(0, mZenModeHelper.mConfig.suppressedVisualEffects); } @Test @@ -1270,13 +1263,13 @@ public class ZenModeHelperTest extends UiServiceTestCase { parser.setInput(new BufferedInputStream( new ByteArrayInputStream(xml.getBytes())), null); parser.nextTag(); - mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL); + mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL); assertEquals(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_AMBIENT | SUPPRESSED_EFFECT_PEEK, - mZenModeHelperSpy.mConfig.suppressedVisualEffects); + mZenModeHelper.mConfig.suppressedVisualEffects); xml = "<zen version=\"6\" user=\"0\">\n" + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" " @@ -1290,9 +1283,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { parser.setInput(new BufferedInputStream( new ByteArrayInputStream(xml.getBytes())), null); parser.nextTag(); - mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL); + mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL); - assertEquals(SUPPRESSED_EFFECT_PEEK, mZenModeHelperSpy.mConfig.suppressedVisualEffects); + assertEquals(SUPPRESSED_EFFECT_PEEK, mZenModeHelper.mConfig.suppressedVisualEffects); xml = "<zen version=\"6\" user=\"0\">\n" + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" " @@ -1306,12 +1299,12 @@ public class ZenModeHelperTest extends UiServiceTestCase { parser.setInput(new BufferedInputStream( new ByteArrayInputStream(xml.getBytes())), null); parser.nextTag(); - mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL); + mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL); assertEquals(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_AMBIENT, - mZenModeHelperSpy.mConfig.suppressedVisualEffects); + mZenModeHelper.mConfig.suppressedVisualEffects); } @Test @@ -1320,7 +1313,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { // no enabled automatic zen rules and no default rules // so rules should be overriden by default rules - mZenModeHelperSpy.mConfig.automaticRules = new ArrayMap<>(); + mZenModeHelper.mConfig.automaticRules = new ArrayMap<>(); // set previous version ByteArrayOutputStream baos = writeXmlAndPurge(5); @@ -1328,10 +1321,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { parser.setInput(new BufferedInputStream( new ByteArrayInputStream(baos.toByteArray())), null); parser.nextTag(); - mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL); + mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL); // check default rules - ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelperSpy.mConfig.automaticRules; + ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelper.mConfig.automaticRules; assertTrue(rules.size() != 0); for (String defaultId : ZenModeConfig.DEFAULT_RULE_IDS) { assertTrue(rules.containsKey(defaultId)); @@ -1356,7 +1349,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { customRule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights); customRule.component = new ComponentName("android", "ScheduleConditionProvider"); disabledAutoRule.put("customRule", customRule); - mZenModeHelperSpy.mConfig.automaticRules = disabledAutoRule; + mZenModeHelper.mConfig.automaticRules = disabledAutoRule; // set previous version ByteArrayOutputStream baos = writeXmlAndPurge(5); @@ -1364,10 +1357,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { parser.setInput(new BufferedInputStream( new ByteArrayInputStream(baos.toByteArray())), null); parser.nextTag(); - mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL); + mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL); // check default rules - ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelperSpy.mConfig.automaticRules; + ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelper.mConfig.automaticRules; assertTrue(rules.size() != 0); for (String defaultId : ZenModeConfig.DEFAULT_RULE_IDS) { assertTrue(rules.containsKey(defaultId)); @@ -1408,7 +1401,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { defaultScheduleRule.id = ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID; automaticRules.put(ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID, defaultScheduleRule); - mZenModeHelperSpy.mConfig.automaticRules = automaticRules; + mZenModeHelper.mConfig.automaticRules = automaticRules; // set previous version ByteArrayOutputStream baos = writeXmlAndPurge(5); @@ -1416,10 +1409,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { parser.setInput(new BufferedInputStream( new ByteArrayInputStream(baos.toByteArray())), null); parser.nextTag(); - mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL); + mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL); // check default rules - ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelperSpy.mConfig.automaticRules; + ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelper.mConfig.automaticRules; assertTrue(rules.size() != 0); for (String defaultId : ZenModeConfig.DEFAULT_RULE_IDS) { assertTrue(rules.containsKey(defaultId)); @@ -1477,7 +1470,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { .build(); automaticRules.put(ZenModeConfig.EVENTS_DEFAULT_RULE_ID, defaultEventRule); - mZenModeHelperSpy.mConfig.automaticRules = automaticRules; + mZenModeHelper.mConfig.automaticRules = automaticRules; // set previous version ByteArrayOutputStream baos = writeXmlAndPurge(5); @@ -1485,10 +1478,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { parser.setInput(new BufferedInputStream( new ByteArrayInputStream(baos.toByteArray())), null); parser.nextTag(); - mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL); + mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL); // check default rules - ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelperSpy.mConfig.automaticRules; + ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelper.mConfig.automaticRules; assertTrue(rules.size() != 0); for (String defaultId : ZenModeConfig.DEFAULT_RULE_IDS) { assertTrue(rules.containsKey(defaultId)); @@ -1498,32 +1491,32 @@ public class ZenModeHelperTest extends UiServiceTestCase { setupZenConfigMaintained(); List<StatsEvent> events = new LinkedList<>(); - mZenModeHelperSpy.pullRules(events); + mZenModeHelper.pullRules(events); assertEquals(4, events.size()); } @Test public void testCountdownConditionSubscription() throws Exception { ZenModeConfig config = new ZenModeConfig(); - mZenModeHelperSpy.mConfig = config; - mZenModeHelperSpy.mConditions.evaluateConfig(mZenModeHelperSpy.mConfig, null, true); - assertEquals(0, mZenModeHelperSpy.mConditions.mSubscriptions.size()); + mZenModeHelper.mConfig = config; + mZenModeHelper.mConditions.evaluateConfig(mZenModeHelper.mConfig, null, true); + assertEquals(0, mZenModeHelper.mConditions.mSubscriptions.size()); - mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule(); + mZenModeHelper.mConfig.manualRule = new ZenModeConfig.ZenRule(); Uri conditionId = ZenModeConfig.toCountdownConditionId(9000000, false); - mZenModeHelperSpy.mConfig.manualRule.conditionId = conditionId; - mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("android", + mZenModeHelper.mConfig.manualRule.conditionId = conditionId; + mZenModeHelper.mConfig.manualRule.component = new ComponentName("android", CountdownConditionProvider.class.getName()); - mZenModeHelperSpy.mConfig.manualRule.condition = new Condition(conditionId, "", "", "", 0, + mZenModeHelper.mConfig.manualRule.condition = new Condition(conditionId, "", "", "", 0, STATE_TRUE, Condition.FLAG_RELEVANT_NOW); - mZenModeHelperSpy.mConfig.manualRule.enabled = true; - ZenModeConfig originalConfig = mZenModeHelperSpy.mConfig.copy(); + mZenModeHelper.mConfig.manualRule.enabled = true; + ZenModeConfig originalConfig = mZenModeHelper.mConfig.copy(); - mZenModeHelperSpy.mConditions.evaluateConfig(mZenModeHelperSpy.mConfig, null, true); + mZenModeHelper.mConditions.evaluateConfig(mZenModeHelper.mConfig, null, true); assertEquals(true, ZenModeConfig.isValidCountdownConditionId(conditionId)); - assertEquals(originalConfig, mZenModeHelperSpy.mConfig); - assertEquals(1, mZenModeHelperSpy.mConditions.mSubscriptions.size()); + assertEquals(originalConfig, mZenModeHelper.mConfig); + assertEquals(1, mZenModeHelper.mConditions.mSubscriptions.size()); } @Test @@ -1531,9 +1524,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { List<StatsEvent> events = new LinkedList<>(); ZenModeConfig config = new ZenModeConfig(); config.automaticRules = new ArrayMap<>(); - mZenModeHelperSpy.mConfig = config; - mZenModeHelperSpy.updateDefaultZenRules(); // shouldn't throw null pointer - mZenModeHelperSpy.pullRules(events); // shouldn't throw null pointer + mZenModeHelper.mConfig = config; + mZenModeHelper.updateDefaultZenRules(); // shouldn't throw null pointer + mZenModeHelper.pullRules(events); // shouldn't throw null pointer } @Test @@ -1555,11 +1548,11 @@ public class ZenModeHelperTest extends UiServiceTestCase { ArrayMap<String, ZenModeConfig.ZenRule> autoRules = new ArrayMap<>(); autoRules.put(SCHEDULE_DEFAULT_RULE_ID, updatedDefaultRule); - mZenModeHelperSpy.mConfig.automaticRules = autoRules; + mZenModeHelper.mConfig.automaticRules = autoRules; - mZenModeHelperSpy.updateDefaultZenRules(); + mZenModeHelper.updateDefaultZenRules(); assertEquals(updatedDefaultRule, - mZenModeHelperSpy.mConfig.automaticRules.get(SCHEDULE_DEFAULT_RULE_ID)); + mZenModeHelper.mConfig.automaticRules.get(SCHEDULE_DEFAULT_RULE_ID)); } @Test @@ -1581,11 +1574,11 @@ public class ZenModeHelperTest extends UiServiceTestCase { ArrayMap<String, ZenModeConfig.ZenRule> autoRules = new ArrayMap<>(); autoRules.put(SCHEDULE_DEFAULT_RULE_ID, updatedDefaultRule); - mZenModeHelperSpy.mConfig.automaticRules = autoRules; + mZenModeHelper.mConfig.automaticRules = autoRules; - mZenModeHelperSpy.updateDefaultZenRules(); + mZenModeHelper.updateDefaultZenRules(); assertEquals(updatedDefaultRule, - mZenModeHelperSpy.mConfig.automaticRules.get(SCHEDULE_DEFAULT_RULE_ID)); + mZenModeHelper.mConfig.automaticRules.get(SCHEDULE_DEFAULT_RULE_ID)); } @Test @@ -1608,11 +1601,11 @@ public class ZenModeHelperTest extends UiServiceTestCase { ArrayMap<String, ZenModeConfig.ZenRule> autoRules = new ArrayMap<>(); autoRules.put(SCHEDULE_DEFAULT_RULE_ID, customDefaultRule); - mZenModeHelperSpy.mConfig.automaticRules = autoRules; + mZenModeHelper.mConfig.automaticRules = autoRules; - mZenModeHelperSpy.updateDefaultZenRules(); + mZenModeHelper.updateDefaultZenRules(); ZenModeConfig.ZenRule ruleAfterUpdating = - mZenModeHelperSpy.mConfig.automaticRules.get(SCHEDULE_DEFAULT_RULE_ID); + mZenModeHelper.mConfig.automaticRules.get(SCHEDULE_DEFAULT_RULE_ID); assertEquals(customDefaultRule.enabled, ruleAfterUpdating.enabled); assertEquals(customDefaultRule.modified, ruleAfterUpdating.modified); assertEquals(customDefaultRule.id, ruleAfterUpdating.id); @@ -1633,7 +1626,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); // We need the package name to be something that's not "android" so there aren't any // existing rules under that package. - String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test"); assertNotNull(id); } try { @@ -1643,7 +1636,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test"); fail("allowed too many rules to be created"); } catch (IllegalArgumentException e) { // yay @@ -1663,7 +1656,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig.toScheduleConditionId(si), new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test"); assertNotNull(id); } try { @@ -1673,7 +1666,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test"); fail("allowed too many rules to be created"); } catch (IllegalArgumentException e) { // yay @@ -1693,7 +1686,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig.toScheduleConditionId(si), new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test"); assertNotNull(id); } try { @@ -1703,7 +1696,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test"); fail("allowed too many rules to be created"); } catch (IllegalArgumentException e) { // yay @@ -1718,10 +1711,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule("android", zenRule, "test"); assertTrue(id != null); - ZenModeConfig.ZenRule ruleInConfig = mZenModeHelperSpy.mConfig.automaticRules.get(id); + ZenModeConfig.ZenRule ruleInConfig = mZenModeHelper.mConfig.automaticRules.get(id); assertTrue(ruleInConfig != null); assertEquals(zenRule.isEnabled(), ruleInConfig.enabled); assertEquals(zenRule.isModified(), ruleInConfig.modified); @@ -1738,10 +1731,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { new ComponentName("android", "ScheduleConditionProvider"), ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule("android", zenRule, "test"); assertTrue(id != null); - ZenModeConfig.ZenRule ruleInConfig = mZenModeHelperSpy.mConfig.automaticRules.get(id); + ZenModeConfig.ZenRule ruleInConfig = mZenModeHelper.mConfig.automaticRules.get(id); assertTrue(ruleInConfig != null); assertEquals(zenRule.isEnabled(), ruleInConfig.enabled); assertEquals(zenRule.isModified(), ruleInConfig.modified); @@ -1761,11 +1754,11 @@ public class ZenModeHelperTest extends UiServiceTestCase { new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelperSpy.addAutomaticZenRule(null, zenRule, "test"); - mZenModeHelperSpy.setAutomaticZenRuleState(zenRule.getConditionId(), + String id = mZenModeHelper.addAutomaticZenRule(null, zenRule, "test"); + mZenModeHelper.setAutomaticZenRuleState(zenRule.getConditionId(), new Condition(zenRule.getConditionId(), "", STATE_TRUE)); - ZenModeConfig.ZenRule ruleInConfig = mZenModeHelperSpy.mConfig.automaticRules.get(id); + ZenModeConfig.ZenRule ruleInConfig = mZenModeHelper.mConfig.automaticRules.get(id); assertEquals(STATE_TRUE, ruleInConfig.condition.state); } @@ -1778,7 +1771,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelperSpy.addAutomaticZenRule(null, zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule(null, zenRule, "test"); AutomaticZenRule zenRule2 = new AutomaticZenRule("NEW", null, @@ -1787,9 +1780,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - mZenModeHelperSpy.updateAutomaticZenRule(id, zenRule2, ""); + mZenModeHelper.updateAutomaticZenRule(id, zenRule2, ""); - ZenModeConfig.ZenRule ruleInConfig = mZenModeHelperSpy.mConfig.automaticRules.get(id); + ZenModeConfig.ZenRule ruleInConfig = mZenModeHelper.mConfig.automaticRules.get(id); assertEquals("NEW", ruleInConfig.name); } @@ -1802,15 +1795,15 @@ public class ZenModeHelperTest extends UiServiceTestCase { new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelperSpy.addAutomaticZenRule(null, zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule(null, zenRule, "test"); assertTrue(id != null); - ZenModeConfig.ZenRule ruleInConfig = mZenModeHelperSpy.mConfig.automaticRules.get(id); + ZenModeConfig.ZenRule ruleInConfig = mZenModeHelper.mConfig.automaticRules.get(id); assertTrue(ruleInConfig != null); assertEquals(zenRule.getName(), ruleInConfig.name); - mZenModeHelperSpy.removeAutomaticZenRule(id, "test"); - assertNull(mZenModeHelperSpy.mConfig.automaticRules.get(id)); + mZenModeHelper.removeAutomaticZenRule(id, "test"); + assertNull(mZenModeHelper.mConfig.automaticRules.get(id)); } @Test @@ -1821,15 +1814,15 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelperSpy.addAutomaticZenRule(null, zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule(null, zenRule, "test"); assertTrue(id != null); - ZenModeConfig.ZenRule ruleInConfig = mZenModeHelperSpy.mConfig.automaticRules.get(id); + ZenModeConfig.ZenRule ruleInConfig = mZenModeHelper.mConfig.automaticRules.get(id); assertTrue(ruleInConfig != null); assertEquals(zenRule.getName(), ruleInConfig.name); - mZenModeHelperSpy.removeAutomaticZenRules(mContext.getPackageName(), "test"); - assertNull(mZenModeHelperSpy.mConfig.automaticRules.get(id)); + mZenModeHelper.removeAutomaticZenRules(mContext.getPackageName(), "test"); + assertNull(mZenModeHelper.mConfig.automaticRules.get(id)); } @Test @@ -1839,17 +1832,17 @@ public class ZenModeHelperTest extends UiServiceTestCase { new ComponentName("android", "ScheduleConditionProvider"), sharedUri, NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule("android", zenRule, "test"); AutomaticZenRule zenRule2 = new AutomaticZenRule("name2", new ComponentName("android", "ScheduleConditionProvider"), sharedUri, NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id2 = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule2, "test"); + String id2 = mZenModeHelper.addAutomaticZenRule("android", zenRule2, "test"); Condition condition = new Condition(sharedUri, "", STATE_TRUE); - mZenModeHelperSpy.setAutomaticZenRuleState(sharedUri, condition); + mZenModeHelper.setAutomaticZenRuleState(sharedUri, condition); - for (ZenModeConfig.ZenRule rule : mZenModeHelperSpy.mConfig.automaticRules.values()) { + for (ZenModeConfig.ZenRule rule : mZenModeHelper.mConfig.automaticRules.values()) { if (rule.id.equals(id)) { assertNotNull(rule.condition); assertTrue(rule.condition.state == STATE_TRUE); @@ -1861,9 +1854,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { } condition = new Condition(sharedUri, "", Condition.STATE_FALSE); - mZenModeHelperSpy.setAutomaticZenRuleState(sharedUri, condition); + mZenModeHelper.setAutomaticZenRuleState(sharedUri, condition); - for (ZenModeConfig.ZenRule rule : mZenModeHelperSpy.mConfig.automaticRules.values()) { + for (ZenModeConfig.ZenRule rule : mZenModeHelper.mConfig.automaticRules.values()) { if (rule.id.equals(id)) { assertNotNull(rule.condition); assertTrue(rule.condition.state == Condition.STATE_FALSE); @@ -1875,31 +1868,48 @@ public class ZenModeHelperTest extends UiServiceTestCase { } } + @Test + public void testSetManualZenMode() { + setupZenConfig(); + + // note that caller=null because that's how it comes in from NMS.setZenMode + mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, null, ""); + mTestableLooper.processAllMessages(); + + // confirm that setting zen mode via setManualZenMode changed the zen mode correctly + assertEquals(ZEN_MODE_IMPORTANT_INTERRUPTIONS, mZenModeHelper.mZenMode); + + // and also that it works to turn it back off again + mZenModeHelper.setManualZenMode(Global.ZEN_MODE_OFF, null, null, ""); + mTestableLooper.processAllMessages(); + assertEquals(Global.ZEN_MODE_OFF, mZenModeHelper.mZenMode); + } + private void setupZenConfig() { - mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; - mZenModeHelperSpy.mConfig.allowAlarms = false; - mZenModeHelperSpy.mConfig.allowMedia = false; - mZenModeHelperSpy.mConfig.allowSystem = false; - mZenModeHelperSpy.mConfig.allowReminders = true; - mZenModeHelperSpy.mConfig.allowCalls = true; - mZenModeHelperSpy.mConfig.allowMessages = true; - mZenModeHelperSpy.mConfig.allowEvents = true; - mZenModeHelperSpy.mConfig.allowRepeatCallers= true; - mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE; - mZenModeHelperSpy.mConfig.manualRule = null; + mZenModeHelper.mZenMode = Global.ZEN_MODE_OFF; + mZenModeHelper.mConfig.allowAlarms = false; + mZenModeHelper.mConfig.allowMedia = false; + mZenModeHelper.mConfig.allowSystem = false; + mZenModeHelper.mConfig.allowReminders = true; + mZenModeHelper.mConfig.allowCalls = true; + mZenModeHelper.mConfig.allowMessages = true; + mZenModeHelper.mConfig.allowEvents = true; + mZenModeHelper.mConfig.allowRepeatCallers = true; + mZenModeHelper.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE; + mZenModeHelper.mConfig.manualRule = null; } private void setupZenConfigMaintained() { // config is still the same as when it was setup (setupZenConfig) - assertFalse(mZenModeHelperSpy.mConfig.allowAlarms); - assertFalse(mZenModeHelperSpy.mConfig.allowMedia); - assertFalse(mZenModeHelperSpy.mConfig.allowSystem); - assertTrue(mZenModeHelperSpy.mConfig.allowReminders); - assertTrue(mZenModeHelperSpy.mConfig.allowCalls); - assertTrue(mZenModeHelperSpy.mConfig.allowMessages); - assertTrue(mZenModeHelperSpy.mConfig.allowEvents); - assertTrue(mZenModeHelperSpy.mConfig.allowRepeatCallers); - assertEquals(SUPPRESSED_EFFECT_BADGE, mZenModeHelperSpy.mConfig.suppressedVisualEffects); + assertFalse(mZenModeHelper.mConfig.allowAlarms); + assertFalse(mZenModeHelper.mConfig.allowMedia); + assertFalse(mZenModeHelper.mConfig.allowSystem); + assertTrue(mZenModeHelper.mConfig.allowReminders); + assertTrue(mZenModeHelper.mConfig.allowCalls); + assertTrue(mZenModeHelper.mConfig.allowMessages); + assertTrue(mZenModeHelper.mConfig.allowEvents); + assertTrue(mZenModeHelper.mConfig.allowRepeatCallers); + assertEquals(SUPPRESSED_EFFECT_BADGE, mZenModeHelper.mConfig.suppressedVisualEffects); } /** diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml index fe7cd4a5edd9..37e5da5f5eaf 100644 --- a/services/tests/wmtests/AndroidManifest.xml +++ b/services/tests/wmtests/AndroidManifest.xml @@ -79,6 +79,7 @@ android:turnScreenOn="true" android:showWhenLocked="true" /> <activity android:name="com.android.server.wm.ActivityOptionsTest$MainActivity" + android:configChanges="screenLayout|screenSize|smallestScreenSize|orientation" android:turnScreenOn="true" android:showWhenLocked="true" /> <activity android:name="com.android.server.wm.ScreenshotTests$ScreenshotActivity" 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/SurfaceControlTests.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceControlTests.java index a27a5fd8a286..342ab83de6f0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceControlTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceControlTests.java @@ -16,19 +16,34 @@ package com.android.server.wm; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; +import android.app.Activity; +import android.app.Instrumentation; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; import android.os.Parcel; import android.platform.test.annotations.Presubmit; +import android.util.Log; import android.view.SurfaceControl; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import androidx.annotation.NonNull; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.concurrent.atomic.AtomicInteger; + /** * Class for testing {@link SurfaceControl}. * @@ -106,6 +121,50 @@ public class SurfaceControlTests { } } + @Test + public void testSurfaceChangedOnRotation() { + final Instrumentation instrumentation = getInstrumentation(); + final Context context = instrumentation.getContext(); + final Activity activity = instrumentation.startActivitySync(new Intent().setComponent( + new ComponentName(context, ActivityOptionsTest.MainActivity.class)) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + final SurfaceView sv = new SurfaceView(activity); + final AtomicInteger surfaceChangedCount = new AtomicInteger(); + instrumentation.runOnMainSync(() -> activity.setContentView(sv)); + sv.getHolder().addCallback(new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + } + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, + int height) { + surfaceChangedCount.getAndIncrement(); + Log.i("surfaceChanged", "width=" + width + " height=" + height + + " getTransformHint=" + + sv.getViewRootImpl().getSurfaceControl().getTransformHint()); + } + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + } + }); + final int rotation = activity.getResources().getConfiguration() + .windowConfiguration.getRotation(); + activity.setRequestedOrientation(activity.getResources().getConfiguration().orientation + == Configuration.ORIENTATION_PORTRAIT + ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + instrumentation.getUiAutomation().syncInputTransactions(); + instrumentation.waitForIdleSync(); + final int newRotation = activity.getResources().getConfiguration() + .windowConfiguration.getRotation(); + final int count = surfaceChangedCount.get(); + activity.finishAndRemoveTask(); + // The first count is triggered from creation, so the target number is 2. + if (rotation != newRotation && count > 2) { + fail("More than once surfaceChanged for rotation change: " + count); + } + } + private SurfaceControl buildTestSurface() { return new SurfaceControl.Builder() .setContainerLayer() 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/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/OpenAppColdFromIcon.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt index 360a2336962c..a658293c4294 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt @@ -16,7 +16,6 @@ package com.android.server.wm.flicker.launch -import android.tools.common.NavBar import android.tools.common.Rotation import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder @@ -87,10 +86,7 @@ open class OpenAppColdFromIcon(flicker: FlickerTest) : OpenAppFromLauncherTransi @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): Collection<FlickerTest> { - // TAPL fails on landscape mode b/240916028 - return FlickerTestFactory.nonRotationTests( - supportedNavigationModes = listOf(NavBar.MODE_3BUTTON) - ) + return FlickerTestFactory.nonRotationTests() } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIconCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIconCfArm.kt index ccbe74f04a70..d33a2724ca44 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIconCfArm.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIconCfArm.kt @@ -17,7 +17,6 @@ package com.android.server.wm.flicker.launch import android.platform.test.annotations.FlakyTest -import android.tools.common.NavBar import android.tools.device.flicker.annotation.FlickerServiceCompatible import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerTest @@ -50,10 +49,7 @@ class OpenAppColdFromIconCfArm(flicker: FlickerTest) : OpenAppColdFromIcon(flick @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): Collection<FlickerTest> { - // TAPL fails on landscape mode b/240916028 - return FlickerTestFactory.nonRotationTests( - supportedNavigationModes = listOf(NavBar.MODE_3BUTTON) - ) + return FlickerTestFactory.nonRotationTests() } } } 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 |