diff options
248 files changed, 10847 insertions, 6031 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index b42c4dacf24f..ff5b2bda7ccf 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -12260,7 +12260,6 @@ package android.provider { } @FlaggedApi("com.android.server.telecom.flags.telecom_mainline_blocked_numbers_manager") public static final class BlockedNumbersManager.BlockSuppressionStatus { - ctor public BlockedNumbersManager.BlockSuppressionStatus(boolean, long); method public boolean getIsSuppressed(); method public long getUntilTimestampMillis(); } @@ -12729,9 +12728,9 @@ package android.security.authenticationpolicy { package android.security.intrusiondetection { @FlaggedApi("android.security.afl_api") public final class IntrusionDetectionEvent implements android.os.Parcelable { - ctor public IntrusionDetectionEvent(@NonNull android.app.admin.SecurityLog.SecurityEvent); - ctor public IntrusionDetectionEvent(@NonNull android.app.admin.DnsEvent); - ctor public IntrusionDetectionEvent(@NonNull android.app.admin.ConnectEvent); + method @NonNull public static android.security.intrusiondetection.IntrusionDetectionEvent createForConnectEvent(@NonNull android.app.admin.ConnectEvent); + method @NonNull public static android.security.intrusiondetection.IntrusionDetectionEvent createForDnsEvent(@NonNull android.app.admin.DnsEvent); + method @NonNull public static android.security.intrusiondetection.IntrusionDetectionEvent createForSecurityEvent(@NonNull android.app.admin.SecurityLog.SecurityEvent); method @FlaggedApi("android.security.afl_api") public int describeContents(); method @NonNull public android.app.admin.ConnectEvent getConnectEvent(); method @NonNull public android.app.admin.DnsEvent getDnsEvent(); diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 832c88a795e5..af6978a6b70c 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -1892,7 +1892,7 @@ public class ActivityOptions extends ComponentOptions { * app to pass through touch events to it when touches fall outside the content window. * * <p> By default, touches that fall on a translucent non-touchable area of an overlaying - * activity window are blocked from passing through to the activity below (source activity), + * activity window may be blocked from passing through to the activity below (source activity), * unless the overlaying activity is from the same UID as the source activity. The source * activity may use this method to opt in and allow the overlaying activities from the * to-be-launched app to pass through touches to itself. The source activity needs to ensure @@ -1900,6 +1900,9 @@ public class ActivityOptions extends ComponentOptions { * attacks. The flag is ignored if the context calling * {@link Context#startActivity(Intent, Bundle)} is not an activity. * + * <p> Apps with target SDK 36 and above that depend on cross-uid pass-through touches must + * opt in to ensure that pass-through touches work correctly. + * * <p> For backward compatibility, apps with target SDK 35 and below may still receive * pass-through touches without opt-in if the cross-uid activity is launched by the source * activity. diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 53b4b54e9f93..efcd278ed118 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -2814,7 +2814,7 @@ public class AppOpsManager { .setDefaultMode(AppOpsManager.MODE_ALLOWED) .build(), new AppOpInfo.Builder(OP_TAKE_AUDIO_FOCUS, OPSTR_TAKE_AUDIO_FOCUS, "TAKE_AUDIO_FOCUS") - .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(), + .setDefaultMode(AppOpsManager.MODE_FOREGROUND).build(), new AppOpInfo.Builder(OP_AUDIO_MASTER_VOLUME, OPSTR_AUDIO_MASTER_VOLUME, "AUDIO_MASTER_VOLUME").setSwitchCode(OP_AUDIO_MASTER_VOLUME) .setRestriction(UserManager.DISALLOW_ADJUST_VOLUME) @@ -3377,10 +3377,6 @@ public class AppOpsManager { * @hide */ public static @Mode int opToDefaultMode(int op) { - if (op == OP_TAKE_AUDIO_FOCUS && roForegroundAudioControl()) { - // when removing the flag, change the entry in sAppOpInfos for OP_TAKE_AUDIO_FOCUS - return AppOpsManager.MODE_FOREGROUND; - } return sAppOpInfos[op].defaultMode; } diff --git a/core/java/android/app/IUserSwitchObserver.aidl b/core/java/android/app/IUserSwitchObserver.aidl index d71ee7c712e7..1ff7a17e578f 100644 --- a/core/java/android/app/IUserSwitchObserver.aidl +++ b/core/java/android/app/IUserSwitchObserver.aidl @@ -19,10 +19,10 @@ package android.app; import android.os.IRemoteCallback; /** {@hide} */ -oneway interface IUserSwitchObserver { - void onBeforeUserSwitching(int newUserId, IRemoteCallback reply); - void onUserSwitching(int newUserId, IRemoteCallback reply); - void onUserSwitchComplete(int newUserId); - void onForegroundProfileSwitch(int newProfileId); - void onLockedBootComplete(int newUserId); +interface IUserSwitchObserver { + void onBeforeUserSwitching(int newUserId); + oneway void onUserSwitching(int newUserId, IRemoteCallback reply); + oneway void onUserSwitchComplete(int newUserId); + oneway void onForegroundProfileSwitch(int newProfileId); + oneway void onLockedBootComplete(int newUserId); } diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index e9b889a2f1aa..2da71471488c 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -68,6 +68,7 @@ import android.service.notification.ZenModeConfig; import android.service.notification.ZenPolicy; import android.util.Log; import android.util.LruCache; +import android.util.Slog; import android.util.proto.ProtoOutputStream; import java.lang.annotation.Retention; @@ -646,16 +647,21 @@ public class NotificationManager { */ public static int MAX_SERVICE_COMPONENT_NAME_LENGTH = 500; - private static final float MAX_NOTIFICATION_ENQUEUE_RATE = 5f; + private static final float MAX_NOTIFICATION_UPDATE_RATE = 5f; + private static final float MAX_NOTIFICATION_UNNECESSARY_CANCEL_RATE = 5f; + private static final int KNOWN_STATUS_ENQUEUED = 1; + private static final int KNOWN_STATUS_CANCELLED = 2; private final Context mContext; private final Map<CallNotificationEventListener, CallNotificationEventCallbackStub> mCallNotificationEventCallbacks = new HashMap<>(); private final InstantSource mClock; - private final RateEstimator mEnqueueRateEstimator = new RateEstimator(); - private final LruCache<String, Boolean> mEnqueuedNotificationKeys = new LruCache<>(10); - private final Object mEnqueueThrottleLock = new Object(); + private final RateEstimator mUpdateRateEstimator = new RateEstimator(); + private final RateEstimator mUnnecessaryCancelRateEstimator = new RateEstimator(); + // Value is KNOWN_STATUS_ENQUEUED/_CANCELLED + private final LruCache<NotificationKey, Integer> mKnownNotifications = new LruCache<>(100); + private final Object mThrottleLock = new Object(); @UnsupportedAppUsage private static INotificationManager sService; @@ -780,7 +786,7 @@ public class NotificationManager { { INotificationManager service = service(); String pkg = mContext.getPackageName(); - if (discardNotify(tag, id, notification)) { + if (discardNotify(user, pkg, tag, id, notification)) { return; } @@ -797,32 +803,39 @@ public class NotificationManager { * Determines whether a {@link #notify} call should be skipped. If the notification is not * skipped, updates tracking metadata to use in future decisions. */ - private boolean discardNotify(@Nullable String tag, int id, Notification notification) { + private boolean discardNotify(UserHandle user, String pkg, @Nullable String tag, int id, + Notification notification) { if (notificationClassification() && NotificationChannel.SYSTEM_RESERVED_IDS.contains(notification.getChannelId())) { return true; } if (Flags.nmBinderPerfThrottleNotify()) { - String key = toEnqueuedNotificationKey(tag, id); + NotificationKey key = new NotificationKey(user, pkg, tag, id); long now = mClock.millis(); - synchronized (mEnqueueThrottleLock) { - if (mEnqueuedNotificationKeys.get(key) != null - && !notification.hasCompletedProgress() - && mEnqueueRateEstimator.getRate(now) > MAX_NOTIFICATION_ENQUEUE_RATE) { - return true; + synchronized (mThrottleLock) { + Integer status = mKnownNotifications.get(key); + if (status != null && status == KNOWN_STATUS_ENQUEUED + && !notification.hasCompletedProgress()) { + float updateRate = mUpdateRateEstimator.getRate(now); + if (updateRate > MAX_NOTIFICATION_UPDATE_RATE) { + Slog.w(TAG, "Shedding update of " + key + + ", notification update maximum rate exceeded (" + updateRate + + ")"); + return true; + } + mUpdateRateEstimator.update(now); } - mEnqueueRateEstimator.update(now); - mEnqueuedNotificationKeys.put(key, Boolean.TRUE); + mKnownNotifications.put(key, KNOWN_STATUS_ENQUEUED); } } return false; } - private static String toEnqueuedNotificationKey(@Nullable String tag, int id) { - return tag + "," + id; - } + + private record NotificationKey(@NonNull UserHandle user, @NonNull String pkg, + @Nullable String tag, int id) { } private Notification fixNotification(Notification notification) { String pkg = mContext.getPackageName(); @@ -920,14 +933,12 @@ public class NotificationManager { @UnsupportedAppUsage public void cancelAsUser(@Nullable String tag, int id, UserHandle user) { - if (Flags.nmBinderPerfThrottleNotify()) { - synchronized (mEnqueueThrottleLock) { - mEnqueuedNotificationKeys.remove(toEnqueuedNotificationKey(tag, id)); - } + String pkg = mContext.getPackageName(); + if (discardCancel(user, pkg, tag, id)) { + return; } INotificationManager service = service(); - String pkg = mContext.getPackageName(); if (localLOGV) Log.v(TAG, pkg + ": cancel(" + id + ")"); try { service.cancelNotificationWithTag( @@ -938,14 +949,43 @@ public class NotificationManager { } /** + * Determines whether a {@link #cancel} call should be skipped. If not skipped, updates tracking + * metadata to use in future decisions. + */ + private boolean discardCancel(UserHandle user, String pkg, @Nullable String tag, int id) { + if (Flags.nmBinderPerfThrottleNotify()) { + NotificationKey key = new NotificationKey(user, pkg, tag, id); + long now = mClock.millis(); + synchronized (mThrottleLock) { + Integer status = mKnownNotifications.get(key); + if (status != null && status == KNOWN_STATUS_CANCELLED) { + float cancelRate = mUnnecessaryCancelRateEstimator.getRate(now); + if (cancelRate > MAX_NOTIFICATION_UNNECESSARY_CANCEL_RATE) { + Slog.w(TAG, "Shedding cancel of " + key + + ", presumably unnecessary and maximum rate exceeded (" + + cancelRate + ")"); + return true; + } + mUnnecessaryCancelRateEstimator.update(now); + } + mKnownNotifications.put(key, KNOWN_STATUS_CANCELLED); + } + } + + return false; + } + + /** * Cancel all previously shown notifications. See {@link #cancel} for the * detailed behavior. */ public void cancelAll() { if (Flags.nmBinderPerfThrottleNotify()) { - synchronized (mEnqueueThrottleLock) { - mEnqueuedNotificationKeys.evictAll(); + synchronized (mThrottleLock) { + for (NotificationKey key : mKnownNotifications.snapshot().keySet()) { + mKnownNotifications.put(key, KNOWN_STATUS_CANCELLED); + } } } diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 51d0b18467f4..d66429a2192d 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -77,6 +77,7 @@ import java.util.function.Function; public class ResourcesManager { static final String TAG = "ResourcesManager"; private static final boolean DEBUG = false; + public static final String RESOURCE_CACHE_DIR = "/data/resource-cache/"; private static volatile ResourcesManager sResourcesManager; @@ -581,7 +582,7 @@ public class ResourcesManager { } private static String overlayPathToIdmapPath(String path) { - return "/data/resource-cache/" + path.substring(1).replace('/', '@') + "@idmap"; + return RESOURCE_CACHE_DIR + path.substring(1).replace('/', '@') + "@idmap"; } /** diff --git a/core/java/android/app/UserSwitchObserver.java b/core/java/android/app/UserSwitchObserver.java index 1664cfb6f7a8..727799a1f948 100644 --- a/core/java/android/app/UserSwitchObserver.java +++ b/core/java/android/app/UserSwitchObserver.java @@ -30,11 +30,7 @@ public class UserSwitchObserver extends IUserSwitchObserver.Stub { } @Override - public void onBeforeUserSwitching(int newUserId, IRemoteCallback reply) throws RemoteException { - if (reply != null) { - reply.sendResult(null); - } - } + public void onBeforeUserSwitching(int newUserId) throws RemoteException {} @Override public void onUserSwitching(int newUserId, IRemoteCallback reply) throws RemoteException { diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index bcaceb24d767..96c71765d102 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -992,15 +992,24 @@ public class ResourcesImpl { } else { dr = loadXmlDrawable(wrapper, value, id, density, file); } - } else if (file.startsWith("frro://")) { + } else if (file.startsWith("frro:/")) { Uri uri = Uri.parse(file); + long offset = Long.parseLong(uri.getQueryParameter("offset")); + long size = Long.parseLong(uri.getQueryParameter("size")); + if (offset < 0 || size <= 0) { + throw new NotFoundException("invalid frro parameters"); + } File f = new File('/' + uri.getHost() + uri.getPath()); + if (!f.getCanonicalPath().startsWith(ResourcesManager.RESOURCE_CACHE_DIR) + || !f.getCanonicalPath().endsWith(".frro") || !f.canRead()) { + throw new NotFoundException("invalid frro path"); + } ParcelFileDescriptor pfd = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY); AssetFileDescriptor afd = new AssetFileDescriptor( pfd, - Long.parseLong(uri.getQueryParameter("offset")), - Long.parseLong(uri.getQueryParameter("size"))); + offset, + size); FileInputStream is = afd.createInputStream(); dr = decodeImageDrawable(is, wrapper); } else { diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java index 3425b77be954..0eb9f29e1ec3 100644 --- a/core/java/android/net/http/X509TrustManagerExtensions.java +++ b/core/java/android/net/http/X509TrustManagerExtensions.java @@ -86,8 +86,8 @@ public class X509TrustManagerExtensions { try { checkServerTrustedOcspAndTlsData = tm.getClass().getMethod("checkServerTrusted", X509Certificate[].class, - Byte[].class, - Byte[].class, + byte[].class, + byte[].class, String.class, String.class); } catch (ReflectiveOperationException ignored) { } @@ -179,7 +179,7 @@ public class X509TrustManagerExtensions { } try { result = (List<X509Certificate>) mCheckServerTrustedOcspAndTlsData.invoke(mTrustManager, - ocspData, tlsSctData, chain, authType, host); + chain, ocspData, tlsSctData, authType, host); return result == null ? Collections.emptyList() : result; } catch (IllegalAccessException e) { throw new CertificateException("Failed to call checkServerTrusted", e); diff --git a/core/java/android/os/PerfettoTrace.java b/core/java/android/os/PerfettoTrace.java new file mode 100644 index 000000000000..164561acac32 --- /dev/null +++ b/core/java/android/os/PerfettoTrace.java @@ -0,0 +1,395 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import dalvik.annotation.optimization.CriticalNative; +import dalvik.annotation.optimization.FastNative; + +import libcore.util.NativeAllocationRegistry; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; + +/** + * Writes trace events to the perfetto trace buffer. These trace events can be + * collected and visualized using the Perfetto UI. + * + * <p>This tracing mechanism is independent of the method tracing mechanism + * offered by {@link Debug#startMethodTracing} or {@link Trace}. + * + * @hide + */ +public final class PerfettoTrace { + private static final String TAG = "PerfettoTrace"; + + // Keep in sync with C++ + private static final int PERFETTO_TE_TYPE_SLICE_BEGIN = 1; + private static final int PERFETTO_TE_TYPE_SLICE_END = 2; + private static final int PERFETTO_TE_TYPE_INSTANT = 3; + private static final int PERFETTO_TE_TYPE_COUNTER = 4; + + private static final boolean IS_FLAG_ENABLED = android.os.Flags.perfettoSdkTracingV2(); + + /** + * For fetching the next flow event id in a process. + */ + private static final AtomicInteger sFlowEventId = new AtomicInteger(); + + /** + * Perfetto category a trace event belongs to. + * Registering a category is not sufficient to capture events within the category, it must + * also be enabled in the trace config. + */ + public static final class Category implements PerfettoTrackEventExtra.PerfettoPointer { + private static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + Category.class.getClassLoader(), native_delete()); + + private final long mPtr; + private final long mExtraPtr; + private final String mName; + private final String mTag; + private final String mSeverity; + private boolean mIsRegistered; + + /** + * Category ctor. + * + * @param name The category name. + */ + public Category(String name) { + this(name, null, null); + } + + /** + * Category ctor. + * + * @param name The category name. + * @param tag An atrace tag name that this category maps to. + */ + public Category(String name, String tag) { + this(name, tag, null); + } + + /** + * Category ctor. + * + * @param name The category name. + * @param tag An atrace tag name that this category maps to. + * @param severity A Log style severity string for the category. + */ + public Category(String name, String tag, String severity) { + mName = name; + mTag = tag; + mSeverity = severity; + mPtr = native_init(name, tag, severity); + mExtraPtr = native_get_extra_ptr(mPtr); + sRegistry.registerNativeAllocation(this, mPtr); + } + + @FastNative + private static native long native_init(String name, String tag, String severity); + @CriticalNative + private static native long native_delete(); + @CriticalNative + private static native void native_register(long ptr); + @CriticalNative + private static native void native_unregister(long ptr); + @CriticalNative + private static native boolean native_is_enabled(long ptr); + @CriticalNative + private static native long native_get_extra_ptr(long ptr); + + /** + * Register the category. + */ + public Category register() { + native_register(mPtr); + mIsRegistered = true; + return this; + } + + /** + * Unregister the category. + */ + public Category unregister() { + native_unregister(mPtr); + mIsRegistered = false; + return this; + } + + /** + * Whether the category is enabled or not. + */ + public boolean isEnabled() { + return IS_FLAG_ENABLED && native_is_enabled(mPtr); + } + + /** + * Whether the category is registered or not. + */ + public boolean isRegistered() { + return mIsRegistered; + } + + /** + * Returns the native pointer for the category. + */ + @Override + public long getPtr() { + return mExtraPtr; + } + } + + @FastNative + private static native void native_event(int type, long tag, String name, long ptr); + + @CriticalNative + private static native long native_get_process_track_uuid(); + + @CriticalNative + private static native long native_get_thread_track_uuid(long tid); + + @FastNative + private static native void native_activate_trigger(String name, int ttlMs); + + /** + * Writes a trace message to indicate a given section of code was invoked. + * + * @param category The perfetto category pointer. + * @param eventName The event name to appear in the trace. + * @param extra The extra arguments. + */ + public static void instant(Category category, String eventName, PerfettoTrackEventExtra extra) { + if (!category.isEnabled()) { + return; + } + + native_event(PERFETTO_TE_TYPE_INSTANT, category.getPtr(), eventName, extra.getPtr()); + extra.reset(); + } + + /** + * Writes a trace message to indicate a given section of code was invoked. + * + * @param category The perfetto category. + * @param eventName The event name to appear in the trace. + * @param extraConfig Consumer for the extra arguments. + */ + public static void instant(Category category, String eventName, + Consumer<PerfettoTrackEventExtra.Builder> extraConfig) { + PerfettoTrackEventExtra.Builder extra = PerfettoTrackEventExtra.builder(); + extraConfig.accept(extra); + instant(category, eventName, extra.build()); + } + + /** + * Writes a trace message to indicate a given section of code was invoked. + * + * @param category The perfetto category. + * @param eventName The event name to appear in the trace. + */ + public static void instant(Category category, String eventName) { + instant(category, eventName, PerfettoTrackEventExtra.builder().build()); + } + + /** + * Writes a trace message to indicate the start of a given section of code. + * + * @param category The perfetto category pointer. + * @param eventName The event name to appear in the trace. + * @param extra The extra arguments. + */ + public static void begin(Category category, String eventName, PerfettoTrackEventExtra extra) { + if (!category.isEnabled()) { + return; + } + + native_event(PERFETTO_TE_TYPE_SLICE_BEGIN, category.getPtr(), eventName, extra.getPtr()); + extra.reset(); + } + + /** + * Writes a trace message to indicate the start of a given section of code. + * + * @param category The perfetto category pointer. + * @param eventName The event name to appear in the trace. + * @param extraConfig Consumer for the extra arguments. + */ + public static void begin(Category category, String eventName, + Consumer<PerfettoTrackEventExtra.Builder> extraConfig) { + PerfettoTrackEventExtra.Builder extra = PerfettoTrackEventExtra.builder(); + extraConfig.accept(extra); + begin(category, eventName, extra.build()); + } + + /** + * Writes a trace message to indicate the start of a given section of code. + * + * @param category The perfetto category pointer. + * @param eventName The event name to appear in the trace. + */ + public static void begin(Category category, String eventName) { + begin(category, eventName, PerfettoTrackEventExtra.builder().build()); + } + + /** + * Writes a trace message to indicate the end of a given section of code. + * + * @param category The perfetto category pointer. + * @param extra The extra arguments. + */ + public static void end(Category category, PerfettoTrackEventExtra extra) { + if (!category.isEnabled()) { + return; + } + + native_event(PERFETTO_TE_TYPE_SLICE_END, category.getPtr(), "", extra.getPtr()); + extra.reset(); + } + + /** + * Writes a trace message to indicate the end of a given section of code. + * + * @param category The perfetto category pointer. + * @param extraConfig Consumer for the extra arguments. + */ + public static void end(Category category, + Consumer<PerfettoTrackEventExtra.Builder> extraConfig) { + PerfettoTrackEventExtra.Builder extra = PerfettoTrackEventExtra.builder(); + extraConfig.accept(extra); + end(category, extra.build()); + } + + /** + * Writes a trace message to indicate the end of a given section of code. + * + * @param category The perfetto category pointer. + */ + public static void end(Category category) { + end(category, PerfettoTrackEventExtra.builder().build()); + } + + /** + * Writes a trace message to indicate the value of a given section of code. + * + * @param category The perfetto category pointer. + * @param extra The extra arguments. + */ + public static void counter(Category category, PerfettoTrackEventExtra extra) { + if (!category.isEnabled()) { + return; + } + + native_event(PERFETTO_TE_TYPE_COUNTER, category.getPtr(), "", extra.getPtr()); + extra.reset(); + } + + /** + * Writes a trace message to indicate the value of a given section of code. + * + * @param category The perfetto category pointer. + * @param extraConfig Consumer for the extra arguments. + */ + public static void counter(Category category, + Consumer<PerfettoTrackEventExtra.Builder> extraConfig) { + PerfettoTrackEventExtra.Builder extra = PerfettoTrackEventExtra.builder(); + extraConfig.accept(extra); + counter(category, extra.build()); + } + + /** + * Writes a trace message to indicate the value of a given section of code. + * + * @param category The perfetto category pointer. + * @param trackName The trackName for the event. + * @param value The value of the counter. + */ + public static void counter(Category category, String trackName, long value) { + PerfettoTrackEventExtra extra = PerfettoTrackEventExtra.builder() + .usingCounterTrack(trackName, PerfettoTrace.getProcessTrackUuid()) + .setCounter(value) + .build(); + counter(category, extra); + } + + /** + * Writes a trace message to indicate the value of a given section of code. + * + * @param category The perfetto category pointer. + * @param trackName The trackName for the event. + * @param value The value of the counter. + */ + public static void counter(Category category, String trackName, double value) { + PerfettoTrackEventExtra extra = PerfettoTrackEventExtra.builder() + .usingCounterTrack(trackName, PerfettoTrace.getProcessTrackUuid()) + .setCounter(value) + .build(); + counter(category, extra); + } + + /** + * Returns the next flow id to be used. + */ + public static int getFlowId() { + return sFlowEventId.incrementAndGet(); + } + + /** + * Returns the global track uuid that can be used as a parent track uuid. + */ + public static long getGlobalTrackUuid() { + return 0; + } + + /** + * Returns the process track uuid that can be used as a parent track uuid. + */ + public static long getProcessTrackUuid() { + if (IS_FLAG_ENABLED) { + return 0; + } + return native_get_process_track_uuid(); + } + + /** + * Given a thread tid, returns the thread track uuid that can be used as a parent track uuid. + */ + public static long getThreadTrackUuid(long tid) { + if (IS_FLAG_ENABLED) { + return 0; + } + return native_get_thread_track_uuid(tid); + } + + /** + * Activates a trigger by name {@code triggerName} with expiry in {@code ttlMs}. + */ + public static void activateTrigger(String triggerName, int ttlMs) { + if (IS_FLAG_ENABLED) { + return; + } + native_activate_trigger(triggerName, ttlMs); + } + + /** + * Registers the process with Perfetto. + */ + public static void register() { + Trace.registerWithPerfetto(); + } +} diff --git a/core/java/android/os/PerfettoTrackEventExtra.java b/core/java/android/os/PerfettoTrackEventExtra.java new file mode 100644 index 000000000000..a219b3b5678b --- /dev/null +++ b/core/java/android/os/PerfettoTrackEventExtra.java @@ -0,0 +1,1081 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import dalvik.annotation.optimization.CriticalNative; +import dalvik.annotation.optimization.FastNative; + +import libcore.util.NativeAllocationRegistry; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Supplier; + +/** + * Holds extras to be passed to Perfetto track events in {@link PerfettoTrace}. + * + * @hide + */ +public final class PerfettoTrackEventExtra { + private static final int DEFAULT_EXTRA_CACHE_SIZE = 5; + private static final ThreadLocal<PerfettoTrackEventExtra> sTrackEventExtra = + new ThreadLocal<PerfettoTrackEventExtra>() { + @Override + protected PerfettoTrackEventExtra initialValue() { + return new PerfettoTrackEventExtra(); + } + }; + private static final AtomicLong sNamedTrackId = new AtomicLong(); + + private boolean mIsInUse; + private CounterInt64 mCounterInt64; + private CounterDouble mCounterDouble; + private Proto mProto; + + /** + * Represents a native pointer to a Perfetto C SDK struct. E.g. PerfettoTeHlExtra. + */ + public interface PerfettoPointer { + /** + * Returns the perfetto struct native pointer. + */ + long getPtr(); + } + + /** + * Container for {@link Field} instances. + */ + public interface FieldContainer { + /** + * Add {@link Field} to the container. + */ + void addField(PerfettoPointer field); + } + + /** + * RingBuffer implemented on top of a SparseArray. + * + * Bounds a SparseArray with a FIFO algorithm. + */ + private static final class RingBuffer<T> { + private final int mCapacity; + private final int[] mKeyArray; + private final T[] mValueArray; + private int mWriteEnd = 0; + + RingBuffer(int capacity) { + mCapacity = capacity; + mKeyArray = new int[capacity]; + mValueArray = (T[]) new Object[capacity]; + } + + public void put(int key, T value) { + mKeyArray[mWriteEnd] = key; + mValueArray[mWriteEnd] = value; + mWriteEnd = (mWriteEnd + 1) % mCapacity; + } + + public T get(int key) { + for (int i = 0; i < mCapacity; i++) { + if (mKeyArray[i] == key) { + return mValueArray[i]; + } + } + return null; + } + } + + private static final class Pool<T> { + private final int mCapacity; + private final T[] mValueArray; + private int mIdx = 0; + + Pool(int capacity) { + mCapacity = capacity; + mValueArray = (T[]) new Object[capacity]; + } + + public void reset() { + mIdx = 0; + } + + public T get(Supplier<T> supplier) { + if (mIdx >= mCapacity) { + return supplier.get(); + } + if (mValueArray[mIdx] == null) { + mValueArray[mIdx] = supplier.get(); + } + return mValueArray[mIdx++]; + } + } + + /** + * Builder for Perfetto track event extras. + */ + public static final class Builder { + // For performance reasons, we hold a reference to mExtra as a holder for + // perfetto pointers being added. This way, we avoid an additional list to hold + // the pointers in Java and we can pass them down directly to native code. + private final PerfettoTrackEventExtra mExtra; + private boolean mIsBuilt; + private Builder mParent; + private FieldContainer mCurrentContainer; + + private final CounterInt64 mCounterInt64; + private final CounterDouble mCounterDouble; + private final Proto mProto; + + private final RingBuffer<NamedTrack> mNamedTrackCache; + private final RingBuffer<CounterTrack> mCounterTrackCache; + private final RingBuffer<ArgInt64> mArgInt64Cache; + private final RingBuffer<ArgBool> mArgBoolCache; + private final RingBuffer<ArgDouble> mArgDoubleCache; + private final RingBuffer<ArgString> mArgStringCache; + + private final Pool<FieldInt64> mFieldInt64Cache; + private final Pool<FieldDouble> mFieldDoubleCache; + private final Pool<FieldString> mFieldStringCache; + private final Pool<FieldNested> mFieldNestedCache; + private final Pool<Flow> mFlowCache; + private final Pool<Builder> mBuilderCache; + + private Builder() { + this(sTrackEventExtra.get(), null, null); + } + + private Builder(PerfettoTrackEventExtra extra, Builder parent, FieldContainer container) { + mExtra = extra; + mParent = parent; + mCurrentContainer = container; + + mNamedTrackCache = mExtra.mNamedTrackCache; + mCounterTrackCache = mExtra.mCounterTrackCache; + mArgInt64Cache = mExtra.mArgInt64Cache; + mArgDoubleCache = mExtra.mArgDoubleCache; + mArgBoolCache = mExtra.mArgBoolCache; + mArgStringCache = mExtra.mArgStringCache; + mFieldInt64Cache = mExtra.mFieldInt64Cache; + mFieldDoubleCache = mExtra.mFieldDoubleCache; + mFieldStringCache = mExtra.mFieldStringCache; + mFieldNestedCache = mExtra.mFieldNestedCache; + mFlowCache = mExtra.mFlowCache; + mBuilderCache = mExtra.mBuilderCache; + + mCounterInt64 = mExtra.getCounterInt64(); + mCounterDouble = mExtra.getCounterDouble(); + mProto = mExtra.getProto(); + } + + /** + * Builds the track event extra. + */ + public PerfettoTrackEventExtra build() { + checkParent(); + mIsBuilt = true; + + mFieldInt64Cache.reset(); + mFieldDoubleCache.reset(); + mFieldStringCache.reset(); + mFieldNestedCache.reset(); + mBuilderCache.reset(); + + return mExtra; + } + + /** + * Adds a debug arg with key {@code name} and value {@code val}. + */ + public Builder addArg(String name, long val) { + checkParent(); + ArgInt64 arg = mArgInt64Cache.get(name.hashCode()); + if (arg == null || !arg.getName().equals(name)) { + arg = new ArgInt64(name); + mArgInt64Cache.put(name.hashCode(), arg); + } + arg.setValue(val); + mExtra.addPerfettoPointer(arg); + return this; + } + + /** + * Adds a debug arg with key {@code name} and value {@code val}. + */ + public Builder addArg(String name, boolean val) { + checkParent(); + ArgBool arg = mArgBoolCache.get(name.hashCode()); + if (arg == null || !arg.getName().equals(name)) { + arg = new ArgBool(name); + mArgBoolCache.put(name.hashCode(), arg); + } + arg.setValue(val); + mExtra.addPerfettoPointer(arg); + return this; + } + + /** + * Adds a debug arg with key {@code name} and value {@code val}. + */ + public Builder addArg(String name, double val) { + checkParent(); + ArgDouble arg = mArgDoubleCache.get(name.hashCode()); + if (arg == null || !arg.getName().equals(name)) { + arg = new ArgDouble(name); + mArgDoubleCache.put(name.hashCode(), arg); + } + arg.setValue(val); + mExtra.addPerfettoPointer(arg); + return this; + } + + /** + * Adds a debug arg with key {@code name} and value {@code val}. + */ + public Builder addArg(String name, String val) { + checkParent(); + ArgString arg = mArgStringCache.get(name.hashCode()); + if (arg == null || !arg.getName().equals(name)) { + arg = new ArgString(name); + mArgStringCache.put(name.hashCode(), arg); + } + arg.setValue(val); + mExtra.addPerfettoPointer(arg); + return this; + } + + /** + * Adds a flow with {@code id}. + */ + public Builder addFlow(int id) { + checkParent(); + Flow flow = mFlowCache.get(Flow::new); + flow.setProcessFlow(id); + mExtra.addPerfettoPointer(flow); + return this; + } + + /** + * Adds a terminating flow with {@code id}. + */ + public Builder addTerminatingFlow(int id) { + checkParent(); + Flow flow = mFlowCache.get(Flow::new); + flow.setProcessTerminatingFlow(id); + mExtra.addPerfettoPointer(flow); + return this; + } + + /** + * Adds the events to a named track instead of the thread track where the + * event occurred. + */ + public Builder usingNamedTrack(String name, long parentUuid) { + checkParent(); + NamedTrack track = mNamedTrackCache.get(name.hashCode()); + if (track == null || !track.getName().equals(name)) { + track = new NamedTrack(name, parentUuid); + mNamedTrackCache.put(name.hashCode(), track); + } + mExtra.addPerfettoPointer(track); + return this; + } + + /** + * Adds the events to a counter track instead. This is required for + * setting counter values. + * + */ + public Builder usingCounterTrack(String name, long parentUuid) { + checkParent(); + CounterTrack track = mCounterTrackCache.get(name.hashCode()); + if (track == null || !track.getName().equals(name)) { + track = new CounterTrack(name, parentUuid); + mCounterTrackCache.put(name.hashCode(), track); + } + mExtra.addPerfettoPointer(track); + return this; + } + + /** + * Sets a long counter value on the event. + * + */ + public Builder setCounter(long val) { + checkParent(); + mCounterInt64.setValue(val); + mExtra.addPerfettoPointer(mCounterInt64); + return this; + } + + /** + * Sets a double counter value on the event. + * + */ + public Builder setCounter(double val) { + checkParent(); + mCounterDouble.setValue(val); + mExtra.addPerfettoPointer(mCounterDouble); + return this; + } + + /** + * Adds a proto field with field id {@code id} and value {@code val}. + */ + public Builder addField(long id, long val) { + checkContainer(); + FieldInt64 field = mFieldInt64Cache.get(FieldInt64::new); + field.setValue(id, val); + mCurrentContainer.addField(field); + return this; + } + + /** + * Adds a proto field with field id {@code id} and value {@code val}. + */ + public Builder addField(long id, double val) { + checkContainer(); + FieldDouble field = mFieldDoubleCache.get(FieldDouble::new); + field.setValue(id, val); + mCurrentContainer.addField(field); + return this; + } + + /** + * Adds a proto field with field id {@code id} and value {@code val}. + */ + public Builder addField(long id, String val) { + checkContainer(); + FieldString field = mFieldStringCache.get(FieldString::new); + field.setValue(id, val); + mCurrentContainer.addField(field); + return this; + } + + /** + * Begins a proto field with field + * Fields can be added from this point and there must be a corresponding + * {@link endProto}. + * + * The proto field is a singleton and all proto fields get added inside the + * one {@link beginProto} and {@link endProto} within the {@link Builder}. + */ + public Builder beginProto() { + checkParent(); + mProto.clearFields(); + mExtra.addPerfettoPointer(mProto); + return mBuilderCache.get(Builder::new).init(this, mProto); + } + + /** + * Ends a proto field. + */ + public Builder endProto() { + if (mParent == null || mCurrentContainer == null) { + throw new IllegalStateException("No proto to end"); + } + return mParent; + } + + /** + * Begins a nested proto field with field id {@code id}. + * Fields can be added from this point and there must be a corresponding + * {@link endNested}. + */ + public Builder beginNested(long id) { + checkContainer(); + FieldNested field = mFieldNestedCache.get(FieldNested::new); + field.setId(id); + mCurrentContainer.addField(field); + return mBuilderCache.get(Builder::new).init(this, field); + } + + /** + * Ends a nested proto field. + */ + public Builder endNested() { + if (mParent == null || mCurrentContainer == null) { + throw new IllegalStateException("No nested field to end"); + } + return mParent; + } + + /** + * Initializes a {@link Builder}. + */ + public Builder init(Builder parent, FieldContainer container) { + mParent = parent; + mCurrentContainer = container; + mIsBuilt = false; + + if (mParent == null) { + if (mExtra.mIsInUse) { + throw new IllegalStateException("Cannot create a new builder when another" + + " extra is in use"); + } + mExtra.mIsInUse = true; + } + return this; + } + + private void checkState() { + if (mIsBuilt) { + throw new IllegalStateException( + "This builder has already been used. Create a new builder for another event."); + } + } + + private void checkParent() { + checkState(); + if (mParent != null) { + throw new IllegalStateException( + "This builder has already been used. Create a new builder for another event."); + } + } + + private void checkContainer() { + checkState(); + if (mCurrentContainer == null) { + throw new IllegalStateException( + "Field operations must be within beginProto/endProto block"); + } + } + } + + /** + * Start a {@link Builder} to build a {@link PerfettoTrackEventExtra}. + */ + public static Builder builder() { + return sTrackEventExtra.get().mBuilderCache.get(Builder::new).init(null, null); + } + + private final RingBuffer<NamedTrack> mNamedTrackCache = + new RingBuffer(DEFAULT_EXTRA_CACHE_SIZE); + private final RingBuffer<CounterTrack> mCounterTrackCache = + new RingBuffer(DEFAULT_EXTRA_CACHE_SIZE); + + private final RingBuffer<ArgInt64> mArgInt64Cache = new RingBuffer(DEFAULT_EXTRA_CACHE_SIZE); + private final RingBuffer<ArgBool> mArgBoolCache = new RingBuffer(DEFAULT_EXTRA_CACHE_SIZE); + private final RingBuffer<ArgDouble> mArgDoubleCache = new RingBuffer(DEFAULT_EXTRA_CACHE_SIZE); + private final RingBuffer<ArgString> mArgStringCache = new RingBuffer(DEFAULT_EXTRA_CACHE_SIZE); + + private final Pool<FieldInt64> mFieldInt64Cache = new Pool(DEFAULT_EXTRA_CACHE_SIZE); + private final Pool<FieldDouble> mFieldDoubleCache = new Pool(DEFAULT_EXTRA_CACHE_SIZE); + private final Pool<FieldString> mFieldStringCache = new Pool(DEFAULT_EXTRA_CACHE_SIZE); + private final Pool<FieldNested> mFieldNestedCache = new Pool(DEFAULT_EXTRA_CACHE_SIZE); + private final Pool<Flow> mFlowCache = new Pool(DEFAULT_EXTRA_CACHE_SIZE); + private final Pool<Builder> mBuilderCache = new Pool(DEFAULT_EXTRA_CACHE_SIZE); + + private static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + PerfettoTrackEventExtra.class.getClassLoader(), native_delete()); + + private final long mPtr; + private static final String TAG = "PerfettoTrackEventExtra"; + + private PerfettoTrackEventExtra() { + mPtr = native_init(); + sRegistry.registerNativeAllocation(this, mPtr); + } + + /** + * Returns the native pointer. + */ + public long getPtr() { + return mPtr; + } + + /** + * Adds a pointer representing a track event parameter. + */ + public void addPerfettoPointer(PerfettoPointer extra) { + native_add_arg(mPtr, extra.getPtr()); + } + + /** + * Resets the track event extra. + */ + public void reset() { + native_clear_args(mPtr); + mIsInUse = false; + } + + private CounterInt64 getCounterInt64() { + if (mCounterInt64 == null) { + mCounterInt64 = new CounterInt64(); + } + return mCounterInt64; + } + + private CounterDouble getCounterDouble() { + if (mCounterDouble == null) { + mCounterDouble = new CounterDouble(); + } + return mCounterDouble; + } + + private Proto getProto() { + if (mProto == null) { + mProto = new Proto(); + } + return mProto; + } + + private static final class Flow implements PerfettoPointer { + private static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + Flow.class.getClassLoader(), native_delete()); + + private final long mPtr; + private final long mExtraPtr; + + Flow() { + mPtr = native_init(); + mExtraPtr = native_get_extra_ptr(mPtr); + sRegistry.registerNativeAllocation(this, mPtr); + } + + public void setProcessFlow(long type) { + native_set_process_flow(mPtr, type); + } + + public void setProcessTerminatingFlow(long id) { + native_set_process_terminating_flow(mPtr, id); + } + + @Override + public long getPtr() { + return mExtraPtr; + } + + @CriticalNative + private static native long native_init(); + @CriticalNative + private static native long native_delete(); + @CriticalNative + private static native void native_set_process_flow(long ptr, long type); + @CriticalNative + private static native void native_set_process_terminating_flow(long ptr, long id); + @CriticalNative + private static native long native_get_extra_ptr(long ptr); + } + + private static class NamedTrack implements PerfettoPointer { + private static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + NamedTrack.class.getClassLoader(), native_delete()); + + private final long mPtr; + private final long mExtraPtr; + private final String mName; + + NamedTrack(String name, long parentUuid) { + mPtr = native_init(sNamedTrackId.incrementAndGet(), name, parentUuid); + mExtraPtr = native_get_extra_ptr(mPtr); + mName = name; + sRegistry.registerNativeAllocation(this, mPtr); + } + + @Override + public long getPtr() { + return mExtraPtr; + } + + public String getName() { + return mName; + } + + @FastNative + private static native long native_init(long id, String name, long parentUuid); + @CriticalNative + private static native long native_delete(); + @CriticalNative + private static native long native_get_extra_ptr(long ptr); + } + + private static final class CounterTrack implements PerfettoPointer { + private static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + CounterTrack.class.getClassLoader(), native_delete()); + + private final long mPtr; + private final long mExtraPtr; + private final String mName; + + CounterTrack(String name, long parentUuid) { + mPtr = native_init(name, parentUuid); + mExtraPtr = native_get_extra_ptr(mPtr); + mName = name; + sRegistry.registerNativeAllocation(this, mPtr); + } + + @Override + public long getPtr() { + return mExtraPtr; + } + + public String getName() { + return mName; + } + + @FastNative + private static native long native_init(String name, long parentUuid); + @CriticalNative + private static native long native_delete(); + @CriticalNative + private static native long native_get_extra_ptr(long ptr); + } + + private static final class CounterInt64 implements PerfettoPointer { + private static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + CounterInt64.class.getClassLoader(), native_delete()); + + private final long mPtr; + private final long mExtraPtr; + + CounterInt64() { + mPtr = native_init(); + mExtraPtr = native_get_extra_ptr(mPtr); + sRegistry.registerNativeAllocation(this, mPtr); + } + + @Override + public long getPtr() { + return mExtraPtr; + } + + public void setValue(long value) { + native_set_value(mPtr, value); + } + + @CriticalNative + private static native long native_init(); + @CriticalNative + private static native long native_delete(); + @CriticalNative + private static native void native_set_value(long ptr, long value); + @CriticalNative + private static native long native_get_extra_ptr(long ptr); + } + + private static final class CounterDouble implements PerfettoPointer { + private static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + CounterDouble.class.getClassLoader(), native_delete()); + + private final long mPtr; + private final long mExtraPtr; + + CounterDouble() { + mPtr = native_init(); + mExtraPtr = native_get_extra_ptr(mPtr); + sRegistry.registerNativeAllocation(this, mPtr); + } + + @Override + public long getPtr() { + return mExtraPtr; + } + + public void setValue(double value) { + native_set_value(mPtr, value); + } + + @CriticalNative + private static native long native_init(); + @CriticalNative + private static native long native_delete(); + @CriticalNative + private static native void native_set_value(long ptr, double value); + @CriticalNative + private static native long native_get_extra_ptr(long ptr); + } + + private static final class ArgInt64 implements PerfettoPointer { + private static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + ArgInt64.class.getClassLoader(), native_delete()); + + // Private pointer holding Perfetto object with metadata + private final long mPtr; + + // Public pointer to Perfetto object itself + private final long mExtraPtr; + + private final String mName; + + ArgInt64(String name) { + mPtr = native_init(name); + mExtraPtr = native_get_extra_ptr(mPtr); + mName = name; + sRegistry.registerNativeAllocation(this, mPtr); + } + + @Override + public long getPtr() { + return mExtraPtr; + } + + public String getName() { + return mName; + } + + public void setValue(long val) { + native_set_value(mPtr, val); + } + + @FastNative + private static native long native_init(String name); + @CriticalNative + private static native long native_delete(); + @CriticalNative + private static native long native_get_extra_ptr(long ptr); + @CriticalNative + private static native void native_set_value(long ptr, long val); + } + + private static final class ArgBool implements PerfettoPointer { + private static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + ArgBool.class.getClassLoader(), native_delete()); + + // Private pointer holding Perfetto object with metadata + private final long mPtr; + + // Public pointer to Perfetto object itself + private final long mExtraPtr; + + private final String mName; + + ArgBool(String name) { + mPtr = native_init(name); + mExtraPtr = native_get_extra_ptr(mPtr); + mName = name; + sRegistry.registerNativeAllocation(this, mPtr); + } + + @Override + public long getPtr() { + return mExtraPtr; + } + + public String getName() { + return mName; + } + + public void setValue(boolean val) { + native_set_value(mPtr, val); + } + + @FastNative + private static native long native_init(String name); + @CriticalNative + private static native long native_delete(); + @CriticalNative + private static native long native_get_extra_ptr(long ptr); + @CriticalNative + private static native void native_set_value(long ptr, boolean val); + } + + private static final class ArgDouble implements PerfettoPointer { + private static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + ArgDouble.class.getClassLoader(), native_delete()); + + // Private pointer holding Perfetto object with metadata + private final long mPtr; + + // Public pointer to Perfetto object itself + private final long mExtraPtr; + + private final String mName; + + ArgDouble(String name) { + mPtr = native_init(name); + mExtraPtr = native_get_extra_ptr(mPtr); + mName = name; + sRegistry.registerNativeAllocation(this, mPtr); + } + + @Override + public long getPtr() { + return mExtraPtr; + } + + public String getName() { + return mName; + } + + public void setValue(double val) { + native_set_value(mPtr, val); + } + + @FastNative + private static native long native_init(String name); + @CriticalNative + private static native long native_delete(); + @CriticalNative + private static native long native_get_extra_ptr(long ptr); + @CriticalNative + private static native void native_set_value(long ptr, double val); + } + + private static final class ArgString implements PerfettoPointer { + private static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + ArgString.class.getClassLoader(), native_delete()); + + // Private pointer holding Perfetto object with metadata + private final long mPtr; + + // Public pointer to Perfetto object itself + private final long mExtraPtr; + + private final String mName; + + ArgString(String name) { + mPtr = native_init(name); + mExtraPtr = native_get_extra_ptr(mPtr); + mName = name; + sRegistry.registerNativeAllocation(this, mPtr); + } + + @Override + public long getPtr() { + return mExtraPtr; + } + + public String getName() { + return mName; + } + + public void setValue(String val) { + native_set_value(mPtr, val); + } + + @FastNative + private static native long native_init(String name); + @CriticalNative + private static native long native_delete(); + @CriticalNative + private static native long native_get_extra_ptr(long ptr); + @FastNative + private static native void native_set_value(long ptr, String val); + } + + private static final class Proto implements PerfettoPointer, FieldContainer { + private static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + Proto.class.getClassLoader(), native_delete()); + + // Private pointer holding Perfetto object with metadata + private final long mPtr; + + // Public pointer to Perfetto object itself + private final long mExtraPtr; + + Proto() { + mPtr = native_init(); + mExtraPtr = native_get_extra_ptr(mPtr); + sRegistry.registerNativeAllocation(this, mPtr); + } + + @Override + public long getPtr() { + return mExtraPtr; + } + + @Override + public void addField(PerfettoPointer field) { + native_add_field(mPtr, field.getPtr()); + } + + public void clearFields() { + native_clear_fields(mPtr); + } + + @CriticalNative + private static native long native_init(); + @CriticalNative + private static native long native_delete(); + @CriticalNative + private static native long native_get_extra_ptr(long ptr); + @CriticalNative + private static native void native_add_field(long ptr, long extraPtr); + @CriticalNative + private static native void native_clear_fields(long ptr); + } + + private static final class FieldInt64 implements PerfettoPointer { + private static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + FieldInt64.class.getClassLoader(), native_delete()); + + // Private pointer holding Perfetto object with metadata + private final long mPtr; + + // Public pointer to Perfetto object itself + private final long mFieldPtr; + + FieldInt64() { + mPtr = native_init(); + mFieldPtr = native_get_extra_ptr(mPtr); + sRegistry.registerNativeAllocation(this, mPtr); + } + + @Override + public long getPtr() { + return mFieldPtr; + } + + public void setValue(long id, long val) { + native_set_value(mPtr, id, val); + } + + @CriticalNative + private static native long native_init(); + @CriticalNative + private static native long native_delete(); + @CriticalNative + private static native long native_get_extra_ptr(long ptr); + @CriticalNative + private static native void native_set_value(long ptr, long id, long val); + } + + private static final class FieldDouble implements PerfettoPointer { + private static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + FieldDouble.class.getClassLoader(), native_delete()); + + // Private pointer holding Perfetto object with metadata + private final long mPtr; + + // Public pointer to Perfetto object itself + private final long mFieldPtr; + + FieldDouble() { + mPtr = native_init(); + mFieldPtr = native_get_extra_ptr(mPtr); + sRegistry.registerNativeAllocation(this, mPtr); + } + + @Override + public long getPtr() { + return mFieldPtr; + } + + public void setValue(long id, double val) { + native_set_value(mPtr, id, val); + } + + @CriticalNative + private static native long native_init(); + @CriticalNative + private static native long native_delete(); + @CriticalNative + private static native long native_get_extra_ptr(long ptr); + @CriticalNative + private static native void native_set_value(long ptr, long id, double val); + } + + private static final class FieldString implements PerfettoPointer { + private static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + FieldString.class.getClassLoader(), native_delete()); + + // Private pointer holding Perfetto object with metadata + private final long mPtr; + + // Public pointer to Perfetto object itself + private final long mFieldPtr; + + FieldString() { + mPtr = native_init(); + mFieldPtr = native_get_extra_ptr(mPtr); + sRegistry.registerNativeAllocation(this, mPtr); + } + + @Override + public long getPtr() { + return mFieldPtr; + } + + public void setValue(long id, String val) { + native_set_value(mPtr, id, val); + } + + @CriticalNative + private static native long native_init(); + @CriticalNative + private static native long native_delete(); + @CriticalNative + private static native long native_get_extra_ptr(long ptr); + @FastNative + private static native void native_set_value(long ptr, long id, String val); + } + + private static final class FieldNested implements PerfettoPointer, FieldContainer { + private static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + FieldNested.class.getClassLoader(), native_delete()); + + // Private pointer holding Perfetto object with metadata + private final long mPtr; + + // Public pointer to Perfetto object itself + private final long mFieldPtr; + + FieldNested() { + mPtr = native_init(); + mFieldPtr = native_get_extra_ptr(mPtr); + sRegistry.registerNativeAllocation(this, mPtr); + } + + @Override + public long getPtr() { + return mFieldPtr; + } + + @Override + public void addField(PerfettoPointer field) { + native_add_field(mPtr, field.getPtr()); + } + + public void setId(long id) { + native_set_id(mPtr, id); + } + + @CriticalNative + private static native long native_init(); + @CriticalNative + private static native long native_delete(); + @CriticalNative + private static native long native_get_extra_ptr(long ptr); + @CriticalNative + private static native void native_add_field(long ptr, long extraPtr); + @CriticalNative + private static native void native_set_id(long ptr, long id); + } + + @CriticalNative + private static native long native_init(); + @CriticalNative + private static native long native_delete(); + @CriticalNative + private static native void native_add_arg(long ptr, long extraPtr); + @CriticalNative + private static native void native_clear_args(long ptr); +} diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig index 2a467386569d..e24f08b7dfe5 100644 --- a/core/java/android/os/flags.aconfig +++ b/core/java/android/os/flags.aconfig @@ -340,6 +340,13 @@ flag { flag { namespace: "system_performance" + name: "perfetto_sdk_tracing_v2" + description: "Tracing using Perfetto SDK API." + bug: "303199244" +} + +flag { + namespace: "system_performance" name: "telemetry_apis_framework_initialization" is_exported: true description: "Control framework initialization APIs of telemetry APIs feature." diff --git a/core/java/android/provider/BlockedNumbersManager.java b/core/java/android/provider/BlockedNumbersManager.java index aee396dec5bc..a0dc176c884b 100644 --- a/core/java/android/provider/BlockedNumbersManager.java +++ b/core/java/android/provider/BlockedNumbersManager.java @@ -357,7 +357,7 @@ public final class BlockedNumbersManager { */ private long mUntilTimestampMillis; - public BlockSuppressionStatus(boolean isSuppressed, long untilTimestampMillis) { + BlockSuppressionStatus(boolean isSuppressed, long untilTimestampMillis) { this.mIsSuppressed = isSuppressed; this.mUntilTimestampMillis = untilTimestampMillis; } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 6898fcef23ab..c1dd36101fc8 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5723,6 +5723,7 @@ public final class Settings { * The value 1 - enable, 0 - disable * @hide */ + @Readable public static final String NOTIFICATION_COOLDOWN_ENABLED = "notification_cooldown_enabled"; diff --git a/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java b/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java index b479ca7a0b6f..76ee4480c222 100644 --- a/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java +++ b/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java @@ -91,12 +91,12 @@ public final class IntrusionDetectionEvent implements Parcelable { }; /** - * Creates an IntrusionDetectionEvent object with a - * {@link SecurityEvent} object as the event source. + * Creates an IntrusionDetectionEvent object with a {@link SecurityEvent} object as the event + * source. * * @param securityEvent The SecurityEvent object. */ - public IntrusionDetectionEvent(@NonNull SecurityEvent securityEvent) { + private IntrusionDetectionEvent(@NonNull SecurityEvent securityEvent) { mType = SECURITY_EVENT; mSecurityEvent = securityEvent; mNetworkEventDns = null; @@ -104,12 +104,11 @@ public final class IntrusionDetectionEvent implements Parcelable { } /** - * Creates an IntrusionDetectionEvent object with a - * {@link DnsEvent} object as the event source. + * Creates an IntrusionDetectionEvent object with a {@link DnsEvent} object as the event source. * * @param dnsEvent The DnsEvent object. */ - public IntrusionDetectionEvent(@NonNull DnsEvent dnsEvent) { + private IntrusionDetectionEvent(@NonNull DnsEvent dnsEvent) { mType = NETWORK_EVENT_DNS; mNetworkEventDns = dnsEvent; mSecurityEvent = null; @@ -117,18 +116,52 @@ public final class IntrusionDetectionEvent implements Parcelable { } /** - * Creates an IntrusionDetectionEvent object with a - * {@link ConnectEvent} object as the event source. + * Creates an IntrusionDetectionEvent object with a {@link ConnectEvent} object as the event + * source. * * @param connectEvent The ConnectEvent object. */ - public IntrusionDetectionEvent(@NonNull ConnectEvent connectEvent) { + private IntrusionDetectionEvent(@NonNull ConnectEvent connectEvent) { mType = NETWORK_EVENT_CONNECT; mNetworkEventConnect = connectEvent; mSecurityEvent = null; mNetworkEventDns = null; } + /** + * Creates an IntrusionDetectionEvent object with a {@link SecurityEvent} object as the event + * source. + * + * @param securityEvent The SecurityEvent object. + */ + @NonNull + public static IntrusionDetectionEvent createForSecurityEvent( + @NonNull SecurityEvent securityEvent) { + return new IntrusionDetectionEvent(securityEvent); + } + + /** + * Creates an IntrusionDetectionEvent object with a {@link DnsEvent} object as the event source. + * + * @param dnsEvent The DnsEvent object. + */ + @NonNull + public static IntrusionDetectionEvent createForDnsEvent(@NonNull DnsEvent dnsEvent) { + return new IntrusionDetectionEvent(dnsEvent); + } + + /** + * Creates an IntrusionDetectionEvent object with a {@link ConnectEvent} object as the event + * source. + * + * @param connectEvent The ConnectEvent object. + */ + @NonNull + public static IntrusionDetectionEvent createForConnectEvent( + @NonNull ConnectEvent connectEvent) { + return new IntrusionDetectionEvent(connectEvent); + } + private IntrusionDetectionEvent(@NonNull Parcel in) { mType = in.readInt(); switch (mType) { diff --git a/core/java/android/security/intrusiondetection/IntrusionDetectionEventTransport.java b/core/java/android/security/intrusiondetection/IntrusionDetectionEventTransport.java index 2e2d0f7f2dd2..4755eaf8542c 100644 --- a/core/java/android/security/intrusiondetection/IntrusionDetectionEventTransport.java +++ b/core/java/android/security/intrusiondetection/IntrusionDetectionEventTransport.java @@ -44,7 +44,8 @@ import java.util.List; * which will then be delivered to the specified location. * * Usage: - * 1. Obtain an instance of {@link IntrusionDetectionEventTransport} using the constructor. + * 1. Obtain an instance of {@link IntrusionDetectionEventTransport} using the appropriate + * creation method. * 2. Initialize the transport by calling {@link #initialize()}. * 3. Add events to the transport queue using {@link #addData(List)}. * 4. Release the transport when finished by calling {@link #release()}. diff --git a/core/java/android/security/intrusiondetection/IntrusionDetectionManager.java b/core/java/android/security/intrusiondetection/IntrusionDetectionManager.java index e2463384d0c8..8a7ec0d61f52 100644 --- a/core/java/android/security/intrusiondetection/IntrusionDetectionManager.java +++ b/core/java/android/security/intrusiondetection/IntrusionDetectionManager.java @@ -230,7 +230,7 @@ public class IntrusionDetectionManager { /** * Disable intrusion detection. * If successful, IntrusionDetectionService will transition to {@link #STATE_DISABLED}. - * <p> + * * When intrusion detection is disabled, device events will no longer be collected. * Any events that have been collected but not yet sent to IntrusionDetectionEventTransport * will be transferred as a final batch. diff --git a/core/java/android/security/net/config/NetworkSecurityTrustManager.java b/core/java/android/security/net/config/NetworkSecurityTrustManager.java index d9cc82a77a85..029b674b6be1 100644 --- a/core/java/android/security/net/config/NetworkSecurityTrustManager.java +++ b/core/java/android/security/net/config/NetworkSecurityTrustManager.java @@ -16,16 +16,17 @@ package android.security.net.config; +import android.util.ArrayMap; + import com.android.org.conscrypt.TrustManagerImpl; -import android.util.ArrayMap; import java.io.IOException; import java.net.Socket; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.MessageDigest; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; import java.util.List; import java.util.Map; import java.util.Set; @@ -105,7 +106,7 @@ public class NetworkSecurityTrustManager extends X509ExtendedTrustManager { /** * Hostname aware version of {@link #checkServerTrusted(X509Certificate[], String)}. - * This interface is used by conscrypt and android.net.http.X509TrustManagerExtensions do not + * This interface is used by Conscrypt and android.net.http.X509TrustManagerExtensions do not * modify without modifying those callers. */ public List<X509Certificate> checkServerTrusted(X509Certificate[] certs, String authType, @@ -115,6 +116,19 @@ public class NetworkSecurityTrustManager extends X509ExtendedTrustManager { return trustedChain; } + /** + * This interface is used by Conscrypt and android.net.http.X509TrustManagerExtensions do not + * modify without modifying those callers. + */ + public List<X509Certificate> checkServerTrusted(X509Certificate[] certs, + byte[] ocspData, byte[] tlsSctData, String authType, + String host) throws CertificateException { + List<X509Certificate> trustedChain = mDelegate.checkServerTrusted( + certs, ocspData, tlsSctData, authType, host); + checkPins(trustedChain); + return trustedChain; + } + private void checkPins(List<X509Certificate> chain) throws CertificateException { PinSet pinSet = mNetworkSecurityConfig.getPins(); if (pinSet.pins.isEmpty() diff --git a/core/java/android/security/net/config/OWNERS b/core/java/android/security/net/config/OWNERS index 85ce3c63f18b..e945ff98a96f 100644 --- a/core/java/android/security/net/config/OWNERS +++ b/core/java/android/security/net/config/OWNERS @@ -1,5 +1,6 @@ -# Bug component: 36824 -set noparent +# Bug component: 1479456 -cbrubaker@google.com +bessiej@google.com brambonne@google.com +sandrom@google.com +tweek@google.com diff --git a/core/java/android/security/net/config/RootTrustManager.java b/core/java/android/security/net/config/RootTrustManager.java index 58dc4ba8df21..a1bdec5280db 100644 --- a/core/java/android/security/net/config/RootTrustManager.java +++ b/core/java/android/security/net/config/RootTrustManager.java @@ -120,7 +120,7 @@ public class RootTrustManager extends X509ExtendedTrustManager { /** * Hostname aware version of {@link #checkServerTrusted(X509Certificate[], String)}. - * This interface is used by conscrypt and android.net.http.X509TrustManagerExtensions do not + * This interface is used by Conscrypt and android.net.http.X509TrustManagerExtensions do not * modify without modifying those callers. */ @UnsupportedAppUsage @@ -134,6 +134,22 @@ public class RootTrustManager extends X509ExtendedTrustManager { return config.getTrustManager().checkServerTrusted(certs, authType, hostname); } + /** + * This interface is used by Conscrypt and android.net.http.X509TrustManagerExtensions do not + * modify without modifying those callers. + */ + public List<X509Certificate> checkServerTrusted(X509Certificate[] certs, + byte[] ocspData, byte[] tlsSctData, String authType, + String hostname) throws CertificateException { + if (hostname == null && mConfig.hasPerDomainConfigs()) { + throw new CertificateException( + "Domain specific configurations require that the hostname be provided"); + } + NetworkSecurityConfig config = mConfig.getConfigForHostname(hostname); + return config.getTrustManager().checkServerTrusted( + certs, ocspData, tlsSctData, authType, hostname); + } + @Override public X509Certificate[] getAcceptedIssuers() { // getAcceptedIssuers is meant to be used to determine which trust anchors the server will diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index 6c50b5f945a5..992790e092d1 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -240,6 +240,7 @@ public final class Choreographer { * stuffing events. */ public void reset() { + isStuffed.set(false); isRecovering = false; numberWaitsForNextVsync = 0; } diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 072a037aa84a..2b4087439323 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -722,6 +722,9 @@ interface IWindowManager */ void setDisplayImePolicy(int displayId, int imePolicy); + /** Called when the expanded state of notification shade is changed. */ + void onNotificationShadeExpanded(IBinder token, boolean expanded); + /** * Waits until input information has been sent from WindowManager to native InputManager, * optionally waiting for animations to complete. diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 38e4e2760d25..ad43c7b7cdc3 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -2590,6 +2590,32 @@ public class KeyEvent extends InputEvent implements Parcelable { return keyCode == KeyEvent.KEYCODE_ALT_LEFT || keyCode == KeyEvent.KEYCODE_ALT_RIGHT; } + /** + * Returns whether the key code passed as argument is allowed for visible background users. + * Visible background users are expected to run on secondary displays with certain limitations + * on system keys. + * + * @hide + */ + public static boolean isVisibleBackgroundUserAllowedKey(int keyCode) { + switch (keyCode) { + case KeyEvent.KEYCODE_POWER: + case KeyEvent.KEYCODE_SLEEP: + case KeyEvent.KEYCODE_WAKEUP: + case KeyEvent.KEYCODE_CALL: + case KeyEvent.KEYCODE_ENDCALL: + case KeyEvent.KEYCODE_ASSIST: + case KeyEvent.KEYCODE_VOICE_ASSIST: + case KeyEvent.KEYCODE_MUTE: + case KeyEvent.KEYCODE_VOLUME_MUTE: + case KeyEvent.KEYCODE_RECENT_APPS: + case KeyEvent.KEYCODE_APP_SWITCH: + case KeyEvent.KEYCODE_NOTIFICATION: + return false; + } + return true; + } + /** {@inheritDoc} */ @Override public final int getDeviceId() { diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig index 3b77b1f65dac..b5582ff9d9be 100644 --- a/core/java/android/window/flags/lse_desktop_experience.aconfig +++ b/core/java/android/window/flags/lse_desktop_experience.aconfig @@ -485,6 +485,13 @@ flag { } flag { + name: "enable_multiple_desktops_backend" + namespace: "lse_desktop_experience" + description: "Enable multiple desktop sessions for desktop windowing (backend)." + bug: "362720497" +} + +flag { name: "enable_connected_displays_dnd" namespace: "lse_desktop_experience" description: "Enable drag-and-drop between connected displays." diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index c1ed51264e23..f346544780b3 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -235,6 +235,17 @@ flag { } flag { + name: "scheduling_for_notification_shade" + namespace: "windowing_frontend" + description: "Demote top-app when notification shade is expanded" + bug: "362467878" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "release_snapshot_aggressively" namespace: "windowing_frontend" description: "Actively release task snapshot memory" diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java index d49afa735646..f443b0adcb9d 100644 --- a/core/java/com/android/internal/util/LatencyTracker.java +++ b/core/java/com/android/internal/util/LatencyTracker.java @@ -38,6 +38,7 @@ import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPOR import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN; import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_CAMERA_CHECK; import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_SENSOR; +import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHADE_WINDOW_DISPLAY_CHANGE; import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_BACK_ARROW; import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR; import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION; @@ -257,6 +258,14 @@ public class LatencyTracker { */ public static final int ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME = 28; + /** + * Time it takes for the shade window to move display after a user interaction. + * <p> + * This starts when the user does an interaction that triggers the window reparenting, and + * finishes after the first doFrame done with the new display configuration. + */ + public static final int ACTION_SHADE_WINDOW_DISPLAY_CHANGE = 29; + private static final int[] ACTIONS_ALL = { ACTION_EXPAND_PANEL, ACTION_TOGGLE_RECENTS, @@ -287,6 +296,7 @@ public class LatencyTracker { ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE, ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN, ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME, + ACTION_SHADE_WINDOW_DISPLAY_CHANGE, }; /** @hide */ @@ -320,6 +330,7 @@ public class LatencyTracker { ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE, ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN, ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME, + ACTION_SHADE_WINDOW_DISPLAY_CHANGE, }) @Retention(RetentionPolicy.SOURCE) public @interface Action { @@ -356,6 +367,7 @@ public class LatencyTracker { UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE, UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN, UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME, + UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHADE_WINDOW_DISPLAY_CHANGE, }; private final Object mLock = new Object(); @@ -554,6 +566,8 @@ public class LatencyTracker { return "ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN"; case UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME: return "ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME"; + case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHADE_WINDOW_DISPLAY_CHANGE: + return "ACTION_SHADE_WINDOW_DISPLAY_CHANGE"; default: throw new IllegalArgumentException("Invalid action"); } diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeTouchHelper.java b/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeTouchHelper.java index 39a2ab3010ac..43118a0800fb 100644 --- a/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeTouchHelper.java +++ b/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeTouchHelper.java @@ -30,7 +30,7 @@ import com.android.internal.widget.ExploreByTouchHelper; import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.semantics.AccessibilitySemantics; -import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics.Mode; +import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent.Mode; import java.util.HashSet; import java.util.List; diff --git a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java index 60767ed9eb00..fb560a568a9c 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java +++ b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java @@ -62,7 +62,7 @@ public class CoreDocument { // We also keep a more fine-grained BUILD number, exposed as // ID_API_LEVEL = DOCUMENT_API_LEVEL + BUILD - static final float BUILD = 0.0f; + static final float BUILD = 0.1f; @NonNull ArrayList<Operation> mOperations = new ArrayList<>(); @@ -123,6 +123,11 @@ public class CoreDocument { return mWidth; } + /** + * Set the viewport width of the document + * + * @param width document width + */ public void setWidth(int width) { this.mWidth = width; mRemoteComposeState.setWindowWidth(width); @@ -132,6 +137,11 @@ public class CoreDocument { return mHeight; } + /** + * Set the viewport height of the document + * + * @param height document height + */ public void setHeight(int height) { this.mHeight = height; mRemoteComposeState.setWindowHeight(height); @@ -395,6 +405,11 @@ public class CoreDocument { // ============== Haptic support ================== public interface HapticEngine { + /** + * Implements a haptic effect + * + * @param type the type of effect + */ void haptic(int type); } @@ -404,6 +419,11 @@ public class CoreDocument { mHapticEngine = engine; } + /** + * Execute an haptic command + * + * @param type the type of haptic pre-defined effect + */ public void haptic(int type) { if (mHapticEngine != null) { mHapticEngine.haptic(type); @@ -412,12 +432,23 @@ public class CoreDocument { // ============== Haptic support ================== - public void appliedTouchOperation(Component operation) { - mAppliedTouchOperations.add(operation); + /** + * To signal that the given component will apply the touch operation + * + * @param component the component applying the touch + */ + public void appliedTouchOperation(Component component) { + mAppliedTouchOperations.add(component); } /** Callback interface for host actions */ public interface ActionCallback { + /** + * Callback for actions + * + * @param name the action name + * @param value the payload of the action + */ void onAction(@NonNull String name, Object value); } @@ -450,7 +481,14 @@ public class CoreDocument { mActionListeners.clear(); } + /** Id Actions */ public interface IdActionCallback { + /** + * Callback on Id Actions + * + * @param id the actio id triggered + * @param metadata optional metadata + */ void onAction(int id, @Nullable String metadata); } @@ -530,10 +568,20 @@ public class CoreDocument { return mTop; } + /** + * Returns the width of the click area + * + * @return the width of the click area + */ public float width() { return Math.max(0, mRight - mLeft); } + /** + * Returns the height of the click area + * + * @return the height of the click area + */ public float height() { return Math.max(0, mBottom - mTop); } @@ -816,6 +864,7 @@ public class CoreDocument { for (ClickAreaRepresentation clickArea : mClickAreas) { if (clickArea.mId == id) { warnClickListeners(clickArea); + return; } } for (IdActionCallback listener : mIdActionListeners) { @@ -1127,6 +1176,11 @@ public class CoreDocument { return count; } + /** + * Returns a list of useful statistics for the runtime document + * + * @return + */ @NonNull public String[] getStats() { ArrayList<String> ret = new ArrayList<>(); @@ -1145,8 +1199,8 @@ public class CoreDocument { values[0] += 1; values[1] += sizeOfComponent(mOperation, buffer); - if (mOperation instanceof Component) { - Component com = (Component) mOperation; + if (mOperation instanceof Container) { + Container com = (Container) mOperation; count += addChildren(com, map, buffer); } else if (mOperation instanceof LoopOperation) { LoopOperation com = (LoopOperation) mOperation; @@ -1172,35 +1226,9 @@ public class CoreDocument { } private int addChildren( - @NonNull Component base, @NonNull HashMap<String, int[]> map, @NonNull WireBuffer tmp) { - int count = base.mList.size(); - for (Operation mOperation : base.mList) { - Class<? extends Operation> c = mOperation.getClass(); - int[] values; - if (map.containsKey(c.getSimpleName())) { - values = map.get(c.getSimpleName()); - } else { - values = new int[2]; - map.put(c.getSimpleName(), values); - } - values[0] += 1; - values[1] += sizeOfComponent(mOperation, tmp); - if (mOperation instanceof Component) { - count += addChildren((Component) mOperation, map, tmp); - } - if (mOperation instanceof LoopOperation) { - count += addChildren((LoopOperation) mOperation, map, tmp); - } - } - return count; - } - - private int addChildren( - @NonNull LoopOperation base, - @NonNull HashMap<String, int[]> map, - @NonNull WireBuffer tmp) { - int count = base.mList.size(); - for (Operation mOperation : base.mList) { + @NonNull Container base, @NonNull HashMap<String, int[]> map, @NonNull WireBuffer tmp) { + int count = base.getList().size(); + for (Operation mOperation : base.getList()) { Class<? extends Operation> c = mOperation.getClass(); int[] values; if (map.containsKey(c.getSimpleName())) { @@ -1211,39 +1239,42 @@ public class CoreDocument { } values[0] += 1; values[1] += sizeOfComponent(mOperation, tmp); - if (mOperation instanceof Component) { - count += addChildren((Component) mOperation, map, tmp); - } - if (mOperation instanceof LoopOperation) { - count += addChildren((LoopOperation) mOperation, map, tmp); + if (mOperation instanceof Container) { + count += addChildren((Container) mOperation, map, tmp); } } return count; } + /** + * Returns a string representation of the operations, traversing the list of operations & + * containers + * + * @return + */ @NonNull public String toNestedString() { StringBuilder ret = new StringBuilder(); for (Operation mOperation : mOperations) { ret.append(mOperation.toString()); ret.append("\n"); - if (mOperation instanceof Component) { - toNestedString((Component) mOperation, ret, " "); + if (mOperation instanceof Container) { + toNestedString((Container) mOperation, ret, " "); } } return ret.toString(); } private void toNestedString( - @NonNull Component base, @NonNull StringBuilder ret, String indent) { - for (Operation mOperation : base.mList) { + @NonNull Container base, @NonNull StringBuilder ret, String indent) { + for (Operation mOperation : base.getList()) { for (String line : mOperation.toString().split("\n")) { ret.append(indent); ret.append(line); ret.append("\n"); } - if (mOperation instanceof Component) { - toNestedString((Component) mOperation, ret, indent + " "); + if (mOperation instanceof Container) { + toNestedString((Container) mOperation, ret, indent + " "); } } } @@ -1255,6 +1286,12 @@ public class CoreDocument { /** defines if a shader can be run */ public interface ShaderControl { + /** + * validate if a shader can run in the document + * + * @param shader the source of the shader + * @return true if the shader is allowed to run + */ boolean isShaderValid(String shader); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/Operations.java b/core/java/com/android/internal/widget/remotecompose/core/Operations.java index d9f12cb71d53..9a37a22390a2 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/Operations.java +++ b/core/java/com/android/internal/widget/remotecompose/core/Operations.java @@ -55,6 +55,8 @@ import com.android.internal.widget.remotecompose.core.operations.MatrixSkew; import com.android.internal.widget.remotecompose.core.operations.MatrixTranslate; import com.android.internal.widget.remotecompose.core.operations.NamedVariable; import com.android.internal.widget.remotecompose.core.operations.PaintData; +import com.android.internal.widget.remotecompose.core.operations.ParticlesCreate; +import com.android.internal.widget.remotecompose.core.operations.ParticlesLoop; import com.android.internal.widget.remotecompose.core.operations.PathAppend; import com.android.internal.widget.remotecompose.core.operations.PathCreate; import com.android.internal.widget.remotecompose.core.operations.PathData; @@ -75,6 +77,8 @@ import com.android.internal.widget.remotecompose.core.operations.layout.CanvasCo import com.android.internal.widget.remotecompose.core.operations.layout.ClickModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.ComponentStart; import com.android.internal.widget.remotecompose.core.operations.layout.ContainerEnd; +import com.android.internal.widget.remotecompose.core.operations.layout.ImpulseOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.ImpulseProcess; import com.android.internal.widget.remotecompose.core.operations.layout.LayoutComponentContent; import com.android.internal.widget.remotecompose.core.operations.layout.LoopOperation; import com.android.internal.widget.remotecompose.core.operations.layout.RootLayoutComponent; @@ -188,6 +192,11 @@ public class Operations { public static final int PATH_TWEEN = 158; public static final int PATH_CREATE = 159; public static final int PATH_ADD = 160; + public static final int PARTICLE_CREATE = 161; + public static final int PARTICLE_PROCESS = 162; + public static final int PARTICLE_LOOP = 163; + public static final int IMPULSE_START = 164; + public static final int IMPULSE_PROCESS = 165; ///////////////////////////////////////// ====================== @@ -366,6 +375,10 @@ public class Operations { map.put(PATH_TWEEN, PathTween::read); map.put(PATH_CREATE, PathCreate::read); map.put(PATH_ADD, PathAppend::read); + map.put(IMPULSE_START, ImpulseOperation::read); + map.put(IMPULSE_PROCESS, ImpulseProcess::read); + map.put(PARTICLE_CREATE, ParticlesCreate::read); + map.put(PARTICLE_LOOP, ParticlesLoop::read); map.put(ACCESSIBILITY_SEMANTICS, CoreSemantics::read); // map.put(ACCESSIBILITY_CUSTOM_ACTION, CoreSemantics::read); diff --git a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java index 4a40a31ef6ab..49a0457c3595 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java +++ b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java @@ -33,10 +33,16 @@ public abstract class PaintContext { return mContext; } + /** + * Returns true if the needsRepaint flag is set + * + * @return true if the document asks to be repainted + */ public boolean doesNeedsRepaint() { return mNeedsRepaint; } + /** Clear the needsRepaint flag */ public void clearNeedsRepaint() { mNeedsRepaint = false; } @@ -65,6 +71,20 @@ public abstract class PaintContext { matrixSave(); } + /** + * Draw a bitmap + * + * @param imageId + * @param srcLeft + * @param srcTop + * @param srcRight + * @param srcBottom + * @param dstLeft + * @param dstTop + * @param dstRight + * @param dstBottom + * @param cdId + */ public abstract void drawBitmap( int imageId, int srcLeft, @@ -77,26 +97,105 @@ public abstract class PaintContext { int dstBottom, int cdId); + /** + * scale the following commands + * + * @param scaleX horizontal scale factor + * @param scaleY vertical scale factor + */ public abstract void scale(float scaleX, float scaleY); + /** + * Rotate the following commands + * + * @param translateX horizontal translation + * @param translateY vertical translation + */ public abstract void translate(float translateX, float translateY); + /** + * Draw an arc + * + * @param left + * @param top + * @param right + * @param bottom + * @param startAngle + * @param sweepAngle + */ public abstract void drawArc( float left, float top, float right, float bottom, float startAngle, float sweepAngle); + /** + * Draw a sector + * + * @param left + * @param top + * @param right + * @param bottom + * @param startAngle + * @param sweepAngle + */ public abstract void drawSector( float left, float top, float right, float bottom, float startAngle, float sweepAngle); + /** + * Draw a bitmap + * + * @param id + * @param left + * @param top + * @param right + * @param bottom + */ public abstract void drawBitmap(int id, float left, float top, float right, float bottom); + /** + * Draw a circle + * + * @param centerX + * @param centerY + * @param radius + */ public abstract void drawCircle(float centerX, float centerY, float radius); + /** + * Draw a line + * + * @param x1 + * @param y1 + * @param x2 + * @param y2 + */ public abstract void drawLine(float x1, float y1, float x2, float y2); + /** + * Draw an oval + * + * @param left + * @param top + * @param right + * @param bottom + */ public abstract void drawOval(float left, float top, float right, float bottom); + /** + * Draw a path + * + * @param id the path id + * @param start starting point of the path where we start drawing it + * @param end ending point of the path where we stop drawing it + */ public abstract void drawPath(int id, float start, float end); + /** + * Draw a rectangle + * + * @param left left coordinate of the rectangle + * @param top top coordinate of the rectangle + * @param right right coordinate of the rectangle + * @param bottom bottom coordinate of the rectangle + */ public abstract void drawRect(float left, float top, float right, float bottom); /** this caches the paint to a paint stack */ @@ -105,9 +204,27 @@ public abstract class PaintContext { /** This restores the paint form the paint stack */ public abstract void restorePaint(); + /** + * draw a round rect + * + * @param left left coordinate of the rectangle + * @param top top coordinate of the rectangle + * @param right right coordinate of the rectangle + * @param bottom bottom coordinate of the rectangle + * @param radiusX horizontal radius of the rounded corner + * @param radiusY vertical radius of the rounded corner + */ public abstract void drawRoundRect( float left, float top, float right, float bottom, float radiusX, float radiusY); + /** + * Draw the text glyphs on the provided path + * + * @param textId id of the text + * @param pathId id of the path + * @param hOffset horizontal offset + * @param vOffset vertical offset + */ public abstract void drawTextOnPath(int textId, int pathId, float hOffset, float vOffset); /** @@ -158,6 +275,14 @@ public abstract class PaintContext { public abstract void drawTweenPath( int path1Id, int path2Id, float tween, float start, float stop); + /** + * Interpolate between two path and return the resulting path + * + * @param out the interpolated path + * @param path1 start path + * @param path2 end path + * @param tween interpolation value from 0 (start path) to 1 (end path) + */ public abstract void tweenPath(int out, int path1, int path2, float tween); /** @@ -275,12 +400,33 @@ public abstract class PaintContext { System.out.println("[LOG] " + content); } + /** Indicates the document needs to be repainted */ public void needsRepaint() { mNeedsRepaint = true; } + /** + * Starts a graphics layer + * + * @param w + * @param h + */ public abstract void startGraphicsLayer(int w, int h); + /** + * Starts a graphics layer + * + * @param scaleX + * @param scaleY + * @param rotationX + * @param rotationY + * @param rotationZ + * @param shadowElevation + * @param transformOriginX + * @param transformOriginY + * @param alpha + * @param renderEffectId + */ public abstract void setGraphicsLayer( float scaleX, float scaleY, @@ -293,6 +439,7 @@ public abstract class PaintContext { float alpha, int renderEffectId); + /** Ends a graphics layer */ public abstract void endGraphicsLayer(); public boolean isVisualDebug() { diff --git a/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java b/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java index cfdd52212b03..f355676be63e 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java @@ -39,6 +39,11 @@ public abstract class PaintOperation extends Operation { return indent + toString(); } + /** + * Paint the operation in the context + * + * @param context painting context + */ public abstract void paint(@NonNull PaintContext context); /** diff --git a/core/java/com/android/internal/widget/remotecompose/core/Platform.java b/core/java/com/android/internal/widget/remotecompose/core/Platform.java index dcb8efebeecc..e4a063d7d6ff 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/Platform.java +++ b/core/java/com/android/internal/widget/remotecompose/core/Platform.java @@ -20,13 +20,38 @@ import android.annotation.Nullable; /** Services that are needed to be provided by the platform during encoding. */ public interface Platform { + + /** + * Converts a platform-specific image object into a platform-independent byte buffer + * + * @param image + * @return + */ @Nullable byte[] imageToByteArray(@NonNull Object image); + /** + * Returns the width of a platform-specific image object + * + * @param image platform-specific image object + * @return the width of the image in pixels + */ int getImageWidth(@NonNull Object image); + /** + * Returns the height of a platform-specific image object + * + * @param image platform-specific image object + * @return the height of the image in pixels + */ int getImageHeight(@NonNull Object image); + /** + * Converts a platform-specific path object into a platform-independent float buffer + * + * @param path + * @return + */ @Nullable float[] pathToFloatArray(@NonNull Object path); @@ -38,6 +63,12 @@ public interface Platform { TODO, } + /** + * Log a message + * + * @param category + * @param message + */ void log(LogCategory category, String message); Platform None = diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java index fc1e36d45a81..39cc997fadc2 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java +++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java @@ -58,6 +58,8 @@ import com.android.internal.widget.remotecompose.core.operations.MatrixSkew; import com.android.internal.widget.remotecompose.core.operations.MatrixTranslate; import com.android.internal.widget.remotecompose.core.operations.NamedVariable; import com.android.internal.widget.remotecompose.core.operations.PaintData; +import com.android.internal.widget.remotecompose.core.operations.ParticlesCreate; +import com.android.internal.widget.remotecompose.core.operations.ParticlesLoop; import com.android.internal.widget.remotecompose.core.operations.PathAppend; import com.android.internal.widget.remotecompose.core.operations.PathCreate; import com.android.internal.widget.remotecompose.core.operations.PathData; @@ -77,6 +79,8 @@ import com.android.internal.widget.remotecompose.core.operations.Utils; import com.android.internal.widget.remotecompose.core.operations.layout.CanvasContent; import com.android.internal.widget.remotecompose.core.operations.layout.ComponentStart; import com.android.internal.widget.remotecompose.core.operations.layout.ContainerEnd; +import com.android.internal.widget.remotecompose.core.operations.layout.ImpulseOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.ImpulseProcess; import com.android.internal.widget.remotecompose.core.operations.layout.LayoutComponentContent; import com.android.internal.widget.remotecompose.core.operations.layout.LoopOperation; import com.android.internal.widget.remotecompose.core.operations.layout.RootLayoutComponent; @@ -411,11 +415,7 @@ public class RemoteComposeBuffer { BitmapData.apply( mBuffer, imageId, imageWidth, imageHeight, data); // todo: potential npe } - int contentDescriptionId = 0; - if (contentDescription != null) { - contentDescriptionId = addText(contentDescription); - } - DrawBitmap.apply(mBuffer, imageId, left, top, right, bottom, contentDescriptionId); + addDrawBitmap(imageId, left, top, right, bottom, contentDescription); } /** @@ -441,6 +441,24 @@ public class RemoteComposeBuffer { } /** + * @param imageId The Id bitmap to be drawn + * @param left left coordinate of rectangle that the bitmap will be to fit into + * @param top top coordinate of rectangle that the bitmap will be to fit into + * @param contentDescription content description of the image + */ + public void addDrawBitmap( + int imageId, float left, float top, @Nullable String contentDescription) { + int imageWidth = mPlatform.getImageWidth(imageId); + int imageHeight = mPlatform.getImageHeight(imageId); + int contentDescriptionId = 0; + if (contentDescription != null) { + contentDescriptionId = addText(contentDescription); + } + DrawBitmap.apply( + mBuffer, imageId, left, top, imageWidth, imageHeight, contentDescriptionId); + } + + /** * @param image The bitmap to be drawn * @param srcLeft left coordinate in the source bitmap will be to extracted * @param srcTop top coordinate in the source bitmap will be to extracted @@ -537,7 +555,7 @@ public class RemoteComposeBuffer { } /** - * This defines the name of the color given the id. + * This defines the name of the bitmap given the id. * * @param id of the Bitmap * @param name Name of the color @@ -2060,4 +2078,61 @@ public class RemoteComposeBuffer { public int nextId() { return mRemoteComposeState.nextId(); } + + private boolean mInImpulseProcess = false; + + /** + * add an impulse. (must be followed by impulse end) + * + * @param duration duration of the impulse + * @param start the start time + */ + public void addImpulse(float duration, float start) { + ImpulseOperation.apply(mBuffer, duration, start); + mInImpulseProcess = false; + } + + /** add an impulse process */ + public void addImpulseProcess() { + ImpulseProcess.apply(mBuffer); + mInImpulseProcess = true; + } + + /** Add an impulse end */ + public void addImpulseEnd() { + ContainerEnd.apply(mBuffer); + if (mInImpulseProcess) { + ContainerEnd.apply(mBuffer); + } + mInImpulseProcess = false; + } + + /** + * Start a particle engine container & initial setup + * + * @param id the particle engine id + * @param varIds list of variable ids + * @param initialExpressions the expressions used to initialize the variables + * @param particleCount the number of particles to draw + */ + public void addParticles( + int id, int[] varIds, float[][] initialExpressions, int particleCount) { + ParticlesCreate.apply(mBuffer, id, varIds, initialExpressions, particleCount); + } + + /** + * Setup the particle engine loop + * + * @param id the particle engine id + * @param restart value on restart + * @param expressions the expressions used to update the variables during the particles run + */ + public void addParticlesLoop(int id, float[] restart, float[][] expressions) { + ParticlesLoop.apply(mBuffer, id, restart, expressions); + } + + /** Closes the particle engine container */ + public void addParticleLoopEnd() { + ContainerEnd.apply(mBuffer); + } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java index 63469aabaed5..ec336633e960 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java +++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java @@ -40,12 +40,12 @@ import java.time.ZoneOffset; * <p>We also contain a PaintContext, so that any operation can draw as needed. */ public abstract class RemoteContext { - private static final int MAX_OP_COUNT = 100_000; // Maximum cmds per frame + private static final int MAX_OP_COUNT = 20_000; // Maximum cmds per frame protected @NonNull CoreDocument mDocument = new CoreDocument(); // todo: is this a valid way to initialize? bbade@ public @NonNull RemoteComposeState mRemoteComposeState = new RemoteComposeState(); // todo, is this a valid use of RemoteComposeState -- bbade@ - long mStart = System.nanoTime(); // todo This should be set at a hi level + @Nullable protected PaintContext mPaintContext = null; protected float mDensity = 2.75f; @@ -71,6 +71,11 @@ public abstract class RemoteContext { return mDensity; } + /** + * Set the density of the document + * + * @param density + */ public void setDensity(float density) { if (density > 0) { mDensity = density; @@ -142,7 +147,6 @@ public abstract class RemoteContext { * @return a monotonic time in seconds (arbitrary zero point) */ public float getAnimationTime() { - mAnimationTime = (System.nanoTime() - mStart) * 1E-9f; // Eliminate return mAnimationTime; } @@ -243,6 +247,11 @@ public abstract class RemoteContext { public abstract @Nullable Object getObject(int mId); + /** + * Add a touch listener to the context + * + * @param touchExpression + */ public void addTouchListener(TouchListener touchExpression) {} /** @@ -337,6 +346,16 @@ public abstract class RemoteContext { // Operations /////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Set the main information about a document + * + * @param majorVersion major version of the document protocol used + * @param minorVersion minor version of the document protocol used + * @param patchVersion patch version of the document protocol used + * @param width original width of the document when created + * @param height original height of the document when created + * @param capabilities bitmask of capabilities used in the document (TBD) + */ public void header( int majorVersion, int minorVersion, @@ -552,6 +571,15 @@ public abstract class RemoteContext { /** Defines when the last build was made */ public static final int ID_API_LEVEL = 28; + /** Defines when the TOUCH EVENT HAPPENED */ + public static final int ID_TOUCH_EVENT_TIME = 29; + + /** Animation time in seconds */ + public static final int ID_ANIMATION_TIME = 30; + + /** The delta between current and last Frame */ + public static final int ID_ANIMATION_DELTA_TIME = 31; + public static final float FLOAT_DENSITY = Utils.asNan(ID_DENSITY); /** CONTINUOUS_SEC is seconds from midnight looping every hour 0-3600 */ @@ -595,6 +623,15 @@ public abstract class RemoteContext { /** TOUCH_VEL_Y is the x velocity of the touch */ public static final float FLOAT_TOUCH_VEL_Y = Utils.asNan(ID_TOUCH_VEL_Y); + /** TOUCH_EVENT_TIME the time of the touch */ + public static final float FLOAT_TOUCH_EVENT_TIME = Utils.asNan(ID_TOUCH_EVENT_TIME); + + /** Animation time in seconds */ + public static final float FLOAT_ANIMATION_TIME = Utils.asNan(ID_ANIMATION_TIME); + + /** Animation time in seconds */ + public static final float FLOAT_ANIMATION_DELTA_TIME = Utils.asNan(ID_ANIMATION_DELTA_TIME); + /** X acceleration sensor value in M/s^2 */ public static final float FLOAT_ACCELERATION_X = Utils.asNan(ID_ACCELERATION_X); diff --git a/core/java/com/android/internal/widget/remotecompose/core/SerializableToString.java b/core/java/com/android/internal/widget/remotecompose/core/SerializableToString.java index 79ac789a454e..37896211bcef 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/SerializableToString.java +++ b/core/java/com/android/internal/widget/remotecompose/core/SerializableToString.java @@ -20,5 +20,11 @@ import android.annotation.NonNull; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; public interface SerializableToString { + /** + * Returns a stable string representation of an operation + * + * @param indent the indentation for that operation + * @param serializer the serializer object + */ void serializeToString(int indent, @NonNull StringSerializer serializer); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/TouchListener.java b/core/java/com/android/internal/widget/remotecompose/core/TouchListener.java index 611ba97c10cb..0a1be82bc53a 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/TouchListener.java +++ b/core/java/com/android/internal/widget/remotecompose/core/TouchListener.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core; +import com.android.internal.widget.remotecompose.core.operations.layout.Component; + /** Interface used by objects to register for touch events */ public interface TouchListener { /** @@ -45,4 +47,11 @@ public interface TouchListener { * @param y the y coord of the drag */ void touchDrag(RemoteContext context, float x, float y); + + /** + * Called after the touch event handler is inflated + * + * @param component component it is under + */ + void setComponent(Component component); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentationBuilder.java b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentationBuilder.java index 0174ce531d3f..0972e05e39b6 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentationBuilder.java +++ b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentationBuilder.java @@ -18,11 +18,33 @@ package com.android.internal.widget.remotecompose.core.documentation; import android.annotation.NonNull; public interface DocumentationBuilder { + + /** + * Add arbitrary text to the documentation + * + * @param value + */ void add(@NonNull String value); + /** + * Add the operation to the documentation + * + * @param category category of the operation + * @param id the OPCODE of the operation + * @param name the name of the operation + * @return a DocumentedOperation + */ @NonNull DocumentedOperation operation(@NonNull String category, int id, @NonNull String name); + /** + * Add the operation to the documentation as a Work in Progress (WIP) operation + * + * @param category category of the operation + * @param id the OPCODE of the operation + * @param name the name of the operation + * @return a DocumentedOperation + */ @NonNull DocumentedOperation wipOperation(@NonNull String category, int id, @NonNull String name); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedCompanionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedCompanionOperation.java index 2806a5e1ad1d..487ea2ebfacb 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedCompanionOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedCompanionOperation.java @@ -18,5 +18,10 @@ package com.android.internal.widget.remotecompose.core.documentation; import android.annotation.NonNull; public interface DocumentedCompanionOperation { + /** + * A callback to populate the documentation of an operation + * + * @param doc the document being built + */ void documentation(@NonNull DocumentationBuilder doc); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedOperation.java b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedOperation.java index bfab62365736..ffe887156e40 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedOperation.java @@ -49,6 +49,12 @@ public class DocumentedOperation { int mExamplesWidth = 100; int mExamplesHeight = 100; + /** + * Returns the string representation of a field type + * + * @param type + * @return + */ @NonNull public static String getType(int type) { switch (type) { @@ -117,6 +123,11 @@ public class DocumentedOperation { return mVarSize; } + /** + * Returns the size of the operation fields + * + * @return size in bytes + */ public int getSizeFields() { int size = 0; mVarSize = ""; @@ -152,12 +163,29 @@ public class DocumentedOperation { return mExamplesHeight; } + /** + * Document a field of the operation + * + * @param type + * @param name + * @param description + * @return + */ @NonNull public DocumentedOperation field(int type, @NonNull String name, @NonNull String description) { mFields.add(new OperationField(type, name, description)); return this; } + /** + * Document a field of the operation + * + * @param type + * @param name + * @param varSize + * @param description + * @return + */ @NonNull public DocumentedOperation field( int type, @NonNull String name, @NonNull String varSize, @NonNull String description) { @@ -165,6 +193,13 @@ public class DocumentedOperation { return this; } + /** + * Add possible values for the operation field + * + * @param name + * @param value + * @return + */ @NonNull public DocumentedOperation possibleValues(@NonNull String name, int value) { if (!mFields.isEmpty()) { @@ -173,24 +208,50 @@ public class DocumentedOperation { return this; } + /** + * Add a description + * + * @param description + * @return + */ @NonNull public DocumentedOperation description(@NonNull String description) { mDescription = description; return this; } + /** + * Add arbitrary text as examples + * + * @param examples + * @return + */ @NonNull public DocumentedOperation examples(@NonNull String examples) { mTextExamples = examples; return this; } + /** + * Add an example image + * + * @param name the title of the image + * @param imagePath the path of the image + * @return + */ @NonNull public DocumentedOperation exampleImage(@NonNull String name, @NonNull String imagePath) { mExamples.add(new StringPair(name, imagePath)); return this; } + /** + * Add examples with a given size + * + * @param width + * @param height + * @return + */ @NonNull public DocumentedOperation examplesDimension(int width, int height) { mExamplesWidth = width; diff --git a/core/java/com/android/internal/widget/remotecompose/core/documentation/OperationField.java b/core/java/com/android/internal/widget/remotecompose/core/documentation/OperationField.java index 9febcfe57047..e120f3150a96 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/documentation/OperationField.java +++ b/core/java/com/android/internal/widget/remotecompose/core/documentation/OperationField.java @@ -61,10 +61,21 @@ public class OperationField { return mPossibleValues; } + /** + * Add possible values for a field + * + * @param name + * @param value + */ public void possibleValue(@NonNull String name, @NonNull String value) { mPossibleValues.add(new StringPair(name, value)); } + /** + * Return true if the field has enumerated values + * + * @return true if enumerated values, false otherwise + */ public boolean hasEnumeratedValues() { return !mPossibleValues.isEmpty(); } @@ -74,6 +85,11 @@ public class OperationField { return mVarSize; } + /** + * Returns the size in byte of the field depending on its type, or -1 if unknown + * + * @return the size in bytes + */ public int getSize() { switch (mType) { case DocumentedOperation.BYTE: diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java index 4c9602572721..98c2745380d7 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java @@ -135,6 +135,15 @@ public class Header extends Operation implements RemoteComposeOperation { return OP_CODE; } + /** + * Apply the header to the wire buffer + * + * @param buffer + * @param width + * @param height + * @param density + * @param capabilities + */ public static void apply( @NonNull WireBuffer buffer, int width, int height, float density, long capabilities) { buffer.start(OP_CODE); @@ -193,6 +202,11 @@ public class Header extends Operation implements RemoteComposeOperation { .field(LONG, "CAPABILITIES", "Major version"); } + /** + * Set the version on a document + * + * @param document + */ public void setVersion(CoreDocument document) { document.setVersion(mMajorVersion, mMinorVersion, mPatchVersion); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ParticlesCreate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ParticlesCreate.java new file mode 100644 index 000000000000..9e891c48c065 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ParticlesCreate.java @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT_ARRAY; +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import static com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression.VAR1; + +import android.annotation.NonNull; + +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.VariableSupport; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation; +import com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression; +import com.android.internal.widget.remotecompose.core.operations.utilities.NanMap; + +import java.util.Arrays; +import java.util.List; + +/** + * This creates a particle system. which consist of id, particleCount, array of id's and equations + * for constructing the particles + */ +public class ParticlesCreate extends Operation implements VariableSupport { + private static final int OP_CODE = Operations.PARTICLE_CREATE; + private static final String CLASS_NAME = "ParticlesCreate"; + private final int mId; + private final float[][] mEquations; + private final float[][] mOutEquations; + private final float[][] mParticles; + private final int[] mIndexeVars; // the elements in mEquations that INDEXES + private final int mParticleCount; + private final int[] mVarId; + private static final int MAX_FLOAT_ARRAY = 2000; + private static final int MAX_EQU_LENGTH = 32; + @NonNull AnimatedFloatExpression mExp = new AnimatedFloatExpression(); + + public ParticlesCreate(int id, int[] varId, float[][] values, int particleCount) { + mId = id; + mVarId = varId; + mEquations = values; + mParticleCount = particleCount; + mOutEquations = new float[values.length][]; + for (int i = 0; i < values.length; i++) { + mOutEquations[i] = new float[values[i].length]; + System.arraycopy(values[i], 0, mOutEquations[i], 0, values[i].length); + } + mParticles = new float[particleCount][varId.length]; + + int[] index = new int[20]; + int indexes = 0; + int var1Int = Float.floatToRawIntBits(VAR1); + for (int j = 0; j < mEquations.length; j++) { + for (int k = 0; k < mEquations[j].length; k++) { + if (Float.isNaN(mEquations[j][k]) + && Float.floatToRawIntBits(mEquations[j][k]) == var1Int) { + index[indexes++] = j * mEquations.length + k; + } + } + } + mIndexeVars = Arrays.copyOf(index, indexes); + } + + @Override + public void updateVariables(@NonNull RemoteContext context) { + for (int i = 0; i < mEquations.length; i++) { + + for (int j = 0; j < mEquations[i].length; j++) { + float v = mEquations[i][j]; + mOutEquations[i][j] = + (Float.isNaN(v) + && !AnimatedFloatExpression.isMathOperator(v) + && !NanMap.isDataVariable(v)) + ? context.getFloat(Utils.idFromNan(v)) + : v; + } + } + } + + @Override + public void registerListening(@NonNull RemoteContext context) { + context.putObject(mId, this); // T + for (int i = 0; i < mEquations.length; i++) { + float[] mEquation = mEquations[i]; + for (float v : mEquation) { + if (Float.isNaN(v) + && !AnimatedFloatExpression.isMathOperator(v) + && !NanMap.isDataVariable(v)) { + context.listensTo(Utils.idFromNan(v), this); + } + } + } + } + + @Override + public void write(@NonNull WireBuffer buffer) { + apply(buffer, mId, mVarId, mEquations, mParticleCount); + } + + @NonNull + @Override + public String toString() { + String str = "ParticlesCreate[" + Utils.idString(mId) + "] "; + for (int j = 0; j < mVarId.length; j++) { + str += "[" + mVarId[j] + "] "; + float[] equation = mEquations[j]; + String[] labels = new String[equation.length]; + for (int i = 0; i < equation.length; i++) { + if (Float.isNaN(equation[i])) { + labels[i] = "[" + Utils.idStringFromNan(equation[i]) + "]"; + } + } + str += AnimatedFloatExpression.toString(equation, labels) + "\n"; + } + + return str; + } + + /** + * Write the operation on the buffer + * + * @param buffer + * @param id + * @param varId + * @param equations + * @param particleCount + */ + public static void apply( + @NonNull WireBuffer buffer, + int id, + @NonNull int[] varId, + @NonNull float[][] equations, + int particleCount) { + buffer.start(OP_CODE); + buffer.writeInt(id); + buffer.writeInt(particleCount); + buffer.writeInt(varId.length); + for (int i = 0; i < varId.length; i++) { + buffer.writeInt(varId[i]); + buffer.writeInt(equations[i].length); + for (int j = 0; j < equations[i].length; j++) { + buffer.writeFloat(equations[i][j]); + } + } + } + + /** + * Read this operation and add it to the list of operations + * + * @param buffer the buffer to read + * @param operations the list of operations that will be added to + */ + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { + int id = buffer.readInt(); + int particleCount = buffer.readInt(); + int varLen = buffer.readInt(); + if (varLen > MAX_FLOAT_ARRAY) { + throw new RuntimeException(varLen + " map entries more than max = " + MAX_FLOAT_ARRAY); + } + int[] varId = new int[varLen]; + float[][] equations = new float[varLen][]; + for (int i = 0; i < varId.length; i++) { + varId[i] = buffer.readInt(); + int equLen = buffer.readInt(); + if (equLen > MAX_EQU_LENGTH) { + throw new RuntimeException( + equLen + " map entries more than max = " + MAX_FLOAT_ARRAY); + } + equations[i] = new float[equLen]; + for (int j = 0; j < equations[i].length; j++) { + equations[i][j] = buffer.readFloat(); + } + } + ParticlesCreate data = new ParticlesCreate(id, varId, equations, particleCount); + operations.add(data); + } + + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ + public static void documentation(@NonNull DocumentationBuilder doc) { + doc.operation("Data Operations", OP_CODE, CLASS_NAME) + .description("Creates a particle system") + .field(DocumentedOperation.INT, "id", "The reference of the particle system") + .field(INT, "particleCount", "number of particles to create") + .field(INT, "varLen", "number of variables asociate with the particles") + .field(FLOAT_ARRAY, "id", "varLen", "id followed by equations") + .field(INT, "equLen", "length of the equation") + .field(FLOAT_ARRAY, "equation", "varLen * equLen", "float array equations"); + } + + @NonNull + @Override + public String deepToString(@NonNull String indent) { + return indent + toString(); + } + + void initializeParticle(int pNo) { + for (int j = 0; j < mParticles[pNo].length; j++) { + for (int k = 0; k < mIndexeVars.length; k++) { + int pos = mIndexeVars[k]; + int jIndex = pos / mOutEquations.length; + int kIndex = pos % mOutEquations.length; + mOutEquations[jIndex][kIndex] = pNo; + } + mParticles[pNo][j] = mExp.eval(mOutEquations[j], mOutEquations[j].length); + } + } + + @Override + public void apply(@NonNull RemoteContext context) { + for (int i = 0; i < mParticles.length; i++) { + initializeParticle(i); + } + } + + public float[][] getParticles() { + return mParticles; + } + + public int[] getVariableIds() { + return mVarId; + } + + public float[][] getEquations() { + return mOutEquations; + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ParticlesLoop.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ParticlesLoop.java new file mode 100644 index 000000000000..791079070622 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ParticlesLoop.java @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT_ARRAY; +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.VariableSupport; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.Container; +import com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression; +import com.android.internal.widget.remotecompose.core.operations.utilities.NanMap; + +import java.util.ArrayList; +import java.util.List; + +/** + * This provides the mechinism to evolve the particles It consist of a restart equation and a list + * of equations particle restarts if restart equation > 0 + */ +public class ParticlesLoop extends PaintOperation implements VariableSupport, Container { + private static final int OP_CODE = Operations.PARTICLE_LOOP; + private static final String CLASS_NAME = "ParticlesLoop"; + private final int mId; + private final float[] mRestart; + private final float[] mOutRestart; + private final float[][] mEquations; + private final float[][] mOutEquations; + private int[] mVarId; + private float[][] mParticles; + private static final int MAX_FLOAT_ARRAY = 2000; + private static final int MAX_EQU_LENGTH = 32; + ParticlesCreate mParticlesSource; + + @NonNull + @Override + public ArrayList<Operation> getList() { + return mList; + } + + @NonNull private ArrayList<Operation> mList = new ArrayList<>(); + + @NonNull AnimatedFloatExpression mExp = new AnimatedFloatExpression(); + + /** + * Create a new ParticlesLoop operation + * + * @param id of the create + * @param restart the restart equation kills and restart when positive + * @param values the loop equations + */ + public ParticlesLoop(int id, float[] restart, float[][] values) { + mId = id; + mRestart = restart; + if (restart != null) { + mOutRestart = new float[restart.length]; + System.arraycopy(restart, 0, mOutRestart, 0, restart.length); + } else { + mOutRestart = null; + } + + mEquations = values; + mOutEquations = new float[values.length][]; + for (int i = 0; i < values.length; i++) { + mOutEquations[i] = new float[values[i].length]; + System.arraycopy(values[i], 0, mOutEquations[i], 0, values[i].length); + } + } + + @Override + public void updateVariables(@NonNull RemoteContext context) { + if (mOutRestart != null) { + for (int i = 0; i < mRestart.length; i++) { + float v = mRestart[i]; + mOutRestart[i] = + (Float.isNaN(v) + && !AnimatedFloatExpression.isMathOperator(v) + && !NanMap.isDataVariable(v)) + ? context.getFloat(Utils.idFromNan(v)) + : v; + } + } + for (int i = 0; i < mEquations.length; i++) { + float[] mEquation = mEquations[i]; + for (int j = 0; j < mEquation.length; j++) { + float v = mEquation[j]; + mOutEquations[i][j] = + (Float.isNaN(v) + && !AnimatedFloatExpression.isMathOperator(v) + && !NanMap.isDataVariable(v)) + ? context.getFloat(Utils.idFromNan(v)) + : v; + } + } + } + + @Override + public void registerListening(@NonNull RemoteContext context) { + mParticlesSource = (ParticlesCreate) context.getObject(mId); + mParticles = mParticlesSource.getParticles(); + mVarId = mParticlesSource.getVariableIds(); + if (mRestart != null) { + for (int i = 0; i < mRestart.length; i++) { + float v = mRestart[i]; + if (Float.isNaN(v) + && !AnimatedFloatExpression.isMathOperator(v) + && !NanMap.isDataVariable(v)) { + context.listensTo(Utils.idFromNan(v), this); + } + } + } + for (int i = 0; i < mEquations.length; i++) { + float[] mEquation = mEquations[i]; + for (float v : mEquation) { + if (Float.isNaN(v) + && !AnimatedFloatExpression.isMathOperator(v) + && !NanMap.isDataVariable(v)) { + context.listensTo(Utils.idFromNan(v), this); + } + } + } + } + + @Override + public void write(@NonNull WireBuffer buffer) { + apply(buffer, mId, mRestart, mEquations); + } + + @NonNull + @Override + public String toString() { + String str = "ParticlesLoop[" + Utils.idString(mId) + "] "; + return str; + } + + /** + * Write the operation on the buffer + * + * @param buffer + * @param id + * @param restart + * @param equations + */ + public static void apply( + @NonNull WireBuffer buffer, + int id, + @Nullable float[] restart, + @NonNull float[][] equations) { + buffer.start(OP_CODE); + buffer.writeInt(id); + if (restart != null) { + buffer.writeInt(restart.length); + for (int i = 0; i < restart.length; i++) { + buffer.writeFloat(restart[i]); + } + } else { + buffer.writeInt(0); + } + buffer.writeInt(equations.length); + for (int i = 0; i < equations.length; i++) { + buffer.writeInt(equations[i].length); + for (int j = 0; j < equations[i].length; j++) { + buffer.writeFloat(equations[i][j]); + } + } + } + + /** + * Read this operation and add it to the list of operations + * + * @param buffer the buffer to read + * @param operations the list of operations that will be added to + */ + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { + int id = buffer.readInt(); + int restartLen = buffer.readInt(); + float[] restart = null; + if (restartLen > 0) { + restart = new float[restartLen]; + for (int i = 0; i < restartLen; i++) { + restart[i] = buffer.readFloat(); + } + } + + int varLen = buffer.readInt(); + if (varLen > MAX_FLOAT_ARRAY) { + throw new RuntimeException(varLen + " map entries more than max = " + MAX_FLOAT_ARRAY); + } + + float[][] equations = new float[varLen][]; + for (int i = 0; i < varLen; i++) { + + int equLen = buffer.readInt(); + if (equLen > MAX_EQU_LENGTH) { + throw new RuntimeException( + equLen + " map entries more than max = " + MAX_FLOAT_ARRAY); + } + equations[i] = new float[equLen]; + for (int j = 0; j < equations[i].length; j++) { + equations[i][j] = buffer.readFloat(); + } + } + ParticlesLoop data = new ParticlesLoop(id, restart, equations); + operations.add(data); + } + + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ + public static void documentation(@NonNull DocumentationBuilder doc) { + doc.operation("Data Operations", OP_CODE, CLASS_NAME) + .description("This evolves the particles & recycles them") + .field(DocumentedOperation.INT, "id", "id of particle system") + .field( + INT, + "recycleLen", + "the number of floats in restart equeation if 0 no restart") + .field(FLOAT_ARRAY, "values", "recycleLen", "array of floats") + .field(INT, "varLen", "the number of equations to follow") + .field(INT, "equLen", "the number of equations to follow") + .field(FLOAT_ARRAY, "values", "equLen", "floats for the equation"); + } + + @NonNull + @Override + public String deepToString(@NonNull String indent) { + return indent + toString(); + } + + @Override + public void paint(@NonNull PaintContext context) { + RemoteContext remoteContext = context.getContext(); + for (int i = 0; i < mParticles.length; i++) { + // Save the values to context TODO hand code the update + for (int j = 0; j < mParticles[i].length; j++) { + remoteContext.loadFloat(mVarId[j], mParticles[i][j]); + updateVariables(remoteContext); + } + // Evaluate the update function + for (int j = 0; j < mParticles[i].length; j++) { + mParticles[i][j] = mExp.eval(mOutEquations[j], mOutEquations[j].length); + remoteContext.loadFloat(mVarId[j], mParticles[i][j]); + } + // test for reset + if (mOutRestart != null) { + for (int k = 0; k < mRestart.length; k++) { + float v = mRestart[k]; + mOutRestart[k] = + (Float.isNaN(v) + && !AnimatedFloatExpression.isMathOperator(v) + && !NanMap.isDataVariable(v)) + ? remoteContext.getFloat(Utils.idFromNan(v)) + : v; + } + if (mExp.eval(mOutRestart, mOutRestart.length) > 0) { + mParticlesSource.initializeParticle(i); + } + } + + for (Operation op : mList) { + if (op instanceof VariableSupport) { + ((VariableSupport) op).updateVariables(context.getContext()); + } + + remoteContext.incrementOpCount(); + op.apply(context.getContext()); + } + } + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java index 55dd88233265..129201c2b2d2 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java @@ -219,6 +219,15 @@ public class RootContentBehavior extends Operation implements RemoteComposeOpera return OP_CODE; } + /** + * Write the operation on the buffer + * + * @param buffer + * @param scroll + * @param alignment + * @param sizing + * @param mode + */ public static void apply( @NonNull WireBuffer buffer, int scroll, int alignment, int sizing, int mode) { buffer.start(OP_CODE); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java index ad86e0f2b1f3..c1ddf63264fa 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java @@ -95,6 +95,12 @@ public class RootContentDescription extends Operation return OP_CODE; } + /** + * Write the operation on the buffer + * + * @param buffer + * @param contentDescription + */ public static void apply(@NonNull WireBuffer buffer, int contentDescription) { buffer.start(Operations.ROOT_CONTENT_DESCRIPTION); buffer.writeInt(contentDescription); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java index e9aae1ebad45..1698ecb9d3fc 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java @@ -92,6 +92,12 @@ public class Theme extends Operation implements RemoteComposeOperation { return OP_CODE; } + /** + * Write the operation on the buffer + * + * @param buffer + * @param theme + */ public static void apply(@NonNull WireBuffer buffer, int theme) { buffer.start(OP_CODE); buffer.writeInt(theme); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java index 3b293bd1b8e0..997628140c46 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java @@ -368,6 +368,7 @@ public class TouchExpression extends Operation implements VariableSupport, Touch * * @param component the component, or null if outside */ + @Override public void setComponent(@Nullable Component component) { mComponent = component; if (mComponent != null) { diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java index 511858aa2b29..abb7ad8910f9 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java @@ -66,6 +66,12 @@ public class CanvasContent extends Component { return "CANVAS_CONTENT"; } + /** + * Write the operation on the buffer + * + * @param buffer + * @param componentId + */ public static void apply(@NonNull WireBuffer buffer, int componentId) { buffer.start(Operations.LAYOUT_CANVAS_CONTENT); buffer.writeInt(componentId); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java index 5f084e938588..110bd3079697 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java @@ -77,6 +77,12 @@ public class ClickModifierOperation extends PaintOperation return CoreSemantics.Mode.MERGE; } + /** + * Animate ripple + * + * @param x starting position x of the ripple + * @param y starting position y of the ripple + */ public void animateRipple(float x, float y) { mAnimateRippleStart = System.currentTimeMillis(); mAnimateRippleX = x; @@ -212,6 +218,11 @@ public class ClickModifierOperation extends PaintOperation return "ClickModifier"; } + /** + * Write the operation on the buffer + * + * @param buffer + */ public static void apply(@NonNull WireBuffer buffer) { buffer.start(OP_CODE); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java index eee2aabe1d8b..8e733ce1d808 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java @@ -24,6 +24,7 @@ import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.PaintOperation; import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.SerializableToString; +import com.android.internal.widget.remotecompose.core.TouchListener; import com.android.internal.widget.remotecompose.core.VariableSupport; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.operations.ComponentValue; @@ -236,6 +237,7 @@ public class Component extends PaintOperation finalizeCreation(); } + /** Callback on component creation TODO: replace with inflate() */ public void finalizeCreation() { for (Operation op : mList) { if (op instanceof Component) { @@ -273,6 +275,11 @@ public class Component extends PaintOperation context.mLastComponent = prev; } + /** + * Add a component value to the component + * + * @param v + */ public void addComponentValue(@NonNull ComponentValue v) { mComponentValues.add(v); } @@ -303,10 +310,10 @@ public class Component extends PaintOperation */ public void inflate() { for (Operation op : mList) { - if (op instanceof TouchExpression) { + if (op instanceof TouchListener) { // Make sure to set the component of a touch expression that belongs to us! - TouchExpression touchExpression = (TouchExpression) op; - touchExpression.setComponent(this); + TouchListener touchListener = (TouchListener) op; + touchListener.setComponent(this); } } } @@ -317,6 +324,11 @@ public class Component extends PaintOperation INVISIBLE } + /** + * Returns true if the component is visible + * + * @return + */ public boolean isVisible() { if (mVisibility != Visibility.VISIBLE || mParent == null) { return mVisibility == Visibility.VISIBLE; @@ -327,6 +339,11 @@ public class Component extends PaintOperation return true; } + /** + * Set the visibility of the component + * + * @param visibility can be VISIBLE, INVISIBLE or GONE + */ public void setVisibility(@NonNull Visibility visibility) { if (visibility != mVisibility || visibility != mScheduledVisibility) { mScheduledVisibility = visibility; @@ -443,6 +460,13 @@ public class Component extends PaintOperation @NonNull public float[] locationInWindow = new float[2]; + /** + * Hit detection -- returns true if the point (x, y) is inside the component + * + * @param x + * @param y + * @return + */ public boolean contains(float x, float y) { locationInWindow[0] = 0f; locationInWindow[1] = 0f; @@ -454,14 +478,32 @@ public class Component extends PaintOperation return x >= lx1 && x < lx2 && y >= ly1 && y < ly2; } + /** + * Returns the horizontal scroll value of the content of this component + * + * @return 0 if no scroll + */ public float getScrollX() { return 0; } + /** + * Returns the vertical scroll value of the content of this component + * + * @return 0 if no scroll + */ public float getScrollY() { return 0; } + /** + * Click handler + * + * @param context + * @param document + * @param x + * @param y + */ public void onClick( @NonNull RemoteContext context, @NonNull CoreDocument document, float x, float y) { if (!contains(x, y)) { @@ -479,6 +521,14 @@ public class Component extends PaintOperation } } + /** + * Touch down handler + * + * @param context + * @param document + * @param x + * @param y + */ public void onTouchDown(RemoteContext context, CoreDocument document, float x, float y) { if (!contains(x, y)) { return; @@ -501,6 +551,17 @@ public class Component extends PaintOperation } } + /** + * Touch Up handler + * + * @param context + * @param document + * @param x + * @param y + * @param dx + * @param dy + * @param force + */ public void onTouchUp( RemoteContext context, CoreDocument document, @@ -529,6 +590,15 @@ public class Component extends PaintOperation } } + /** + * Touch Cancel handler + * + * @param context + * @param document + * @param x + * @param y + * @param force + */ public void onTouchCancel( RemoteContext context, CoreDocument document, float x, float y, boolean force) { if (!force && !contains(x, y)) { @@ -551,6 +621,15 @@ public class Component extends PaintOperation } } + /** + * Touch Drag handler + * + * @param context + * @param document + * @param x + * @param y + * @param force + */ public void onTouchDrag( RemoteContext context, CoreDocument document, float x, float y, boolean force) { if (!force && !contains(x, y)) { @@ -573,6 +652,12 @@ public class Component extends PaintOperation } } + /** + * Returns the location of the component relative to the root component + * + * @param value a 2 dimension float array that will receive the horizontal and vertical position + * of the component. + */ public void getLocationInWindow(@NonNull float[] value) { value[0] += mX; value[1] += mY; @@ -681,6 +766,7 @@ public class Component extends PaintOperation } } + /** Mark the tree as needing a repaint */ public void needsRepaint() { try { getRoot().mNeedsRepaint = true; @@ -689,6 +775,11 @@ public class Component extends PaintOperation } } + /** + * Debugging function returning the list of child operations + * + * @return a formatted string with the list of operations + */ @NonNull public String content() { StringBuilder builder = new StringBuilder(); @@ -700,6 +791,11 @@ public class Component extends PaintOperation return builder.toString(); } + /** + * Returns a string containing the text operations if any + * + * @return + */ @NonNull public String textContent() { StringBuilder builder = new StringBuilder(); @@ -713,6 +809,12 @@ public class Component extends PaintOperation return builder.toString(); } + /** + * Utility debug function + * + * @param component + * @param context + */ public void debugBox(@NonNull Component component, @NonNull PaintContext context) { float width = component.mWidth; float height = component.mHeight; @@ -731,11 +833,22 @@ public class Component extends PaintOperation context.restorePaint(); } + /** + * Set the position of this component relative to its parent + * + * @param x horizontal position + * @param y vertical position + */ public void setLayoutPosition(float x, float y) { this.mX = x; this.mY = y; } + /** + * The vertical position of this component relative to its parent + * + * @return + */ public float getTranslateX() { if (mParent != null) { return mX - mParent.mX; @@ -743,6 +856,11 @@ public class Component extends PaintOperation return 0f; } + /** + * The horizontal position of this component relative to its parent + * + * @return + */ public float getTranslateY() { if (mParent != null) { return mY - mParent.mY; @@ -750,6 +868,11 @@ public class Component extends PaintOperation return 0f; } + /** + * Paint the component itself. + * + * @param context + */ public void paintingComponent(@NonNull PaintContext context) { if (mPreTranslate != null) { mPreTranslate.paint(context); @@ -778,6 +901,12 @@ public class Component extends PaintOperation context.getContext().mLastComponent = prev; } + /** + * If animation is turned on and we need to be animated, we'll apply it. + * + * @param context + * @return + */ public boolean applyAnimationAsNeeded(@NonNull PaintContext context) { if (context.isAnimationEnabled() && mAnimateMeasure != null) { mAnimateMeasure.paint(context); @@ -822,6 +951,11 @@ public class Component extends PaintOperation paintingComponent(context); } + /** + * Extract child components + * + * @param components an ArrayList that will be populated by child components (if any) + */ public void getComponents(@NonNull ArrayList<Component> components) { for (Operation op : mList) { if (op instanceof Component) { @@ -830,6 +964,11 @@ public class Component extends PaintOperation } } + /** + * Extract child TextData elements + * + * @param data an ArrayList that will be populated with the TextData elements (if any) + */ public void getData(@NonNull ArrayList<TextData> data) { for (Operation op : mList) { if (op instanceof TextData) { @@ -838,6 +977,11 @@ public class Component extends PaintOperation } } + /** + * Returns the number of children components + * + * @return + */ public int getComponentCount() { int count = 0; for (Operation op : mList) { @@ -848,6 +992,12 @@ public class Component extends PaintOperation return count; } + /** + * Return the id used for painting the component -- either its component id or its animation id + * (if set) + * + * @return + */ public int getPaintId() { if (mAnimationId != -1) { return mAnimationId; @@ -855,10 +1005,21 @@ public class Component extends PaintOperation return mComponentId; } + /** + * Return true if the needsRepaint flag is set on this component + * + * @return + */ public boolean doesNeedsRepaint() { return mNeedsRepaint; } + /** + * Utility function to return a component from its id + * + * @param cid + * @return + */ @Nullable public Component getComponent(int cid) { if (mComponentId == cid || mAnimationId == cid) { diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java index f009d8801159..5ef71d006107 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java @@ -126,6 +126,12 @@ public class ComponentStart extends Operation implements Container { public static final int LAYOUT_ROW = 15; public static final int LAYOUT_COLUMN = 16; + /** + * Returns the string representation of the component type + * + * @param type + * @return a string representing the component type + */ @NonNull public static String typeDescription(int type) { switch (type) { @@ -179,6 +185,15 @@ public class ComponentStart extends Operation implements Container { return Operations.COMPONENT_START; } + /** + * Write the operation on the buffer + * + * @param buffer + * @param type + * @param componentId + * @param width + * @param height + */ public static void apply( @NonNull WireBuffer buffer, int type, int componentId, float width, float height) { buffer.start(Operations.COMPONENT_START); @@ -188,6 +203,11 @@ public class ComponentStart extends Operation implements Container { buffer.writeFloat(height); } + /** + * Return the size of the operation in byte + * + * @return the size in byte + */ public static int size() { return 1 + 4 + 4 + 4; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Container.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Container.java index c678f6c22cef..41e2bf801009 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Container.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Container.java @@ -21,7 +21,13 @@ import com.android.internal.widget.remotecompose.core.Operation; import java.util.ArrayList; +/** An Operation container */ public interface Container { + /** + * Returns a list of child operations + * + * @return a list of child operations + */ @NonNull ArrayList<Operation> getList(); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ContainerEnd.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ContainerEnd.java index 4290c4bc3c2b..004f19407c90 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ContainerEnd.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ContainerEnd.java @@ -68,6 +68,11 @@ public class ContainerEnd extends Operation { return Operations.CONTAINER_END; } + /** + * Write the operation on the buffer + * + * @param buffer + */ public static void apply(@NonNull WireBuffer buffer) { buffer.start(id()); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseOperation.java new file mode 100644 index 000000000000..e277d49325be --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseOperation.java @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.layout; + +import android.annotation.NonNull; + +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.VariableSupport; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation; +import com.android.internal.widget.remotecompose.core.operations.Utils; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a Impulse Event To trigger an impulse event. set the startAt time to the + * context.getAnimationTime() Impluse Operation. This operation execute a list of actions once and + * the impluseProcess is executed for a fixed duration + */ +public class ImpulseOperation extends PaintOperation implements VariableSupport, Container { + private static final int OP_CODE = Operations.IMPULSE_START; + private static final String CLASS_NAME = "ImpulseOperation"; + private float mDuration; + private float mStartAt; + private float mOutDuration; + private float mOutStartAt; + private boolean mInitialPass = true; + @NonNull public ArrayList<Operation> mList = new ArrayList<>(); + + int mIndexVariableId; + + private ImpulseProcess mProcess; + + /** + * Constructor for a Impulse Operation + * + * @param duration the duration of the impluse + * @param startAt the start time of the impluse + */ + public ImpulseOperation(float duration, float startAt) { + mDuration = duration; + mStartAt = startAt; + mOutStartAt = startAt; + mOutDuration = duration; + } + + @Override + public void registerListening(RemoteContext context) { + if (mProcess == null) { + System.out.println("....."); + Operation last = mList.get(mList.size() - 1); + if (last instanceof ImpulseProcess) { + mProcess = (ImpulseProcess) last; + mList.remove(last); + } + } + if (Float.isNaN(mStartAt)) { + context.listensTo(Utils.idFromNan(mStartAt), this); + } + if (Float.isNaN(mDuration)) { + context.listensTo(Utils.idFromNan(mDuration), this); + } + for (Operation operation : mList) { + if (operation instanceof VariableSupport) { + VariableSupport variableSupport = (VariableSupport) operation; + variableSupport.registerListening(context); + } + } + if (mProcess != null) { + mProcess.registerListening(context); + } + } + + @Override + public void updateVariables(RemoteContext context) { + + mOutDuration = + Float.isNaN(mDuration) ? context.getFloat(Utils.idFromNan(mDuration)) : mDuration; + + mOutStartAt = + Float.isNaN(mStartAt) ? context.getFloat(Utils.idFromNan(mStartAt)) : mStartAt; + if (mProcess != null) { + mProcess.updateVariables(context); + } + } + + @NonNull + public ArrayList<Operation> getList() { + return mList; + } + + @Override + public void write(@NonNull WireBuffer buffer) { + apply(buffer, mDuration, mStartAt); + } + + @NonNull + @Override + public String toString() { + StringBuilder builder = new StringBuilder("LoopOperation\n"); + for (Operation operation : mList) { + builder.append(" startAt: "); + builder.append(mStartAt); + builder.append(" duration: "); + builder.append(mDuration); + builder.append("\n"); + } + return builder.toString(); + } + + @NonNull + @Override + public String deepToString(@NonNull String indent) { + return (indent != null ? indent : "") + toString(); + } + + @Override + public void paint(@NonNull PaintContext context) { + RemoteContext remoteContext = context.getContext(); + + if (remoteContext.getAnimationTime() < mOutStartAt + mOutDuration) { + if (mInitialPass) { + for (Operation op : mList) { + if (op instanceof VariableSupport && op.isDirty()) { + ((VariableSupport) op).updateVariables(context.getContext()); + } + remoteContext.incrementOpCount(); + op.apply(context.getContext()); + } + mInitialPass = false; + } else { + remoteContext.incrementOpCount(); + if (mProcess != null) { + mProcess.paint(context); + } + } + } else { + mInitialPass = true; + } + } + + /** + * The name of the class + * + * @return the name + */ + @NonNull + public static String name() { + return CLASS_NAME; + } + + /** + * Write the operation on the buffer + * + * @param buffer + * @param duration + * @param startAt + */ + public static void apply(@NonNull WireBuffer buffer, float duration, float startAt) { + buffer.start(OP_CODE); + buffer.writeFloat(duration); + buffer.writeFloat(startAt); + } + + /** + * Read this operation and add it to the list of operations + * + * @param buffer the buffer to read + * @param operations the list of operations that will be added to + */ + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { + float duration = buffer.readFloat(); + float startAt = buffer.readFloat(); + + operations.add(new ImpulseOperation(duration, startAt)); + } + + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ + public static void documentation(@NonNull DocumentationBuilder doc) { + doc.operation("Operations", OP_CODE, name()) + .description( + "Impulse Operation. This operation execute a list of action for a fixed" + + " duration") + .field(DocumentedOperation.FLOAT, "duration", "How long to last") + .field(DocumentedOperation.FLOAT, "startAt", "value step"); + } + + /** + * Calculate and estimate of the number of iterations + * + * @return number of loops or 10 if based on variables + */ + public int estimateIterations() { + if (Float.isNaN(mDuration)) { + return 10; // this is a generic estmate if the values are variables; + } + return (int) (mDuration * 60); + } + + /** + * set the impulse process. This gets executed for the duration of the impulse + * + * @param impulseProcess process to be executed every time + */ + public void setProcess(ImpulseProcess impulseProcess) { + mProcess = impulseProcess; + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseProcess.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseProcess.java new file mode 100644 index 000000000000..f896f3d8ee9c --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseProcess.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.layout; + +import android.annotation.NonNull; + +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.VariableSupport; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; + +import java.util.ArrayList; +import java.util.List; + +/** Represents the repeating part of an Impulse. */ +public class ImpulseProcess extends PaintOperation implements VariableSupport, Container { + private static final int OP_CODE = Operations.IMPULSE_PROCESS; + private static final String CLASS_NAME = "ImpulseProcess"; + + @NonNull public ArrayList<Operation> mList = new ArrayList<>(); + + /** The constructor */ + public ImpulseProcess() {} + + @Override + public void registerListening(RemoteContext context) { + for (Operation operation : mList) { + if (operation instanceof VariableSupport) { + VariableSupport variableSupport = (VariableSupport) operation; + variableSupport.registerListening(context); + } + } + } + + @Override + public void updateVariables(RemoteContext context) { + for (Operation operation : mList) { + if (operation instanceof VariableSupport) { + VariableSupport variableSupport = (VariableSupport) operation; + variableSupport.updateVariables(context); + } + } + } + + /** + * The returns a list to be filled + * + * @return list to be filled + */ + @NonNull + public ArrayList<Operation> getList() { + return mList; + } + + @Override + public void write(@NonNull WireBuffer buffer) { + apply(buffer); + } + + @NonNull + @Override + public String toString() { + StringBuilder builder = new StringBuilder(CLASS_NAME + "\n"); + for (Operation operation : mList) { + builder.append(" "); + builder.append(operation); + builder.append("\n"); + } + return builder.toString(); + } + + @NonNull + @Override + public String deepToString(@NonNull String indent) { + return (indent != null ? indent : "") + toString(); + } + + @Override + public void paint(@NonNull PaintContext context) { + RemoteContext remoteContext = context.getContext(); + for (Operation op : mList) { + if (op instanceof VariableSupport && op.isDirty()) { + ((VariableSupport) op).updateVariables(context.getContext()); + } + remoteContext.incrementOpCount(); + op.apply(context.getContext()); + } + } + + /** + * The name of the class + * + * @return the name + */ + @NonNull + public static String name() { + return "Loop"; + } + + /** + * Apply this operation to the buffer + * + * @param buffer + */ + public static void apply(@NonNull WireBuffer buffer) { + buffer.start(OP_CODE); + } + + /** + * Read this operation and add it to the list of operations + * + * @param buffer the buffer to read + * @param operations the list of operations that will be added to + */ + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { + operations.add(new ImpulseProcess()); + } + + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ + public static void documentation(@NonNull DocumentationBuilder doc) { + doc.operation("Operations", OP_CODE, name()) + .description("Impulse Process that runs a list of operations"); + } + + /** + * Calculate and estimate of the number of iterations + * + * @return number of loops or 10 if based on variables + */ + public int estimateIterations() { + return 1; + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java index 91038852573e..e71cb9a51830 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java @@ -22,6 +22,7 @@ import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.OperationInterface; import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.TouchListener; import com.android.internal.widget.remotecompose.core.VariableSupport; import com.android.internal.widget.remotecompose.core.operations.BitmapData; import com.android.internal.widget.remotecompose.core.operations.FloatExpression; @@ -176,8 +177,8 @@ public class LayoutComponent extends Component { || (op instanceof PaintData) || (op instanceof FloatExpression)) { supportedOperations.add(op); - if (op instanceof TouchExpression) { - ((TouchExpression) op).setComponent(this); + if (op instanceof TouchListener) { + ((TouchListener) op).setComponent(this); } } else { // nothing diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java index 27172aa7672c..4babe5f036a5 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java @@ -66,6 +66,12 @@ public class LayoutComponentContent extends Component { return "CONTENT"; } + /** + * Write the operation on the buffer + * + * @param buffer + * @param componentId + */ public static void apply(@NonNull WireBuffer buffer, int componentId) { buffer.start(Operations.LAYOUT_CONTENT); buffer.writeInt(componentId); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java index 6dce6f115572..bfa417e87637 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java @@ -88,6 +88,18 @@ public abstract class ListActionsOperation extends PaintOperation } } + /** + * Execute the list of actions + * + * @param context the RemoteContext + * @param document the current document + * @param component the component we belong to + * @param x the x touch down coordinate + * @param y the y touch down coordinate + * @param force if true, will apply the actions even if the component is not visible / not + * containing the touch down coordinates + * @return true if we applied the actions, false otherwise + */ public boolean applyActions( RemoteContext context, CoreDocument document, diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java index f5954eea04af..0f4cf562eae6 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java @@ -33,6 +33,7 @@ import java.util.List; /** Represents a loop of operations */ public class LoopOperation extends PaintOperation implements Container, VariableSupport { + private static final int OP_CODE = Operations.LOOP_START; @NonNull public ArrayList<Operation> mList = new ArrayList<>(); @@ -77,6 +78,7 @@ public class LoopOperation extends PaintOperation implements Container, Variable mIndexVariableId = indexId; } + @Override @NonNull public ArrayList<Operation> getList() { return mList; @@ -139,6 +141,15 @@ public class LoopOperation extends PaintOperation implements Container, Variable return "Loop"; } + /** + * Write the operation on the buffer + * + * @param buffer + * @param indexId + * @param from + * @param step + * @param until + */ public static void apply( @NonNull WireBuffer buffer, int indexId, float from, float step, float until) { buffer.start(OP_CODE); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java index baff5ee488a7..f94cda21aca7 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java @@ -174,6 +174,11 @@ public class RootLayoutComponent extends Component { context.restore(); } + /** + * Display the component hierarchy + * + * @return a formatted string containing the component hierarchy + */ @NonNull public String displayHierarchy() { StringSerializer serializer = new StringSerializer(); @@ -181,6 +186,13 @@ public class RootLayoutComponent extends Component { return serializer.toString(); } + /** + * Display the component hierarchy + * + * @param component the current component + * @param indent the current indentation level + * @param serializer the serializer we write to + */ public void displayHierarchy( @NonNull Component component, int indent, @NonNull StringSerializer serializer) { component.serializeToString(indent, serializer); @@ -214,6 +226,12 @@ public class RootLayoutComponent extends Component { return Operations.LAYOUT_ROOT; } + /** + * Write the operation on the buffer + * + * @param buffer + * @param componentId + */ public static void apply(@NonNull WireBuffer buffer, int componentId) { buffer.start(Operations.LAYOUT_ROOT); buffer.writeInt(componentId); @@ -249,6 +267,11 @@ public class RootLayoutComponent extends Component { apply(buffer, mComponentId); } + /** + * Returns true if we have components with a touch listener + * + * @return true if listeners, false otherwise + */ public boolean hasTouchListeners() { return mHasTouchListeners; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/DebugLog.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/DebugLog.java index 842c9c161aee..96e29cdd01ab 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/DebugLog.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/DebugLog.java @@ -40,6 +40,11 @@ public class DebugLog { } } + /** + * Add a node to the current node + * + * @param node + */ public void add(@NonNull Node node) { list.add(node); } @@ -54,23 +59,35 @@ public class DebugLog { @NonNull public static Node node = new Node(null, "Root"); @NonNull public static Node currentNode = node; + /** clear the current logging */ public static void clear() { node = new Node(null, "Root"); currentNode = node; } + /** + * start a node + * + * @param valueSupplier + */ public static void s(@NonNull StringValueSupplier valueSupplier) { if (DEBUG_LAYOUT_ON) { currentNode = new Node(currentNode, valueSupplier.getString()); } } + /** + * arbitrary log statement + * + * @param valueSupplier + */ public static void log(@NonNull StringValueSupplier valueSupplier) { if (DEBUG_LAYOUT_ON) { new LogNode(currentNode, valueSupplier.getString()); } } + /** end a node */ public static void e() { if (DEBUG_LAYOUT_ON) { if (currentNode.parent != null) { @@ -81,6 +98,11 @@ public class DebugLog { } } + /** + * end a node + * + * @param valueSupplier + */ public static void e(@NonNull StringValueSupplier valueSupplier) { if (DEBUG_LAYOUT_ON) { currentNode.endString = valueSupplier.getString(); @@ -92,6 +114,13 @@ public class DebugLog { } } + /** + * print a given node + * + * @param indent + * @param node + * @param builder + */ public static void printNode(int indent, @NonNull Node node, @NonNull StringBuilder builder) { if (DEBUG_LAYOUT_ON) { StringBuilder indentationBuilder = new StringBuilder(); @@ -121,6 +150,7 @@ public class DebugLog { } } + /** Output the captured log to System.out */ public static void display() { if (DEBUG_LAYOUT_ON) { StringBuilder builder = new StringBuilder(); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java index 7e467012536d..b2ea0afd8fab 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java @@ -162,7 +162,7 @@ public class AnimatedFloatExpression { /** VAR2 operator */ public static final float VAR3 = asNan(OFFSET + 43); - // TODO CLAMP, CBRT, DEG, RAD, EXPM1, CEIL, FLOOR + // TODO SQUARE, DUP, HYPOT, SWAP // private static final float FP_PI = (float) Math.PI; private static final float FP_TO_RAD = 57.29578f; // 180/PI private static final float FP_TO_DEG = 0.017453292f; // 180/PI @@ -172,7 +172,7 @@ public class AnimatedFloatExpression { @NonNull float[] mVar = new float[0]; @Nullable CollectionsAccess mCollectionsAccess; IntMap<MonotonicSpline> mSplineMap = new IntMap<>(); - private Random mRandom; + private static Random sRandom; private float getSplineValue(int arrayId, float pos) { MonotonicSpline fit = mSplineMap.get(arrayId); @@ -806,21 +806,21 @@ public class AnimatedFloatExpression { return sp - 1; case OP_RAND: - if (mRandom == null) { - mRandom = new Random(); + if (sRandom == null) { + sRandom = new Random(); } - mStack[sp + 1] = mRandom.nextFloat(); + mStack[sp + 1] = sRandom.nextFloat(); return sp + 1; case OP_RAND_SEED: float seed = mStack[sp]; if (seed == 0) { - mRandom = new Random(); + sRandom = new Random(); } else { - if (mRandom == null) { - mRandom = new Random(Float.floatToRawIntBits(seed)); + if (sRandom == null) { + sRandom = new Random(Float.floatToRawIntBits(seed)); } else { - mRandom.setSeed(Float.floatToRawIntBits(seed)); + sRandom.setSeed(Float.floatToRawIntBits(seed)); } } return sp - 1; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java index c7e2442221cd..56a041026c1f 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java @@ -108,14 +108,14 @@ public class VelocityEasing { return mStage[i].getPos(t); } } - var ret = (float) getEasing((t - mStage[lastStages].mStartTime)); + float ret = (float) getEasing((t - mStage[lastStages].mStartTime)); ret += mStage[lastStages].mStartPos; return ret; } @Override public String toString() { - var s = " "; + String s = " "; for (int i = 0; i < mNumberOfStages; i++) { Stage stage = mStage[i]; s += " $i $stage"; diff --git a/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibilityModifier.java b/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibilityModifier.java index cd8b7b865cd2..098c4c3190e5 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibilityModifier.java +++ b/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibilityModifier.java @@ -17,7 +17,20 @@ package com.android.internal.widget.remotecompose.core.semantics; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ModifierOperation; -/** A Modifier that provides semantic info. */ +/** + * A Modifier that provides semantic info. + * + * <p>This is needed since `AccessibilityModifier` is generally an open set and designed to be + * extended. + */ public interface AccessibilityModifier extends ModifierOperation, AccessibleComponent { + /** + * This method retrieves the operation code. + * + * <p>This function is used to get the current operation code associated with the object or + * context this method belongs to. + * + * @return The operation code as an integer. + */ int getOpCode(); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibleComponent.java b/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibleComponent.java index e07fc4d9a8f8..cc6c2a6ac7a9 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibleComponent.java +++ b/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibleComponent.java @@ -17,29 +17,100 @@ package com.android.internal.widget.remotecompose.core.semantics; import android.annotation.Nullable; +/** + * Interface representing an accessible component in the UI. This interface defines properties and + * methods related to accessibility semantics for a component. It extends the {@link + * AccessibilitySemantics} interface to inherit semantic properties. + * + * <p>This is similar to {@link CoreSemantics} but handles built in operations that also expose + * those core semantics. + */ public interface AccessibleComponent extends AccessibilitySemantics { + /** + * Returns the ID of the content description for this item. + * + * <p>The content description is used to provide textual information about the item to + * accessibility services, such as screen readers. This allows users with visual impairments to + * understand the purpose and content of the item. + * + * <p>This is similar to AccessibilityNodeInfo.getContentDescription(). + * + * @return The ID of a RemoteString for the content description, or null if no content + * description is provided. + */ default @Nullable Integer getContentDescriptionId() { return null; } + /** + * Gets the text ID associated with this object. + * + * <p>This method is intended to be overridden by subclasses that need to associate a specific + * text ID with themselves. The default implementation returns null, indicating that no text ID + * is associated with the object. + * + * <p>This is similar to AccessibilityNodeInfo.getText(). + * + * @return The text ID, or null if no text ID is associated with this object. + */ default @Nullable Integer getTextId() { return null; } + /** + * Retrieves the role associated with this object. The enum type deliberately matches the + * Compose Role. In the platform it will be applied as ROLE_DESCRIPTION_KEY. + * + * <p>The default implementation returns {@code null}, indicating that no role is assigned. + * + * @return The role associated with this object, or {@code null} if no role is assigned. + */ default @Nullable Role getRole() { return null; } + /** + * Checks if the element is clickable. + * + * <p>By default, elements are not considered clickable. Subclasses should override this method + * to indicate clickability based on their specific properties and behavior. + * + * <p>This is similar to AccessibilityNodeInfo.isClickable(). + * + * @return {@code true} if the element is clickable, {@code false} otherwise. + */ default boolean isClickable() { return false; } + /** + * Gets the merge mode of the operation. + * + * <p>The mode indicates the type of operation being performed. By default it returns {@link + * CoreSemantics.Mode#SET}, indicating a "set" operation. + * + * <p>{@link CoreSemantics.Mode#CLEAR_AND_SET} matches a Compose modifier of + * `Modifier.clearAndSetSemantics {}` + * + * <p>{@link CoreSemantics.Mode#MERGE} matches a Compose modifier of + * `Modifier.semantics(mergeDescendants = true) {}` + * + * @return The mode of the operation, which defaults to {@link CoreSemantics.Mode#SET}. + */ default CoreSemantics.Mode getMode() { return CoreSemantics.Mode.SET; } - // Our master list - // https://developer.android.com/reference/kotlin/androidx/compose/ui/semantics/Role + /** + * Represents the role of an accessible component. + * + * <p>The enum type deliberately matches the Compose Role. In the platform it will be applied as + * ROLE_DESCRIPTION_KEY. + * + * @link <a + * href="https://developer.android.com/reference/androidx/compose/ui/semantics/Role">Compose + * Semantics Role</a> + */ enum Role { BUTTON("Button"), CHECKBOX("Checkbox"), @@ -70,4 +141,21 @@ public interface AccessibleComponent extends AccessibilitySemantics { return Role.UNKNOWN; } } + + /** + * Defines the merge mode of an element in the semantic tree. + * + * <p>{@link CoreSemantics.Mode#CLEAR_AND_SET} matches a Compose modifier of + * `Modifier.clearAndSetSemantics {}` + * + * <p>{@link CoreSemantics.Mode#MERGE} matches a Compose modifier of + * `Modifier.semantics(mergeDescendants = true) {}` + * + * <p>{@link CoreSemantics.Mode#SET} adds or overrides semantics on an element. + */ + enum Mode { + SET, + CLEAR_AND_SET, + MERGE + } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/semantics/CoreSemantics.java b/core/java/com/android/internal/widget/remotecompose/core/semantics/CoreSemantics.java index 4047dd27d163..5b35ee5fc7ed 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/semantics/CoreSemantics.java +++ b/core/java/com/android/internal/widget/remotecompose/core/semantics/CoreSemantics.java @@ -118,16 +118,22 @@ public class CoreSemantics extends Operation implements AccessibilityModifier { return indent + this; } - @NonNull - public String serializedName() { - return "SEMANTICS"; - } - @Override public void serializeToString(int indent, @NonNull StringSerializer serializer) { - serializer.append(indent, serializedName() + " = " + this); + serializer.append(indent, "SEMANTICS" + " = " + this); } + /** + * Reads a CoreSemantics object from a WireBuffer and adds it to a list of operations. + * + * <p>This method reads the data required to construct a CoreSemantics object from the provided + * WireBuffer. After reading and constructing the CoreSemantics object, it is added to the + * provided list of operations. + * + * @param buffer The WireBuffer to read data from. + * @param operations The list of operations to which the read CoreSemantics object will be + * added. + */ public static void read(WireBuffer buffer, List<Operation> operations) { CoreSemantics semantics = new CoreSemantics(); @@ -148,10 +154,4 @@ public class CoreSemantics extends Operation implements AccessibilityModifier { public @Nullable Integer getTextId() { return mTextId != 0 ? mTextId : null; } - - public enum Mode { - SET, - CLEAR_AND_SET, - MERGE - } } diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java index da65a9cf5cc9..970cc4a44672 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java +++ b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java @@ -19,7 +19,9 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.Paint; import android.graphics.Point; +import android.graphics.Rect; import android.util.AttributeSet; import android.view.Choreographer; import android.view.MotionEvent; @@ -47,6 +49,7 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta Point mActionDownPoint = new Point(0, 0); AndroidRemoteContext mARContext = new AndroidRemoteContext(); float mDensity = 1f; + long mStart = System.nanoTime(); long mLastFrameDelay = 1; float mMaxFrameRate = 60f; // frames per seconds @@ -103,12 +106,14 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta public void setDocument(RemoteComposeDocument value) { mDocument = value; mDocument.initializeContext(mARContext); + mDisable = false; mARContext.setAnimationEnabled(true); mARContext.setDensity(mDensity); mARContext.setUseChoreographer(true); setContentDescription(mDocument.getDocument().getContentDescription()); updateClickAreas(); requestLayout(); + mARContext.loadFloat(RemoteContext.ID_TOUCH_EVENT_TIME, -Float.MAX_VALUE); invalidate(); } @@ -337,6 +342,8 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta mActionDownPoint.y = (int) event.getY(); CoreDocument doc = mDocument.getDocument(); if (doc.hasTouchListener()) { + mARContext.loadFloat( + RemoteContext.ID_TOUCH_EVENT_TIME, mARContext.getAnimationTime()); mInActionDown = true; if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); @@ -368,6 +375,8 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta performClick(); doc = mDocument.getDocument(); if (doc.hasTouchListener()) { + mARContext.loadFloat( + RemoteContext.ID_TOUCH_EVENT_TIME, mARContext.getAnimationTime()); mVelocityTracker.computeCurrentVelocity(1000); float dx = mVelocityTracker.getXVelocity(pointerId); float dy = mVelocityTracker.getYVelocity(pointerId); @@ -380,6 +389,8 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta case MotionEvent.ACTION_MOVE: if (mInActionDown) { if (mVelocityTracker != null) { + mARContext.loadFloat( + RemoteContext.ID_TOUCH_EVENT_TIME, mARContext.getAnimationTime()); mVelocityTracker.addMovement(event); doc = mDocument.getDocument(); boolean repaint = doc.touchDrag(mARContext, event.getX(), event.getY()); @@ -453,7 +464,9 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta private int mCount; private long mTime = System.nanoTime(); private long mDuration; - private boolean mEvalTime = false; + private boolean mEvalTime = false; // turn on to measure eval time + private float mLastAnimationTime = 0.1f; // set to random non 0 number + private boolean mDisable = false; /** * This returns the amount of time in ms the player used to evalueate a pass it is averaged over @@ -480,36 +493,76 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta if (mDocument == null) { return; } - long start = mEvalTime ? System.nanoTime() : 0; - mARContext.useCanvas(canvas); - mARContext.mWidth = getWidth(); - mARContext.mHeight = getHeight(); - mDocument.paint(mARContext, mTheme); - if (mDebug == 1) { - mCount++; - if (System.nanoTime() - mTime > 1000000000L) { - System.out.println(" count " + mCount + " fps"); - mCount = 0; - mTime = System.nanoTime(); - } + if (mDisable) { + drawDisable(canvas); + return; } - int nextFrame = mDocument.needsRepaint(); - if (nextFrame > 0) { - mLastFrameDelay = Math.max(mMaxFrameDelay, nextFrame); - if (mChoreographer != null) { - mChoreographer.postFrameCallbackDelayed(mFrameCallback, mLastFrameDelay); + try { + + long start = mEvalTime ? System.nanoTime() : 0; // measure execut of commands + + float animationTime = (System.nanoTime() - mStart) * 1E-9f; + mARContext.setAnimationTime(animationTime); + mARContext.loadFloat(RemoteContext.ID_ANIMATION_TIME, animationTime); + float loopTime = animationTime - mLastAnimationTime; + mARContext.loadFloat(RemoteContext.ID_ANIMATION_DELTA_TIME, loopTime); + mLastAnimationTime = animationTime; + mARContext.setAnimationEnabled(true); + mARContext.currentTime = System.currentTimeMillis(); + mARContext.setDebug(mDebug); + float density = getContext().getResources().getDisplayMetrics().density; + mARContext.useCanvas(canvas); + mARContext.mWidth = getWidth(); + mARContext.mHeight = getHeight(); + mDocument.paint(mARContext, mTheme); + if (mDebug == 1) { + mCount++; + if (System.nanoTime() - mTime > 1000000000L) { + System.out.println(" count " + mCount + " fps"); + mCount = 0; + mTime = System.nanoTime(); + } } - if (!mARContext.useChoreographer()) { - invalidate(); + int nextFrame = mDocument.needsRepaint(); + if (nextFrame > 0) { + mLastFrameDelay = Math.max(mMaxFrameDelay, nextFrame); + if (mChoreographer != null) { + mChoreographer.postFrameCallbackDelayed(mFrameCallback, mLastFrameDelay); + } + if (!mARContext.useChoreographer()) { + invalidate(); + } + } else { + if (mChoreographer != null) { + mChoreographer.removeFrameCallback(mFrameCallback); + } } - } else { - if (mChoreographer != null) { - mChoreographer.removeFrameCallback(mFrameCallback); + if (mEvalTime) { + mDuration += System.nanoTime() - start; + mCount++; } + } catch (Exception ex) { + mARContext.getLastOpCount(); + mDisable = true; + invalidate(); } - if (mEvalTime) { - mDuration += System.nanoTime() - start; - mCount++; - } + } + + private void drawDisable(Canvas canvas) { + Rect rect = new Rect(); + canvas.drawColor(Color.BLACK); + Paint paint = new Paint(); + paint.setTextSize(128f); + paint.setColor(Color.RED); + int w = getWidth(); + int h = getHeight(); + + String str = "âš "; + paint.getTextBounds(str, 0, 1, rect); + + float x = w / 2f - rect.width() / 2f - rect.left; + float y = h / 2f + rect.height() / 2f - rect.bottom; + + canvas.drawText(str, x, y, paint); } } diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 027113a75f6b..3afe27ea591f 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -179,6 +179,8 @@ cc_library_shared_for_libandroid_runtime { "android_os_NativeHandle.cpp", "android_os_MemoryFile.cpp", "android_os_MessageQueue.cpp", + "android_os_PerfettoTrace.cpp", + "android_os_PerfettoTrackEventExtra.cpp", "android_os_Parcel.cpp", "android_os_PerformanceHintManager.cpp", "android_os_SELinux.cpp", @@ -482,11 +484,22 @@ cc_library_shared_for_libandroid_runtime { "libbinder", "libhidlbase", // libhwbinder is in here ], + version_script: "platform/linux/libandroid_runtime_export.txt", + }, + darwin: { + host_ldlibs: [ + "-framework AppKit", + ], + dist: { + targets: ["layoutlib_jni"], + dir: "layoutlib_native/darwin", + }, + exported_symbols_list: "platform/darwin/libandroid_runtime_export.exp", }, linux_glibc_x86_64: { ldflags: ["-static-libgcc"], dist: { - targets: ["layoutlib"], + targets: ["layoutlib_jni"], dir: "layoutlib_native/linux", tag: "stripped_all", }, diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 78d69f0714e0..aea1734918d6 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -158,6 +158,8 @@ extern int register_android_os_SELinux(JNIEnv* env); extern int register_android_os_storage_StorageManager(JNIEnv* env); extern int register_android_os_SystemProperties(JNIEnv *env); extern int register_android_os_SystemClock(JNIEnv* env); +extern int register_android_os_PerfettoTrace(JNIEnv* env); +extern int register_android_os_PerfettoTrackEventExtra(JNIEnv* env); extern int register_android_os_Trace(JNIEnv* env); extern int register_android_os_FileObserver(JNIEnv *env); extern int register_android_os_UEventObserver(JNIEnv* env); @@ -1605,6 +1607,8 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_os_GraphicsEnvironment), REG_JNI(register_android_os_MessageQueue), REG_JNI(register_android_os_SELinux), + REG_JNI(register_android_os_PerfettoTrace), + REG_JNI(register_android_os_PerfettoTrackEventExtra), REG_JNI(register_android_os_Trace), REG_JNI(register_android_os_UEventObserver), REG_JNI(register_android_net_LocalSocketImpl), diff --git a/core/jni/android_os_PerfettoTrace.cpp b/core/jni/android_os_PerfettoTrace.cpp new file mode 100644 index 000000000000..988aea722be3 --- /dev/null +++ b/core/jni/android_os_PerfettoTrace.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <android-base/logging.h> +#include <android-base/properties.h> +#include <cutils/compiler.h> +#include <cutils/trace.h> +#include <jni.h> +#include <log/log.h> +#include <nativehelper/JNIHelp.h> +#include <nativehelper/scoped_local_ref.h> +#include <nativehelper/scoped_primitive_array.h> +#include <nativehelper/scoped_utf_chars.h> +#include <tracing_sdk.h> + +namespace android { +template <typename T> +inline static T* toPointer(jlong ptr) { + return reinterpret_cast<T*>(static_cast<uintptr_t>(ptr)); +} + +template <typename T> +inline static jlong toJLong(T* ptr) { + return static_cast<jlong>(reinterpret_cast<uintptr_t>(ptr)); +} + +static const char* fromJavaString(JNIEnv* env, jstring jstr) { + if (!jstr) return ""; + ScopedUtfChars chars(env, jstr); + + if (!chars.c_str()) { + ALOGE("Failed extracting string"); + return ""; + } + + return chars.c_str(); +} + +static void android_os_PerfettoTrace_event(JNIEnv* env, jclass, jint type, jlong cat_ptr, + jstring name, jlong extra_ptr) { + ScopedUtfChars name_utf(env, name); + if (!name_utf.c_str()) { + ALOGE("Failed extracting string"); + } + + tracing_perfetto::Category* category = toPointer<tracing_perfetto::Category>(cat_ptr); + tracing_perfetto::trace_event(type, category->get(), name_utf.c_str(), + toPointer<tracing_perfetto::Extra>(extra_ptr)); +} + +static jlong android_os_PerfettoTrace_get_process_track_uuid() { + return tracing_perfetto::get_process_track_uuid(); +} + +static jlong android_os_PerfettoTrace_get_thread_track_uuid(jlong tid) { + return tracing_perfetto::get_thread_track_uuid(tid); +} + +static void android_os_PerfettoTrace_activate_trigger(JNIEnv* env, jclass, jstring name, + jint ttl_ms) { + ScopedUtfChars name_utf(env, name); + if (!name_utf.c_str()) { + ALOGE("Failed extracting string"); + return; + } + + tracing_perfetto::activate_trigger(name_utf.c_str(), static_cast<uint32_t>(ttl_ms)); +} + +static jlong android_os_PerfettoTraceCategory_init(JNIEnv* env, jclass, jstring name, jstring tag, + jstring severity) { + return toJLong(new tracing_perfetto::Category(fromJavaString(env, name), + fromJavaString(env, tag), + fromJavaString(env, severity))); +} + +static jlong android_os_PerfettoTraceCategory_delete() { + return toJLong(&tracing_perfetto::Category::delete_category); +} + +static void android_os_PerfettoTraceCategory_register(jlong ptr) { + tracing_perfetto::Category* category = toPointer<tracing_perfetto::Category>(ptr); + category->register_category(); +} + +static void android_os_PerfettoTraceCategory_unregister(jlong ptr) { + tracing_perfetto::Category* category = toPointer<tracing_perfetto::Category>(ptr); + category->unregister_category(); +} + +static jboolean android_os_PerfettoTraceCategory_is_enabled(jlong ptr) { + tracing_perfetto::Category* category = toPointer<tracing_perfetto::Category>(ptr); + return category->is_category_enabled(); +} + +static jlong android_os_PerfettoTraceCategory_get_extra_ptr(jlong ptr) { + tracing_perfetto::Category* category = toPointer<tracing_perfetto::Category>(ptr); + return toJLong(category->get()); +} + +static const JNINativeMethod gCategoryMethods[] = { + {"native_init", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J", + (void*)android_os_PerfettoTraceCategory_init}, + {"native_delete", "()J", (void*)android_os_PerfettoTraceCategory_delete}, + {"native_register", "(J)V", (void*)android_os_PerfettoTraceCategory_register}, + {"native_unregister", "(J)V", (void*)android_os_PerfettoTraceCategory_unregister}, + {"native_is_enabled", "(J)Z", (void*)android_os_PerfettoTraceCategory_is_enabled}, + {"native_get_extra_ptr", "(J)J", (void*)android_os_PerfettoTraceCategory_get_extra_ptr}, +}; + +static const JNINativeMethod gTraceMethods[] = + {{"native_event", "(IJLjava/lang/String;J)V", (void*)android_os_PerfettoTrace_event}, + {"native_get_process_track_uuid", "()J", + (void*)android_os_PerfettoTrace_get_process_track_uuid}, + {"native_get_thread_track_uuid", "(J)J", + (void*)android_os_PerfettoTrace_get_thread_track_uuid}, + {"native_activate_trigger", "(Ljava/lang/String;I)V", + (void*)android_os_PerfettoTrace_activate_trigger}}; + +int register_android_os_PerfettoTrace(JNIEnv* env) { + int res = jniRegisterNativeMethods(env, "android/os/PerfettoTrace", gTraceMethods, + NELEM(gTraceMethods)); + + res = jniRegisterNativeMethods(env, "android/os/PerfettoTrace$Category", gCategoryMethods, + NELEM(gCategoryMethods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods."); + + return 0; +} + +} // namespace android diff --git a/core/jni/android_os_PerfettoTrackEventExtra.cpp b/core/jni/android_os_PerfettoTrackEventExtra.cpp new file mode 100644 index 000000000000..9adad7bca940 --- /dev/null +++ b/core/jni/android_os_PerfettoTrackEventExtra.cpp @@ -0,0 +1,536 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <cutils/compiler.h> +#include <cutils/trace.h> +#include <jni.h> +#include <log/log.h> +#include <nativehelper/JNIHelp.h> +#include <nativehelper/scoped_utf_chars.h> +#include <tracing_sdk.h> + +static constexpr ssize_t kMaxStrLen = 4096; +namespace android { +template <typename T> +inline static T* toPointer(jlong ptr) { + return reinterpret_cast<T*>(static_cast<uintptr_t>(ptr)); +} + +template <typename T> +inline static jlong toJLong(T* ptr) { + return static_cast<jlong>(reinterpret_cast<uintptr_t>(ptr)); +} + +static const char* fromJavaString(JNIEnv* env, jstring jstr) { + if (!jstr) return ""; + ScopedUtfChars chars(env, jstr); + + if (!chars.c_str()) { + ALOGE("Failed extracting string"); + return ""; + } + + return chars.c_str(); +} + +static jlong android_os_PerfettoTrackEventExtraArgInt64_init(JNIEnv* env, jclass, jstring name) { + return toJLong(new tracing_perfetto::DebugArg<int64_t>(fromJavaString(env, name))); +} + +static jlong android_os_PerfettoTrackEventExtraArgBool_init(JNIEnv* env, jclass, jstring name) { + return toJLong(new tracing_perfetto::DebugArg<bool>(fromJavaString(env, name))); +} + +static jlong android_os_PerfettoTrackEventExtraArgDouble_init(JNIEnv* env, jclass, jstring name) { + return toJLong(new tracing_perfetto::DebugArg<double>(fromJavaString(env, name))); +} + +static jlong android_os_PerfettoTrackEventExtraArgString_init(JNIEnv* env, jclass, jstring name) { + return toJLong(new tracing_perfetto::DebugArg<const char*>(fromJavaString(env, name))); +} + +static jlong android_os_PerfettoTrackEventExtraArgInt64_delete() { + return toJLong(&tracing_perfetto::DebugArg<int64_t>::delete_arg); +} + +static jlong android_os_PerfettoTrackEventExtraArgBool_delete() { + return toJLong(&tracing_perfetto::DebugArg<bool>::delete_arg); +} + +static jlong android_os_PerfettoTrackEventExtraArgDouble_delete() { + return toJLong(&tracing_perfetto::DebugArg<double>::delete_arg); +} + +static jlong android_os_PerfettoTrackEventExtraArgString_delete() { + return toJLong(&tracing_perfetto::DebugArg<const char*>::delete_arg); +} + +static jlong android_os_PerfettoTrackEventExtraArgInt64_get_extra_ptr(jlong ptr) { + tracing_perfetto::DebugArg<int64_t>* arg = toPointer<tracing_perfetto::DebugArg<int64_t>>(ptr); + return toJLong(arg->get()); +} + +static jlong android_os_PerfettoTrackEventExtraArgBool_get_extra_ptr(jlong ptr) { + tracing_perfetto::DebugArg<bool>* arg = toPointer<tracing_perfetto::DebugArg<bool>>(ptr); + return toJLong(arg->get()); +} + +static jlong android_os_PerfettoTrackEventExtraArgDouble_get_extra_ptr(jlong ptr) { + tracing_perfetto::DebugArg<double>* arg = toPointer<tracing_perfetto::DebugArg<double>>(ptr); + return toJLong(arg->get()); +} + +static jlong android_os_PerfettoTrackEventExtraArgString_get_extra_ptr(jlong ptr) { + tracing_perfetto::DebugArg<const char*>* arg = + toPointer<tracing_perfetto::DebugArg<const char*>>(ptr); + return toJLong(arg->get()); +} + +static void android_os_PerfettoTrackEventExtraArgInt64_set_value(jlong ptr, jlong val) { + tracing_perfetto::DebugArg<int64_t>* arg = toPointer<tracing_perfetto::DebugArg<int64_t>>(ptr); + arg->set_value(val); +} + +static void android_os_PerfettoTrackEventExtraArgBool_set_value(jlong ptr, jboolean val) { + tracing_perfetto::DebugArg<bool>* arg = toPointer<tracing_perfetto::DebugArg<bool>>(ptr); + arg->set_value(val); +} + +static void android_os_PerfettoTrackEventExtraArgDouble_set_value(jlong ptr, jdouble val) { + tracing_perfetto::DebugArg<double>* arg = toPointer<tracing_perfetto::DebugArg<double>>(ptr); + arg->set_value(val); +} + +static void android_os_PerfettoTrackEventExtraArgString_set_value(JNIEnv* env, jclass, jlong ptr, + jstring val) { + tracing_perfetto::DebugArg<const char*>* arg = + toPointer<tracing_perfetto::DebugArg<const char*>>(ptr); + arg->set_value(strdup(fromJavaString(env, val))); +} + +static jlong android_os_PerfettoTrackEventExtraFieldInt64_init() { + return toJLong(new tracing_perfetto::ProtoField<int64_t>()); +} + +static jlong android_os_PerfettoTrackEventExtraFieldDouble_init() { + return toJLong(new tracing_perfetto::ProtoField<double>()); +} + +static jlong android_os_PerfettoTrackEventExtraFieldString_init() { + return toJLong(new tracing_perfetto::ProtoField<const char*>()); +} + +static jlong android_os_PerfettoTrackEventExtraFieldNested_init() { + return toJLong(new tracing_perfetto::ProtoFieldNested()); +} + +static jlong android_os_PerfettoTrackEventExtraFieldInt64_delete() { + return toJLong(&tracing_perfetto::ProtoField<int64_t>::delete_field); +} + +static jlong android_os_PerfettoTrackEventExtraFieldDouble_delete() { + return toJLong(&tracing_perfetto::ProtoField<double>::delete_field); +} + +static jlong android_os_PerfettoTrackEventExtraFieldString_delete() { + return toJLong(&tracing_perfetto::ProtoField<const char*>::delete_field); +} + +static jlong android_os_PerfettoTrackEventExtraFieldNested_delete() { + return toJLong(&tracing_perfetto::ProtoFieldNested::delete_field); +} + +static jlong android_os_PerfettoTrackEventExtraFieldInt64_get_extra_ptr(jlong ptr) { + tracing_perfetto::ProtoField<int64_t>* field = + toPointer<tracing_perfetto::ProtoField<int64_t>>(ptr); + return toJLong(field->get()); +} + +static jlong android_os_PerfettoTrackEventExtraFieldDouble_get_extra_ptr(jlong ptr) { + tracing_perfetto::ProtoField<double>* field = + toPointer<tracing_perfetto::ProtoField<double>>(ptr); + return toJLong(field->get()); +} + +static jlong android_os_PerfettoTrackEventExtraFieldString_get_extra_ptr(jlong ptr) { + tracing_perfetto::ProtoField<const char*>* field = + toPointer<tracing_perfetto::ProtoField<const char*>>(ptr); + return toJLong(field->get()); +} + +static jlong android_os_PerfettoTrackEventExtraFieldNested_get_extra_ptr(jlong ptr) { + tracing_perfetto::ProtoFieldNested* field = toPointer<tracing_perfetto::ProtoFieldNested>(ptr); + return toJLong(field->get()); +} + +static void android_os_PerfettoTrackEventExtraFieldInt64_set_value(jlong ptr, jlong id, jlong val) { + tracing_perfetto::ProtoField<int64_t>* field = + toPointer<tracing_perfetto::ProtoField<int64_t>>(ptr); + field->set_value(id, val); +} + +static void android_os_PerfettoTrackEventExtraFieldDouble_set_value(jlong ptr, jlong id, + jdouble val) { + tracing_perfetto::ProtoField<double>* field = + toPointer<tracing_perfetto::ProtoField<double>>(ptr); + field->set_value(id, val); +} + +static void android_os_PerfettoTrackEventExtraFieldString_set_value(JNIEnv* env, jclass, jlong ptr, + jlong id, jstring val) { + tracing_perfetto::ProtoField<const char*>* field = + toPointer<tracing_perfetto::ProtoField<const char*>>(ptr); + field->set_value(id, strdup(fromJavaString(env, val))); +} + +static void android_os_PerfettoTrackEventExtraFieldNested_add_field(jlong field_ptr, + jlong arg_ptr) { + tracing_perfetto::ProtoFieldNested* field = + toPointer<tracing_perfetto::ProtoFieldNested>(field_ptr); + field->add_field(toPointer<PerfettoTeHlProtoField>(arg_ptr)); +} + +static void android_os_PerfettoTrackEventExtraFieldNested_set_id(jlong ptr, jlong id) { + tracing_perfetto::ProtoFieldNested* field = toPointer<tracing_perfetto::ProtoFieldNested>(ptr); + field->set_id(id); +} + +static jlong android_os_PerfettoTrackEventExtraFlow_init() { + return toJLong(new tracing_perfetto::Flow()); +} + +static void android_os_PerfettoTrackEventExtraFlow_set_process_flow(jlong ptr, jlong id) { + tracing_perfetto::Flow* flow = toPointer<tracing_perfetto::Flow>(ptr); + flow->set_process_flow(id); +} + +static void android_os_PerfettoTrackEventExtraFlow_set_process_terminating_flow(jlong ptr, + jlong id) { + tracing_perfetto::Flow* flow = toPointer<tracing_perfetto::Flow>(ptr); + flow->set_process_terminating_flow(id); +} + +static jlong android_os_PerfettoTrackEventExtraFlow_delete() { + return toJLong(&tracing_perfetto::Flow::delete_flow); +} + +static jlong android_os_PerfettoTrackEventExtraFlow_get_extra_ptr(jlong ptr) { + tracing_perfetto::Flow* flow = toPointer<tracing_perfetto::Flow>(ptr); + return toJLong(flow->get()); +} + +static jlong android_os_PerfettoTrackEventExtraNamedTrack_init(JNIEnv* env, jclass, jlong id, + jstring name, jlong parent_uuid) { + return toJLong(new tracing_perfetto::NamedTrack(id, parent_uuid, fromJavaString(env, name))); +} + +static jlong android_os_PerfettoTrackEventExtraNamedTrack_delete() { + return toJLong(&tracing_perfetto::NamedTrack::delete_track); +} + +static jlong android_os_PerfettoTrackEventExtraNamedTrack_get_extra_ptr(jlong ptr) { + tracing_perfetto::NamedTrack* track = toPointer<tracing_perfetto::NamedTrack>(ptr); + return toJLong(track->get()); +} + +static jlong android_os_PerfettoTrackEventExtraCounterTrack_init(JNIEnv* env, jclass, jstring name, + jlong parent_uuid) { + return toJLong( + new tracing_perfetto::RegisteredTrack(1, parent_uuid, fromJavaString(env, name), true)); +} + +static jlong android_os_PerfettoTrackEventExtraCounterTrack_delete() { + return toJLong(&tracing_perfetto::RegisteredTrack::delete_track); +} + +static jlong android_os_PerfettoTrackEventExtraCounterTrack_get_extra_ptr(jlong ptr) { + tracing_perfetto::RegisteredTrack* track = toPointer<tracing_perfetto::RegisteredTrack>(ptr); + return toJLong(track->get()); +} + +static jlong android_os_PerfettoTrackEventExtraCounterInt64_init() { + return toJLong(new tracing_perfetto::Counter<int64_t>()); +} + +static jlong android_os_PerfettoTrackEventExtraCounterInt64_delete() { + return toJLong(&tracing_perfetto::Counter<int64_t>::delete_counter); +} + +static void android_os_PerfettoTrackEventExtraCounterInt64_set_value(jlong ptr, jlong val) { + tracing_perfetto::Counter<int64_t>* counter = + toPointer<tracing_perfetto::Counter<int64_t>>(ptr); + counter->set_value(val); +} + +static jlong android_os_PerfettoTrackEventExtraCounterInt64_get_extra_ptr(jlong ptr) { + tracing_perfetto::Counter<int64_t>* counter = + toPointer<tracing_perfetto::Counter<int64_t>>(ptr); + return toJLong(counter->get()); +} + +static jlong android_os_PerfettoTrackEventExtraCounterDouble_init() { + return toJLong(new tracing_perfetto::Counter<double>()); +} + +static jlong android_os_PerfettoTrackEventExtraCounterDouble_delete() { + return toJLong(&tracing_perfetto::Counter<double>::delete_counter); +} + +static void android_os_PerfettoTrackEventExtraCounterDouble_set_value(jlong ptr, jdouble val) { + tracing_perfetto::Counter<double>* counter = toPointer<tracing_perfetto::Counter<double>>(ptr); + counter->set_value(val); +} + +static jlong android_os_PerfettoTrackEventExtraCounterDouble_get_extra_ptr(jlong ptr) { + tracing_perfetto::Counter<double>* counter = toPointer<tracing_perfetto::Counter<double>>(ptr); + return toJLong(counter->get()); +} + +static jlong android_os_PerfettoTrackEventExtra_init() { + return toJLong(new tracing_perfetto::Extra()); +} + +static jlong android_os_PerfettoTrackEventExtra_delete() { + return toJLong(&tracing_perfetto::Extra::delete_extra); +} + +static void android_os_PerfettoTrackEventExtra_add_arg(jlong extra_ptr, jlong arg_ptr) { + tracing_perfetto::Extra* extra = toPointer<tracing_perfetto::Extra>(extra_ptr); + extra->push_extra(toPointer<PerfettoTeHlExtra>(arg_ptr)); +} + +static void android_os_PerfettoTrackEventExtra_clear_args(jlong ptr) { + tracing_perfetto::Extra* extra = toPointer<tracing_perfetto::Extra>(ptr); + extra->clear_extras(); +} + +static jlong android_os_PerfettoTrackEventExtraProto_init() { + return toJLong(new tracing_perfetto::Proto()); +} + +static jlong android_os_PerfettoTrackEventExtraProto_delete() { + return toJLong(&tracing_perfetto::Proto::delete_proto); +} + +static jlong android_os_PerfettoTrackEventExtraProto_get_extra_ptr(jlong ptr) { + tracing_perfetto::Proto* proto = toPointer<tracing_perfetto::Proto>(ptr); + return toJLong(proto->get()); +} + +static void android_os_PerfettoTrackEventExtraProto_add_field(long proto_ptr, jlong arg_ptr) { + tracing_perfetto::Proto* proto = toPointer<tracing_perfetto::Proto>(proto_ptr); + proto->add_field(toPointer<PerfettoTeHlProtoField>(arg_ptr)); +} + +static void android_os_PerfettoTrackEventExtraProto_clear_fields(jlong ptr) { + tracing_perfetto::Proto* proto = toPointer<tracing_perfetto::Proto>(ptr); + proto->clear_fields(); +} + +static const JNINativeMethod gExtraMethods[] = + {{"native_init", "()J", (void*)android_os_PerfettoTrackEventExtra_init}, + {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtra_delete}, + {"native_add_arg", "(JJ)V", (void*)android_os_PerfettoTrackEventExtra_add_arg}, + {"native_clear_args", "(J)V", (void*)android_os_PerfettoTrackEventExtra_clear_args}}; + +static const JNINativeMethod gProtoMethods[] = + {{"native_init", "()J", (void*)android_os_PerfettoTrackEventExtraProto_init}, + {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraProto_delete}, + {"native_get_extra_ptr", "(J)J", + (void*)android_os_PerfettoTrackEventExtraProto_get_extra_ptr}, + {"native_add_field", "(JJ)V", (void*)android_os_PerfettoTrackEventExtraProto_add_field}, + {"native_clear_fields", "(J)V", + (void*)android_os_PerfettoTrackEventExtraProto_clear_fields}}; + +static const JNINativeMethod gArgInt64Methods[] = { + {"native_init", "(Ljava/lang/String;)J", + (void*)android_os_PerfettoTrackEventExtraArgInt64_init}, + {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraArgInt64_delete}, + {"native_get_extra_ptr", "(J)J", + (void*)android_os_PerfettoTrackEventExtraArgInt64_get_extra_ptr}, + {"native_set_value", "(JJ)V", (void*)android_os_PerfettoTrackEventExtraArgInt64_set_value}, +}; + +static const JNINativeMethod gArgBoolMethods[] = { + {"native_init", "(Ljava/lang/String;)J", + (void*)android_os_PerfettoTrackEventExtraArgBool_init}, + {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraArgBool_delete}, + {"native_get_extra_ptr", "(J)J", + (void*)android_os_PerfettoTrackEventExtraArgBool_get_extra_ptr}, + {"native_set_value", "(JZ)V", (void*)android_os_PerfettoTrackEventExtraArgBool_set_value}, +}; + +static const JNINativeMethod gArgDoubleMethods[] = { + {"native_init", "(Ljava/lang/String;)J", + (void*)android_os_PerfettoTrackEventExtraArgDouble_init}, + {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraArgDouble_delete}, + {"native_get_extra_ptr", "(J)J", + (void*)android_os_PerfettoTrackEventExtraArgDouble_get_extra_ptr}, + {"native_set_value", "(JD)V", (void*)android_os_PerfettoTrackEventExtraArgDouble_set_value}, +}; + +static const JNINativeMethod gArgStringMethods[] = { + {"native_init", "(Ljava/lang/String;)J", + (void*)android_os_PerfettoTrackEventExtraArgString_init}, + {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraArgString_delete}, + {"native_get_extra_ptr", "(J)J", + (void*)android_os_PerfettoTrackEventExtraArgString_get_extra_ptr}, + {"native_set_value", "(JLjava/lang/String;)V", + (void*)android_os_PerfettoTrackEventExtraArgString_set_value}, +}; + +static const JNINativeMethod gFieldInt64Methods[] = { + {"native_init", "()J", (void*)android_os_PerfettoTrackEventExtraFieldInt64_init}, + {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraFieldInt64_delete}, + {"native_get_extra_ptr", "(J)J", + (void*)android_os_PerfettoTrackEventExtraFieldInt64_get_extra_ptr}, + {"native_set_value", "(JJJ)V", + (void*)android_os_PerfettoTrackEventExtraFieldInt64_set_value}, +}; + +static const JNINativeMethod gFieldDoubleMethods[] = { + {"native_init", "()J", (void*)android_os_PerfettoTrackEventExtraFieldDouble_init}, + {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraFieldDouble_delete}, + {"native_get_extra_ptr", "(J)J", + (void*)android_os_PerfettoTrackEventExtraFieldDouble_get_extra_ptr}, + {"native_set_value", "(JJD)V", + (void*)android_os_PerfettoTrackEventExtraFieldDouble_set_value}, +}; + +static const JNINativeMethod gFieldStringMethods[] = { + {"native_init", "()J", (void*)android_os_PerfettoTrackEventExtraFieldString_init}, + {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraFieldString_delete}, + {"native_get_extra_ptr", "(J)J", + (void*)android_os_PerfettoTrackEventExtraFieldString_get_extra_ptr}, + {"native_set_value", "(JJLjava/lang/String;)V", + (void*)android_os_PerfettoTrackEventExtraFieldString_set_value}, +}; + +static const JNINativeMethod gFieldNestedMethods[] = + {{"native_init", "()J", (void*)android_os_PerfettoTrackEventExtraFieldNested_init}, + {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraFieldNested_delete}, + {"native_get_extra_ptr", "(J)J", + (void*)android_os_PerfettoTrackEventExtraFieldNested_get_extra_ptr}, + {"native_add_field", "(JJ)V", + (void*)android_os_PerfettoTrackEventExtraFieldNested_add_field}, + {"native_set_id", "(JJ)V", (void*)android_os_PerfettoTrackEventExtraFieldNested_set_id}}; + +static const JNINativeMethod gFlowMethods[] = { + {"native_init", "()J", (void*)android_os_PerfettoTrackEventExtraFlow_init}, + {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraFlow_delete}, + {"native_set_process_flow", "(JJ)V", + (void*)android_os_PerfettoTrackEventExtraFlow_set_process_flow}, + {"native_set_process_terminating_flow", "(JJ)V", + (void*)android_os_PerfettoTrackEventExtraFlow_set_process_terminating_flow}, + {"native_get_extra_ptr", "(J)J", + (void*)android_os_PerfettoTrackEventExtraFlow_get_extra_ptr}, +}; + +static const JNINativeMethod gNamedTrackMethods[] = { + {"native_init", "(JLjava/lang/String;J)J", + (void*)android_os_PerfettoTrackEventExtraNamedTrack_init}, + {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraNamedTrack_delete}, + {"native_get_extra_ptr", "(J)J", + (void*)android_os_PerfettoTrackEventExtraNamedTrack_get_extra_ptr}, +}; + +static const JNINativeMethod gCounterTrackMethods[] = + {{"native_init", "(Ljava/lang/String;J)J", + (void*)android_os_PerfettoTrackEventExtraCounterTrack_init}, + {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraCounterTrack_delete}, + {"native_get_extra_ptr", "(J)J", + (void*)android_os_PerfettoTrackEventExtraCounterTrack_get_extra_ptr}}; + +static const JNINativeMethod gCounterInt64Methods[] = + {{"native_init", "()J", (void*)android_os_PerfettoTrackEventExtraCounterInt64_init}, + {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraCounterInt64_delete}, + {"native_set_value", "(JJ)V", + (void*)android_os_PerfettoTrackEventExtraCounterInt64_set_value}, + {"native_get_extra_ptr", "(J)J", + (void*)android_os_PerfettoTrackEventExtraCounterInt64_get_extra_ptr}}; + +static const JNINativeMethod gCounterDoubleMethods[] = + {{"native_init", "()J", (void*)android_os_PerfettoTrackEventExtraCounterDouble_init}, + {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraCounterDouble_delete}, + {"native_set_value", "(JD)V", + (void*)android_os_PerfettoTrackEventExtraCounterDouble_set_value}, + {"native_get_extra_ptr", "(J)J", + (void*)android_os_PerfettoTrackEventExtraCounterDouble_get_extra_ptr}}; + +int register_android_os_PerfettoTrackEventExtra(JNIEnv* env) { + int res = jniRegisterNativeMethods(env, "android/os/PerfettoTrackEventExtra$ArgInt64", + gArgInt64Methods, NELEM(gArgInt64Methods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register arg int64 native methods."); + + res = jniRegisterNativeMethods(env, "android/os/PerfettoTrackEventExtra$ArgBool", + gArgBoolMethods, NELEM(gArgBoolMethods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register arg bool native methods."); + + res = jniRegisterNativeMethods(env, "android/os/PerfettoTrackEventExtra$ArgDouble", + gArgDoubleMethods, NELEM(gArgDoubleMethods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register arg double native methods."); + + res = jniRegisterNativeMethods(env, "android/os/PerfettoTrackEventExtra$ArgString", + gArgStringMethods, NELEM(gArgStringMethods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register arg string native methods."); + + res = jniRegisterNativeMethods(env, "android/os/PerfettoTrackEventExtra$FieldInt64", + gFieldInt64Methods, NELEM(gFieldInt64Methods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register field int64 native methods."); + + res = jniRegisterNativeMethods(env, "android/os/PerfettoTrackEventExtra$FieldDouble", + gFieldDoubleMethods, NELEM(gFieldDoubleMethods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register field double native methods."); + + res = jniRegisterNativeMethods(env, "android/os/PerfettoTrackEventExtra$FieldString", + gFieldStringMethods, NELEM(gFieldStringMethods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register field string native methods."); + + res = jniRegisterNativeMethods(env, "android/os/PerfettoTrackEventExtra$FieldNested", + gFieldNestedMethods, NELEM(gFieldNestedMethods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register field nested native methods."); + + res = jniRegisterNativeMethods(env, "android/os/PerfettoTrackEventExtra", gExtraMethods, + NELEM(gExtraMethods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register extra native methods."); + + res = jniRegisterNativeMethods(env, "android/os/PerfettoTrackEventExtra$Proto", gProtoMethods, + NELEM(gProtoMethods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register proto native methods."); + + res = jniRegisterNativeMethods(env, "android/os/PerfettoTrackEventExtra$Flow", gFlowMethods, + NELEM(gFlowMethods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register flow native methods."); + + res = jniRegisterNativeMethods(env, "android/os/PerfettoTrackEventExtra$NamedTrack", + gNamedTrackMethods, NELEM(gNamedTrackMethods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register named track native methods."); + + res = jniRegisterNativeMethods(env, "android/os/PerfettoTrackEventExtra$CounterTrack", + gCounterTrackMethods, NELEM(gCounterTrackMethods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register counter track native methods."); + + res = jniRegisterNativeMethods(env, "android/os/PerfettoTrackEventExtra$CounterInt64", + gCounterInt64Methods, NELEM(gCounterInt64Methods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register counter int64 native methods."); + + res = jniRegisterNativeMethods(env, "android/os/PerfettoTrackEventExtra$CounterDouble", + gCounterDoubleMethods, NELEM(gCounterDoubleMethods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register counter double native methods."); + return 0; +} + +} // namespace android diff --git a/core/jni/platform/darwin/libandroid_runtime_export.exp b/core/jni/platform/darwin/libandroid_runtime_export.exp new file mode 100644 index 000000000000..00a7585719ea --- /dev/null +++ b/core/jni/platform/darwin/libandroid_runtime_export.exp @@ -0,0 +1,38 @@ +# +# Copyright (C) 2024 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# symbols needed for the JNI operations +_JNI_OnLoad +_ANativeWindow* + +# symbols needed to link with layoutlib_jni +___android_log* +__ZNK7android7RefBase* +__ZN7android4base9SetLogger* +__ZN7android4base10SetAborter* +__ZN7android4base11GetProperty* +__ZN7android4Rect* +__ZN7android5Fence* +__ZN7android7RefBase* +__ZN7android7String* +__ZN7android10VectorImpl* +__ZN7android11BufferQueue* +__ZN7android14AndroidRuntime* +__ZN7android14sp_report_raceEv* +__ZN7android15KeyCharacterMap* +__ZN7android15InputDeviceInfo* +__ZN7android31android_view_InputDevice_create* +__ZN7android53android_view_Surface_createFromIGraphicBufferProducer* diff --git a/core/jni/platform/linux/libandroid_runtime_export.txt b/core/jni/platform/linux/libandroid_runtime_export.txt new file mode 100644 index 000000000000..50e0b750f61e --- /dev/null +++ b/core/jni/platform/linux/libandroid_runtime_export.txt @@ -0,0 +1,49 @@ +# +# Copyright (C) 2024 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +{ + global: + # symbols needed for the JNI operations + JNI_OnLoad; + ANativeWindow*; + + # symbols needed to link with layoutlib_jni + __android_log*; + _ZNK7android7RefBase*; + _ZN7android4base9SetLogger*; + _ZN7android4base10SetAborter*; + _ZN7android4base11GetProperty*; + _ZN7android4Rect*; + _ZN7android5Fence*; + _ZN7android7RefBase*; + _ZN7android7String*; + _ZN7android10VectorImpl*; + _ZN7android11BufferQueue*; + _ZN7android14AndroidRuntime*; + _ZN7android14sp_report_raceEv*; + _ZN7android15KeyCharacterMap*; + _ZN7android15InputDeviceInfo*; + _ZN7android31android_view_InputDevice_create*; + _ZN7android53android_view_Surface_createFromIGraphicBufferProducer*; + + # symbols needed by Ravenwood to override system properties + __system_property_find; + __system_property_get; + __system_property_read_callback; + __system_property_set; + local: + *; +}; diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index c67a0f9659f0..3ef3dfdc0183 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -119,6 +119,7 @@ android_test { "android.view.flags-aconfig-java", ], jni_libs: [ + "libperfetto_trace_test_jni", "libpowermanagertest_jni", "libviewRootImplTest_jni", "libworksourceparceltest_jni", @@ -260,6 +261,7 @@ android_ravenwood_test { "compatibility-device-util-axt-ravenwood", "flag-junit", "platform-test-annotations", + "perfetto_trace_java_protos", "flag-junit", "testng", ], diff --git a/core/tests/coretests/jni/Android.bp b/core/tests/coretests/jni/Android.bp index d6379ca8c3e6..798ec90eb884 100644 --- a/core/tests/coretests/jni/Android.bp +++ b/core/tests/coretests/jni/Android.bp @@ -111,3 +111,27 @@ cc_test_library { ], gtest: false, } + +cc_test_library { + name: "libperfetto_trace_test_jni", + srcs: [ + "PerfettoTraceTest.cpp", + ], + static_libs: [ + "perfetto_trace_protos", + "libtracing_perfetto_test_utils", + ], + shared_libs: [ + "liblog", + "libnativehelper", + "libperfetto_c", + "libprotobuf-cpp-lite", + "libtracing_perfetto", + ], + stl: "libc++_static", + cflags: [ + "-Werror", + "-Wall", + ], + gtest: false, +} diff --git a/core/tests/coretests/jni/PerfettoTraceTest.cpp b/core/tests/coretests/jni/PerfettoTraceTest.cpp new file mode 100644 index 000000000000..41d02ed70c9a --- /dev/null +++ b/core/tests/coretests/jni/PerfettoTraceTest.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// #define LOG_NDEBUG 0 +#define LOG_TAG "PerfettoTraceTest" + +#include <nativehelper/JNIHelp.h> +#include <utils/Log.h> + +#include "jni.h" +#include "perfetto/public/abi/data_source_abi.h" +#include "perfetto/public/abi/heap_buffer.h" +#include "perfetto/public/abi/pb_decoder_abi.h" +#include "perfetto/public/abi/tracing_session_abi.h" +#include "perfetto/public/abi/track_event_abi.h" +#include "perfetto/public/compiler.h" +#include "perfetto/public/data_source.h" +#include "perfetto/public/pb_decoder.h" +#include "perfetto/public/producer.h" +#include "perfetto/public/protos/config/trace_config.pzc.h" +#include "perfetto/public/protos/trace/interned_data/interned_data.pzc.h" +#include "perfetto/public/protos/trace/test_event.pzc.h" +#include "perfetto/public/protos/trace/trace.pzc.h" +#include "perfetto/public/protos/trace/trace_packet.pzc.h" +#include "perfetto/public/protos/trace/track_event/debug_annotation.pzc.h" +#include "perfetto/public/protos/trace/track_event/track_descriptor.pzc.h" +#include "perfetto/public/protos/trace/track_event/track_event.pzc.h" +#include "perfetto/public/protos/trace/trigger.pzc.h" +#include "perfetto/public/te_category_macros.h" +#include "perfetto/public/te_macros.h" +#include "perfetto/public/track_event.h" +#include "protos/perfetto/trace/interned_data/interned_data.pb.h" +#include "protos/perfetto/trace/trace.pb.h" +#include "protos/perfetto/trace/trace_packet.pb.h" +#include "tracing_perfetto.h" +#include "utils.h" + +namespace android { +using ::perfetto::protos::EventCategory; +using ::perfetto::protos::EventName; +using ::perfetto::protos::FtraceEvent; +using ::perfetto::protos::FtraceEventBundle; +using ::perfetto::protos::InternedData; +using ::perfetto::protos::Trace; +using ::perfetto::protos::TracePacket; + +using ::perfetto::shlib::test_utils::TracingSession; + +struct TracingSessionHolder { + TracingSession tracing_session; +}; + +static void nativeRegisterPerfetto([[maybe_unused]] JNIEnv* env, jclass /* obj */) { + tracing_perfetto::registerWithPerfetto(false /* test */); +} + +static jlong nativeStartTracing(JNIEnv* env, jclass /* obj */, jbyteArray configBytes) { + jsize length = env->GetArrayLength(configBytes); + std::vector<uint8_t> data; + data.reserve(length); + env->GetByteArrayRegion(configBytes, 0, length, reinterpret_cast<jbyte*>(data.data())); + + TracingSession session = TracingSession::FromBytes(data.data(), length); + TracingSessionHolder* holder = new TracingSessionHolder(std::move(session)); + + return reinterpret_cast<long>(holder); +} + +static jbyteArray nativeStopTracing([[maybe_unused]] JNIEnv* env, jclass /* obj */, jlong ptr) { + TracingSessionHolder* holder = reinterpret_cast<TracingSessionHolder*>(ptr); + + // Stop + holder->tracing_session.FlushBlocking(5000); + holder->tracing_session.StopBlocking(); + + std::vector<uint8_t> data = holder->tracing_session.ReadBlocking(); + + delete holder; + + jbyteArray bytes = env->NewByteArray(data.size()); + env->SetByteArrayRegion(bytes, 0, data.size(), reinterpret_cast<jbyte*>(data.data())); + return bytes; +} + +extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) { + JNIEnv* env; + const JNINativeMethod methodTable[] = {/* name, signature, funcPtr */ + {"nativeStartTracing", "([B)J", + (void*)nativeStartTracing}, + {"nativeStopTracing", "(J)[B", (void*)nativeStopTracing}, + {"nativeRegisterPerfetto", "()V", + (void*)nativeRegisterPerfetto}}; + + if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + return JNI_ERR; + } + + jniRegisterNativeMethods(env, "android/os/PerfettoTraceTest", methodTable, + sizeof(methodTable) / sizeof(JNINativeMethod)); + + return JNI_VERSION_1_6; +} + +} /* namespace android */ diff --git a/core/tests/coretests/src/android/app/NotificationManagerTest.java b/core/tests/coretests/src/android/app/NotificationManagerTest.java index 3213abe13d8a..a47fc9436226 100644 --- a/core/tests/coretests/src/android/app/NotificationManagerTest.java +++ b/core/tests/coretests/src/android/app/NotificationManagerTest.java @@ -18,6 +18,7 @@ package android.app; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atMost; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -67,6 +68,8 @@ public class NotificationManagerTest { mClock.advanceByMillis(5); } + verify(mNotificationManager.mBackendService, atLeast(20)).enqueueNotificationWithTag(any(), + any(), any(), anyInt(), any(), anyInt()); verify(mNotificationManager.mBackendService, atMost(30)).enqueueNotificationWithTag(any(), any(), any(), anyInt(), any(), anyInt()); } @@ -101,7 +104,38 @@ public class NotificationManagerTest { @Test @EnableFlags(Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY) - public void notify_rapidAddAndCancel_isNotThrottled() throws Exception { + public void cancel_unnecessaryAndRapid_isThrottled() throws Exception { + + for (int i = 0; i < 100; i++) { + mNotificationManager.cancel(1); + mClock.advanceByMillis(5); + } + + verify(mNotificationManager.mBackendService, atLeast(20)).cancelNotificationWithTag(any(), + any(), any(), anyInt(), anyInt()); + verify(mNotificationManager.mBackendService, atMost(30)).cancelNotificationWithTag(any(), + any(), any(), anyInt(), anyInt()); + } + + @Test + @EnableFlags(Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY) + public void cancel_unnecessaryButReasonable_isNotThrottled() throws Exception { + // Scenario: the app tries to repeatedly cancel a single notification, but at a reasonable + // rate. Strange, but not what we're trying to block with NM_BINDER_PERF_THROTTLE_NOTIFY. + for (int i = 0; i < 100; i++) { + mNotificationManager.cancel(1); + mClock.advanceByMillis(500); + } + + verify(mNotificationManager.mBackendService, times(100)).cancelNotificationWithTag(any(), + any(), any(), anyInt(), anyInt()); + } + + @Test + @EnableFlags(Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY) + public void cancel_necessaryAndRapid_isNotThrottled() throws Exception { + // Scenario: the app posts and immediately cancels a bunch of notifications. Strange, + // but not what we're trying to block with NM_BINDER_PERF_THROTTLE_NOTIFY. Notification n = exampleNotification(); for (int i = 0; i < 100; i++) { @@ -112,6 +146,23 @@ public class NotificationManagerTest { verify(mNotificationManager.mBackendService, times(100)).enqueueNotificationWithTag(any(), any(), any(), anyInt(), any(), anyInt()); + verify(mNotificationManager.mBackendService, times(100)).cancelNotificationWithTag(any(), + any(), any(), anyInt(), anyInt()); + } + + @Test + @EnableFlags(Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY) + public void cancel_maybeNecessaryAndRapid_isNotThrottled() throws Exception { + // Scenario: the app posted a lot of notifications, is killed, then restarts (so NM client + // doesn't know about them), then cancels them one by one. We don't want to throttle this + // case. + for (int i = 0; i < 100; i++) { + mNotificationManager.cancel(i); + mClock.advanceByMillis(1); + } + + verify(mNotificationManager.mBackendService, times(100)).cancelNotificationWithTag(any(), + any(), any(), anyInt(), anyInt()); } private Notification exampleNotification() { diff --git a/core/tests/coretests/src/android/net/http/OWNERS b/core/tests/coretests/src/android/net/http/OWNERS new file mode 100644 index 000000000000..c93a4195c2d9 --- /dev/null +++ b/core/tests/coretests/src/android/net/http/OWNERS @@ -0,0 +1 @@ +include /core/java/android/net/http/OWNERS diff --git a/core/tests/coretests/src/android/net/http/X509TrustManagerExtensionsTest.java b/core/tests/coretests/src/android/net/http/X509TrustManagerExtensionsTest.java index 04aa62a3e38e..a6ad80d344c5 100644 --- a/core/tests/coretests/src/android/net/http/X509TrustManagerExtensionsTest.java +++ b/core/tests/coretests/src/android/net/http/X509TrustManagerExtensionsTest.java @@ -16,6 +16,17 @@ package android.net.http; +import static org.junit.Assert.fail; + +import android.platform.test.annotations.Presubmit; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.org.conscrypt.TrustManagerImpl; + +import org.junit.Test; +import org.junit.runner.RunWith; + import java.security.KeyStore; import java.security.cert.X509Certificate; @@ -23,11 +34,9 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; -import junit.framework.TestCase; - -import com.android.org.conscrypt.TrustManagerImpl; - -public class X509TrustManagerExtensionsTest extends TestCase { +@Presubmit +@RunWith(AndroidJUnit4.class) +public class X509TrustManagerExtensionsTest { private class NotATrustManagerImpl implements X509TrustManager { @@ -40,6 +49,7 @@ public class X509TrustManagerExtensionsTest extends TestCase { } } + @Test public void testBadCast() throws Exception { NotATrustManagerImpl ntmi = new NotATrustManagerImpl(); try { @@ -49,12 +59,14 @@ public class X509TrustManagerExtensionsTest extends TestCase { } } + @Test public void testGoodCast() throws Exception { String defaultType = KeyStore.getDefaultType(); TrustManagerImpl tmi = new TrustManagerImpl(KeyStore.getInstance(defaultType)); X509TrustManagerExtensions tme = new X509TrustManagerExtensions(tmi); } + @Test public void testNormalUseCase() throws Exception { String defaultAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); TrustManagerFactory tmf = TrustManagerFactory.getInstance(defaultAlgorithm); diff --git a/core/tests/coretests/src/android/os/PerfettoTraceTest.java b/core/tests/coretests/src/android/os/PerfettoTraceTest.java new file mode 100644 index 000000000000..292f7500479b --- /dev/null +++ b/core/tests/coretests/src/android/os/PerfettoTraceTest.java @@ -0,0 +1,600 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import static android.os.PerfettoTrace.Category; + +import static com.google.common.truth.Truth.assertThat; + +import static perfetto.protos.ChromeLatencyInfoOuterClass.ChromeLatencyInfo.LatencyComponentType.COMPONENT_INPUT_EVENT_LATENCY_BEGIN_RWH; +import static perfetto.protos.ChromeLatencyInfoOuterClass.ChromeLatencyInfo.LatencyComponentType.COMPONENT_INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL; + +import android.platform.test.annotations.IgnoreUnderRavenwood; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.util.ArraySet; +import android.util.Log; + +import androidx.test.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import perfetto.protos.ChromeLatencyInfoOuterClass.ChromeLatencyInfo; +import perfetto.protos.ChromeLatencyInfoOuterClass.ChromeLatencyInfo.ComponentInfo; +import perfetto.protos.DataSourceConfigOuterClass.DataSourceConfig; +import perfetto.protos.DebugAnnotationOuterClass.DebugAnnotation; +import perfetto.protos.DebugAnnotationOuterClass.DebugAnnotationName; +import perfetto.protos.InternedDataOuterClass.InternedData; +import perfetto.protos.SourceLocationOuterClass.SourceLocation; +import perfetto.protos.TraceConfigOuterClass.TraceConfig; +import perfetto.protos.TraceConfigOuterClass.TraceConfig.BufferConfig; +import perfetto.protos.TraceConfigOuterClass.TraceConfig.DataSource; +import perfetto.protos.TraceConfigOuterClass.TraceConfig.TriggerConfig; +import perfetto.protos.TraceConfigOuterClass.TraceConfig.TriggerConfig.Trigger; +import perfetto.protos.TraceOuterClass.Trace; +import perfetto.protos.TracePacketOuterClass.TracePacket; +import perfetto.protos.TrackDescriptorOuterClass.TrackDescriptor; +import perfetto.protos.TrackEventConfigOuterClass.TrackEventConfig; +import perfetto.protos.TrackEventOuterClass.EventCategory; +import perfetto.protos.TrackEventOuterClass.EventName; +import perfetto.protos.TrackEventOuterClass.TrackEvent; + +import java.util.List; +import java.util.Set; + +/** + * This class is used to test the native tracing support. Run this test + * while tracing on the emulator and then run traceview to view the trace. + */ +@RunWith(AndroidJUnit4.class) +@IgnoreUnderRavenwood(blockedBy = PerfettoTrace.class) +public class PerfettoTraceTest { + @Rule + public final CheckFlagsRule mCheckFlagsRule = + DeviceFlagsValueProvider.createCheckFlagsRule( + InstrumentationRegistry.getInstrumentation().getUiAutomation()); + + private static final String TAG = "PerfettoTraceTest"; + private static final String FOO = "foo"; + private static final String BAR = "bar"; + + private static final Category FOO_CATEGORY = new Category(FOO); + + private final Set<String> mCategoryNames = new ArraySet<>(); + private final Set<String> mEventNames = new ArraySet<>(); + private final Set<String> mDebugAnnotationNames = new ArraySet<>(); + private final Set<String> mTrackNames = new ArraySet<>(); + + static { + try { + System.loadLibrary("perfetto_trace_test_jni"); + Log.i(TAG, "Successfully loaded trace_test native library"); + } catch (UnsatisfiedLinkError ule) { + Log.w(TAG, "Could not load trace_test native library"); + } + } + + @Before + public void setUp() { + PerfettoTrace.register(); + nativeRegisterPerfetto(); + FOO_CATEGORY.register(); + + mCategoryNames.clear(); + mEventNames.clear(); + mDebugAnnotationNames.clear(); + mTrackNames.clear(); + } + + @Test + @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2) + public void testDebugAnnotations() throws Exception { + TraceConfig traceConfig = getTraceConfig(FOO); + + long ptr = nativeStartTracing(traceConfig.toByteArray()); + + PerfettoTrackEventExtra extra = PerfettoTrackEventExtra.builder() + .addFlow(2) + .addTerminatingFlow(3) + .addArg("long_val", 10000000000L) + .addArg("bool_val", true) + .addArg("double_val", 3.14) + .addArg("string_val", FOO) + .build(); + PerfettoTrace.instant(FOO_CATEGORY, "event", extra); + + byte[] traceBytes = nativeStopTracing(ptr); + + Trace trace = Trace.parseFrom(traceBytes); + + boolean hasTrackEvent = false; + boolean hasDebugAnnotations = false; + for (TracePacket packet: trace.getPacketList()) { + TrackEvent event; + if (packet.hasTrackEvent()) { + hasTrackEvent = true; + event = packet.getTrackEvent(); + + if (TrackEvent.Type.TYPE_INSTANT.equals(event.getType()) + && event.getDebugAnnotationsCount() == 4 && event.getFlowIdsCount() == 1 + && event.getTerminatingFlowIdsCount() == 1) { + hasDebugAnnotations = true; + + List<DebugAnnotation> annotations = event.getDebugAnnotationsList(); + + assertThat(annotations.get(0).getIntValue()).isEqualTo(10000000000L); + assertThat(annotations.get(1).getBoolValue()).isTrue(); + assertThat(annotations.get(2).getDoubleValue()).isEqualTo(3.14); + assertThat(annotations.get(3).getStringValue()).isEqualTo(FOO); + } + } + + collectInternedData(packet); + } + + assertThat(hasTrackEvent).isTrue(); + assertThat(hasDebugAnnotations).isTrue(); + assertThat(mCategoryNames).contains(FOO); + + assertThat(mDebugAnnotationNames).contains("long_val"); + assertThat(mDebugAnnotationNames).contains("bool_val"); + assertThat(mDebugAnnotationNames).contains("double_val"); + assertThat(mDebugAnnotationNames).contains("string_val"); + } + + @Test + @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2) + public void testDebugAnnotationsWithLamda() throws Exception { + TraceConfig traceConfig = getTraceConfig(FOO); + + long ptr = nativeStartTracing(traceConfig.toByteArray()); + + PerfettoTrace.instant(FOO_CATEGORY, "event", e -> e.addArg("long_val", 123L)); + + byte[] traceBytes = nativeStopTracing(ptr); + + Trace trace = Trace.parseFrom(traceBytes); + + boolean hasTrackEvent = false; + boolean hasDebugAnnotations = false; + for (TracePacket packet: trace.getPacketList()) { + TrackEvent event; + if (packet.hasTrackEvent()) { + hasTrackEvent = true; + event = packet.getTrackEvent(); + + if (TrackEvent.Type.TYPE_INSTANT.equals(event.getType()) + && event.getDebugAnnotationsCount() == 1) { + hasDebugAnnotations = true; + + List<DebugAnnotation> annotations = event.getDebugAnnotationsList(); + assertThat(annotations.get(0).getIntValue()).isEqualTo(123L); + } + } + } + + assertThat(hasTrackEvent).isTrue(); + assertThat(hasDebugAnnotations).isTrue(); + } + + @Test + @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2) + public void testNamedTrack() throws Exception { + TraceConfig traceConfig = getTraceConfig(FOO); + + long ptr = nativeStartTracing(traceConfig.toByteArray()); + + PerfettoTrackEventExtra beginExtra = PerfettoTrackEventExtra.builder() + .usingNamedTrack(FOO, PerfettoTrace.getProcessTrackUuid()) + .build(); + PerfettoTrace.begin(FOO_CATEGORY, "event", beginExtra); + + PerfettoTrackEventExtra endExtra = PerfettoTrackEventExtra.builder() + .usingNamedTrack("bar", PerfettoTrace.getThreadTrackUuid(Process.myTid())) + .build(); + PerfettoTrace.end(FOO_CATEGORY, endExtra); + + Trace trace = Trace.parseFrom(nativeStopTracing(ptr)); + + boolean hasTrackEvent = false; + boolean hasTrackUuid = false; + for (TracePacket packet: trace.getPacketList()) { + TrackEvent event; + if (packet.hasTrackEvent()) { + hasTrackEvent = true; + event = packet.getTrackEvent(); + + if (TrackEvent.Type.TYPE_SLICE_BEGIN.equals(event.getType()) + && event.hasTrackUuid()) { + hasTrackUuid = true; + } + + if (TrackEvent.Type.TYPE_SLICE_END.equals(event.getType()) + && event.hasTrackUuid()) { + hasTrackUuid &= true; + } + } + + collectInternedData(packet); + collectTrackNames(packet); + } + + assertThat(hasTrackEvent).isTrue(); + assertThat(hasTrackUuid).isTrue(); + assertThat(mCategoryNames).contains(FOO); + assertThat(mTrackNames).contains(FOO); + } + + @Test + @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2) + public void testCounter() throws Exception { + TraceConfig traceConfig = getTraceConfig(FOO); + + long ptr = nativeStartTracing(traceConfig.toByteArray()); + + PerfettoTrackEventExtra intExtra = PerfettoTrackEventExtra.builder() + .usingCounterTrack(FOO, PerfettoTrace.getProcessTrackUuid()) + .setCounter(16) + .build(); + PerfettoTrace.counter(FOO_CATEGORY, intExtra); + + PerfettoTrackEventExtra doubleExtra = PerfettoTrackEventExtra.builder() + .usingCounterTrack("bar", PerfettoTrace.getProcessTrackUuid()) + .setCounter(3.14) + .build(); + PerfettoTrace.counter(FOO_CATEGORY, doubleExtra); + + Trace trace = Trace.parseFrom(nativeStopTracing(ptr)); + + boolean hasTrackEvent = false; + boolean hasCounterValue = false; + boolean hasDoubleCounterValue = false; + for (TracePacket packet: trace.getPacketList()) { + TrackEvent event; + if (packet.hasTrackEvent()) { + hasTrackEvent = true; + event = packet.getTrackEvent(); + + if (TrackEvent.Type.TYPE_COUNTER.equals(event.getType()) + && event.getCounterValue() == 16) { + hasCounterValue = true; + } + + if (TrackEvent.Type.TYPE_COUNTER.equals(event.getType()) + && event.getDoubleCounterValue() == 3.14) { + hasDoubleCounterValue = true; + } + } + + collectTrackNames(packet); + } + + assertThat(hasTrackEvent).isTrue(); + assertThat(hasCounterValue).isTrue(); + assertThat(hasDoubleCounterValue).isTrue(); + assertThat(mTrackNames).contains(FOO); + assertThat(mTrackNames).contains(BAR); + } + + @Test + @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2) + public void testProto() throws Exception { + TraceConfig traceConfig = getTraceConfig(FOO); + + long ptr = nativeStartTracing(traceConfig.toByteArray()); + + PerfettoTrackEventExtra extra5 = PerfettoTrackEventExtra.builder() + .beginProto() + .beginNested(33L) + .addField(4L, 2L) + .addField(3, "ActivityManagerService.java:11489") + .endNested() + .addField(2001, "AIDL::IActivityManager") + .endProto() + .build(); + PerfettoTrace.instant(FOO_CATEGORY, "event_proto", extra5); + + byte[] traceBytes = nativeStopTracing(ptr); + + Trace trace = Trace.parseFrom(traceBytes); + + boolean hasTrackEvent = false; + boolean hasSourceLocation = false; + + for (TracePacket packet: trace.getPacketList()) { + TrackEvent event; + if (packet.hasTrackEvent()) { + hasTrackEvent = true; + event = packet.getTrackEvent(); + + if (TrackEvent.Type.TYPE_INSTANT.equals(event.getType()) + && event.hasSourceLocation()) { + SourceLocation loc = event.getSourceLocation(); + if ("ActivityManagerService.java:11489".equals(loc.getFunctionName()) + && loc.getLineNumber() == 2) { + hasSourceLocation = true; + } + } + } + + collectInternedData(packet); + } + + assertThat(hasTrackEvent).isTrue(); + assertThat(hasSourceLocation).isTrue(); + assertThat(mCategoryNames).contains(FOO); + } + + @Test + @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2) + public void testProtoNested() throws Exception { + TraceConfig traceConfig = getTraceConfig(FOO); + + long ptr = nativeStartTracing(traceConfig.toByteArray()); + + PerfettoTrackEventExtra extra6 = PerfettoTrackEventExtra.builder() + .beginProto() + .beginNested(29L) + .beginNested(4L) + .addField(1L, 2) + .addField(2L, 20000) + .endNested() + .beginNested(4L) + .addField(1L, 1) + .addField(2L, 40000) + .endNested() + .endNested() + .endProto() + .build(); + PerfettoTrace.instant(FOO_CATEGORY, "event_proto_nested", extra6); + + byte[] traceBytes = nativeStopTracing(ptr); + + Trace trace = Trace.parseFrom(traceBytes); + + boolean hasTrackEvent = false; + boolean hasChromeLatencyInfo = false; + + for (TracePacket packet: trace.getPacketList()) { + TrackEvent event; + if (packet.hasTrackEvent()) { + hasTrackEvent = true; + event = packet.getTrackEvent(); + + if (TrackEvent.Type.TYPE_INSTANT.equals(event.getType()) + && event.hasChromeLatencyInfo()) { + ChromeLatencyInfo latencyInfo = event.getChromeLatencyInfo(); + if (latencyInfo.getComponentInfoCount() == 2) { + hasChromeLatencyInfo = true; + ComponentInfo cmpInfo1 = latencyInfo.getComponentInfo(0); + assertThat(cmpInfo1.getComponentType()) + .isEqualTo(COMPONENT_INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL); + assertThat(cmpInfo1.getTimeUs()).isEqualTo(20000); + + ComponentInfo cmpInfo2 = latencyInfo.getComponentInfo(1); + assertThat(cmpInfo2.getComponentType()) + .isEqualTo(COMPONENT_INPUT_EVENT_LATENCY_BEGIN_RWH); + assertThat(cmpInfo2.getTimeUs()).isEqualTo(40000); + } + } + } + + collectInternedData(packet); + } + + assertThat(hasTrackEvent).isTrue(); + assertThat(hasChromeLatencyInfo).isTrue(); + assertThat(mCategoryNames).contains(FOO); + } + + @Test + @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2) + public void testActivateTrigger() throws Exception { + TraceConfig traceConfig = getTriggerTraceConfig(FOO, FOO); + + long ptr = nativeStartTracing(traceConfig.toByteArray()); + + PerfettoTrackEventExtra extra = PerfettoTrackEventExtra.builder().build(); + PerfettoTrace.instant(FOO_CATEGORY, "event_trigger", extra); + + PerfettoTrace.activateTrigger(FOO, 1000); + + byte[] traceBytes = nativeStopTracing(ptr); + + Trace trace = Trace.parseFrom(traceBytes); + + boolean hasTrackEvent = false; + boolean hasChromeLatencyInfo = false; + + for (TracePacket packet: trace.getPacketList()) { + TrackEvent event; + if (packet.hasTrackEvent()) { + hasTrackEvent = true; + } + + collectInternedData(packet); + } + + assertThat(mCategoryNames).contains(FOO); + } + + @Test + @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2) + public void testMultipleExtras() throws Exception { + boolean hasException = false; + try { + PerfettoTrackEventExtra.builder(); + + // Unclosed extra will throw an exception here + PerfettoTrackEventExtra.builder(); + } catch (Exception e) { + hasException = true; + } + + try { + PerfettoTrackEventExtra.builder().build(); + + // Closed extra but unused (reset hasn't been called internally) will throw an exception + // here. + PerfettoTrackEventExtra.builder(); + } catch (Exception e) { + hasException &= true; + } + + assertThat(hasException).isTrue(); + } + + @Test + @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2) + public void testRegister() throws Exception { + TraceConfig traceConfig = getTraceConfig(BAR); + + Category barCategory = new Category(BAR); + long ptr = nativeStartTracing(traceConfig.toByteArray()); + + PerfettoTrackEventExtra beforeExtra = PerfettoTrackEventExtra.builder() + .addArg("before", 1) + .build(); + PerfettoTrace.instant(barCategory, "event", beforeExtra); + + barCategory.register(); + + PerfettoTrackEventExtra afterExtra = PerfettoTrackEventExtra.builder() + .addArg("after", 1) + .build(); + PerfettoTrace.instant(barCategory, "event", afterExtra); + + byte[] traceBytes = nativeStopTracing(ptr); + + Trace trace = Trace.parseFrom(traceBytes); + + boolean hasTrackEvent = false; + for (TracePacket packet: trace.getPacketList()) { + TrackEvent event; + if (packet.hasTrackEvent()) { + hasTrackEvent = true; + event = packet.getTrackEvent(); + } + + collectInternedData(packet); + } + + assertThat(hasTrackEvent).isTrue(); + assertThat(mCategoryNames).contains(BAR); + + assertThat(mDebugAnnotationNames).contains("after"); + assertThat(mDebugAnnotationNames).doesNotContain("before"); + } + + private static native long nativeStartTracing(byte[] config); + private static native void nativeRegisterPerfetto(); + private static native byte[] nativeStopTracing(long ptr); + + private TrackEvent getTrackEvent(Trace trace, int idx) { + int curIdx = 0; + for (TracePacket packet: trace.getPacketList()) { + if (packet.hasTrackEvent()) { + if (curIdx++ == idx) { + return packet.getTrackEvent(); + } + } + } + + return null; + } + + private TraceConfig getTraceConfig(String cat) { + BufferConfig bufferConfig = BufferConfig.newBuilder().setSizeKb(1024).build(); + TrackEventConfig trackEventConfig = TrackEventConfig + .newBuilder() + .addEnabledCategories(cat) + .build(); + DataSourceConfig dsConfig = DataSourceConfig + .newBuilder() + .setName("track_event") + .setTargetBuffer(0) + .setTrackEventConfig(trackEventConfig) + .build(); + DataSource ds = DataSource.newBuilder().setConfig(dsConfig).build(); + TraceConfig traceConfig = TraceConfig + .newBuilder() + .addBuffers(bufferConfig) + .addDataSources(ds) + .build(); + return traceConfig; + } + + private TraceConfig getTriggerTraceConfig(String cat, String triggerName) { + BufferConfig bufferConfig = BufferConfig.newBuilder().setSizeKb(1024).build(); + TrackEventConfig trackEventConfig = TrackEventConfig + .newBuilder() + .addEnabledCategories(cat) + .build(); + DataSourceConfig dsConfig = DataSourceConfig + .newBuilder() + .setName("track_event") + .setTargetBuffer(0) + .setTrackEventConfig(trackEventConfig) + .build(); + DataSource ds = DataSource.newBuilder().setConfig(dsConfig).build(); + Trigger trigger = Trigger.newBuilder().setName(triggerName).build(); + TriggerConfig triggerConfig = TriggerConfig + .newBuilder() + .setTriggerMode(TriggerConfig.TriggerMode.STOP_TRACING) + .setTriggerTimeoutMs(1000) + .addTriggers(trigger) + .build(); + TraceConfig traceConfig = TraceConfig + .newBuilder() + .addBuffers(bufferConfig) + .addDataSources(ds) + .setTriggerConfig(triggerConfig) + .build(); + return traceConfig; + } + + private void collectInternedData(TracePacket packet) { + if (!packet.hasInternedData()) { + return; + } + + InternedData data = packet.getInternedData(); + + for (EventCategory cat : data.getEventCategoriesList()) { + mCategoryNames.add(cat.getName()); + } + for (EventName ev : data.getEventNamesList()) { + mEventNames.add(ev.getName()); + } + for (DebugAnnotationName dbg : data.getDebugAnnotationNamesList()) { + mDebugAnnotationNames.add(dbg.getName()); + } + } + + private void collectTrackNames(TracePacket packet) { + if (!packet.hasTrackDescriptor()) { + return; + } + TrackDescriptor desc = packet.getTrackDescriptor(); + mTrackNames.add(desc.getName()); + } +} diff --git a/libs/WindowManager/Shell/AndroidManifest.xml b/libs/WindowManager/Shell/AndroidManifest.xml index 636e3cfd571d..46fe53716c01 100644 --- a/libs/WindowManager/Shell/AndroidManifest.xml +++ b/libs/WindowManager/Shell/AndroidManifest.xml @@ -26,6 +26,7 @@ <uses-permission android:name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE" /> <uses-permission android:name="android.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION" /> <uses-permission android:name="android.permission.MANAGE_KEY_GESTURES" /> + <uses-permission android:name="android.permission.MANAGE_DISPLAYS" /> <application> <activity diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig index 500548500927..bbdcbc9147e4 100644 --- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig +++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig @@ -178,3 +178,10 @@ flag { description: "Factor task-view state tracking out of taskviewtransitions" bug: "384976265" } + +flag { + name: "enable_non_default_display_split" + namespace: "multitasking" + description: "Enables split screen on non default displays" + bug: "384999213" +} diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt index 04c9ffbac287..5c86b321b60f 100644 --- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt @@ -16,6 +16,7 @@ package com.android.wm.shell.bubbles.bar +import android.animation.AnimatorTestRule import android.content.Context import android.content.pm.LauncherApps import android.graphics.PointF @@ -25,7 +26,7 @@ import android.view.IWindowManager import android.view.MotionEvent import android.view.View import android.view.WindowManager -import androidx.core.animation.AnimatorTestRule +import androidx.core.view.children import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest @@ -41,7 +42,7 @@ import com.android.wm.shell.bubbles.Bubble import com.android.wm.shell.bubbles.BubbleController import com.android.wm.shell.bubbles.BubbleData import com.android.wm.shell.bubbles.BubbleDataRepository -import com.android.wm.shell.bubbles.BubbleEducationController +import com.android.wm.shell.bubbles.BubbleExpandedViewManager import com.android.wm.shell.bubbles.BubbleLogger import com.android.wm.shell.bubbles.BubblePositioner import com.android.wm.shell.bubbles.Bubbles.SysuiProxy @@ -68,32 +69,31 @@ import com.android.wm.shell.transition.Transitions import com.google.common.truth.Truth.assertThat import org.junit.After import org.junit.Before -import org.junit.ClassRule +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.mock import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever /** Tests for [BubbleBarLayerView] */ @SmallTest @RunWith(AndroidJUnit4::class) class BubbleBarLayerViewTest { - companion object { - @JvmField @ClassRule val animatorTestRule: AnimatorTestRule = AnimatorTestRule() - } + @get:Rule val animatorTestRule: AnimatorTestRule = AnimatorTestRule(this) private val context = ApplicationProvider.getApplicationContext<Context>() private lateinit var bubbleBarLayerView: BubbleBarLayerView - private lateinit var uiEventLoggerFake: UiEventLoggerFake - private lateinit var bubbleController: BubbleController - private lateinit var bubblePositioner: BubblePositioner - - private lateinit var bubble: Bubble + private lateinit var expandedViewManager: BubbleExpandedViewManager + private lateinit var mainExecutor: TestShellExecutor + private lateinit var bgExecutor: TestShellExecutor + private lateinit var bubbleLogger: BubbleLogger + private lateinit var testBubblesList: MutableList<Bubble> @Before fun setUp() { @@ -102,25 +102,20 @@ class BubbleBarLayerViewTest { PhysicsAnimatorTestUtils.prepareForTest() uiEventLoggerFake = UiEventLoggerFake() - val bubbleLogger = BubbleLogger(uiEventLoggerFake) + bubbleLogger = BubbleLogger(uiEventLoggerFake) - val mainExecutor = TestShellExecutor() - val bgExecutor = TestShellExecutor() + mainExecutor = TestShellExecutor() + bgExecutor = TestShellExecutor() val windowManager = context.getSystemService(WindowManager::class.java) bubblePositioner = BubblePositioner(context, windowManager) bubblePositioner.setShowingInBubbleBar(true) - val bubbleData = - BubbleData( - context, - bubbleLogger, - bubblePositioner, - BubbleEducationController(context), - mainExecutor, - bgExecutor, - ) + testBubblesList = mutableListOf() + val bubbleData = mock<BubbleData>() + whenever(bubbleData.bubbles).thenReturn(testBubblesList) + whenever(bubbleData.hasBubbles()).thenReturn(!testBubblesList.isEmpty()) bubbleController = createBubbleController( @@ -137,21 +132,7 @@ class BubbleBarLayerViewTest { bubbleBarLayerView = BubbleBarLayerView(context, bubbleController, bubbleData, bubbleLogger) - val expandedViewManager = FakeBubbleExpandedViewManager(bubbleBar = true, expanded = true) - val bubbleTaskView = FakeBubbleTaskViewFactory(context, mainExecutor).create() - val bubbleBarExpandedView = - FakeBubbleFactory.createExpandedView( - context, - bubblePositioner, - expandedViewManager, - bubbleTaskView, - mainExecutor, - bgExecutor, - bubbleLogger, - ) - - val viewInfo = FakeBubbleFactory.createViewInfo(bubbleBarExpandedView) - bubble = FakeBubbleFactory.createChatBubble(context, viewInfo = viewInfo) + expandedViewManager = FakeBubbleExpandedViewManager(bubbleBar = true, expanded = true) } @After @@ -221,7 +202,54 @@ class BubbleBarLayerViewTest { } @Test + fun showExpandedView() { + val bubble = createBubble("first") + + getInstrumentation().runOnMainSync { bubbleBarLayerView.showExpandedView(bubble) } + waitForExpandedViewAnimation() + + // Scrim, dismiss view and expanded view + assertThat(bubbleBarLayerView.childCount).isEqualTo(3) + assertThat(bubbleBarLayerView.getChildAt(2)).isEqualTo(bubble.bubbleBarExpandedView) + } + + @Test + fun twoBubbles_dismissActiveBubble_newBubbleShown() { + val firstBubble = createBubble("first") + val secondBubble = createBubble("second") + + getInstrumentation().runOnMainSync { bubbleBarLayerView.showExpandedView(firstBubble) } + waitForExpandedViewAnimation() + + getInstrumentation().runOnMainSync { bubbleBarLayerView.removeBubble(firstBubble) {} } + // Expanded view is removed when bubble is removed + assertThat(firstBubble.bubbleBarExpandedView).isNull() + + getInstrumentation().runOnMainSync { bubbleBarLayerView.showExpandedView(secondBubble) } + waitForExpandedViewAnimation() + + assertThat(bubbleBarLayerView.children.count { it is BubbleBarExpandedView }).isEqualTo(1) + assertThat(bubbleBarLayerView.children.last()).isEqualTo(secondBubble.bubbleBarExpandedView) + } + + @Test + fun twoBubbles_switchBubbles_newBubbleShown() { + val firstBubble = createBubble("first") + val secondBubble = createBubble("second") + + getInstrumentation().runOnMainSync { bubbleBarLayerView.showExpandedView(firstBubble) } + waitForExpandedViewAnimation() + + getInstrumentation().runOnMainSync { bubbleBarLayerView.showExpandedView(secondBubble) } + waitForExpandedViewAnimation() + + assertThat(bubbleBarLayerView.children.count { it is BubbleBarExpandedView }).isEqualTo(1) + assertThat(bubbleBarLayerView.children.last()).isEqualTo(secondBubble.bubbleBarExpandedView) + } + + @Test fun testEventLogging_dismissExpandedViewViaDrag() { + val bubble = createBubble("first") getInstrumentation().runOnMainSync { bubbleBarLayerView.showExpandedView(bubble) } assertThat(bubbleBarLayerView.findViewById<View>(R.id.bubble_bar_handle_view)).isNotNull() @@ -235,6 +263,7 @@ class BubbleBarLayerViewTest { @Test fun testEventLogging_dragExpandedViewLeft() { + val bubble = createBubble("first") bubblePositioner.bubbleBarLocation = BubbleBarLocation.RIGHT getInstrumentation().runOnMainSync { @@ -259,6 +288,7 @@ class BubbleBarLayerViewTest { @Test fun testEventLogging_dragExpandedViewRight() { + val bubble = createBubble("first") bubblePositioner.bubbleBarLocation = BubbleBarLocation.LEFT getInstrumentation().runOnMainSync { @@ -281,6 +311,27 @@ class BubbleBarLayerViewTest { assertThat(uiEventLoggerFake.logs[0]).hasBubbleInfo(bubble) } + private fun createBubble(key: String): Bubble { + val bubbleTaskView = FakeBubbleTaskViewFactory(context, mainExecutor).create() + val bubbleBarExpandedView = + FakeBubbleFactory.createExpandedView( + context, + bubblePositioner, + expandedViewManager, + bubbleTaskView, + mainExecutor, + bgExecutor, + bubbleLogger, + ) + // Mark visible so we don't wait for task view before animations can start + bubbleBarExpandedView.onContentVisibilityChanged(true) + + val viewInfo = FakeBubbleFactory.createViewInfo(bubbleBarExpandedView) + return FakeBubbleFactory.createChatBubble(context, key, viewInfo).also { + testBubblesList.add(it) + } + } + private fun leftEdge(): PointF { val screenSize = bubblePositioner.availableRect return PointF(screenSize.left.toFloat(), screenSize.height() / 2f) @@ -293,12 +344,12 @@ class BubbleBarLayerViewTest { private fun waitForExpandedViewAnimation() { // wait for idle to allow the animation to start - getInstrumentation().waitForIdleSync() - getInstrumentation().runOnMainSync { animatorTestRule.advanceTimeBy(200) } + getInstrumentation().runOnMainSync { animatorTestRule.advanceTimeBy(1000) } PhysicsAnimatorTestUtils.blockUntilAnimationsEnd( AnimatableScaleMatrix.SCALE_X, AnimatableScaleMatrix.SCALE_Y, ) + getInstrumentation().waitForIdleSync() } private fun View.dispatchTouchEvent(eventTime: Long, action: Int, point: PointF) { diff --git a/libs/WindowManager/Shell/shared/res/drawable/floating_dismiss_background.xml b/libs/WindowManager/Shell/shared/res/drawable/floating_dismiss_background.xml new file mode 100644 index 000000000000..003f397ff97d --- /dev/null +++ b/libs/WindowManager/Shell/shared/res/drawable/floating_dismiss_background.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<shape + xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="oval"> + + <stroke + android:width="2dp" + android:color="@android:color/system_primary_fixed" /> + + <solid android:color="@android:color/system_primary_fixed" /> +</shape>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/shared/res/drawable/floating_dismiss_ic_close.xml b/libs/WindowManager/Shell/shared/res/drawable/floating_dismiss_ic_close.xml new file mode 100644 index 000000000000..8b133a417f79 --- /dev/null +++ b/libs/WindowManager/Shell/shared/res/drawable/floating_dismiss_ic_close.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="32dp" + android:height="32dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:pathData="M19.000000,6.400000l-1.400000,-1.400000 -5.600000,5.600000 -5.600000,-5.600000 -1.400000,1.400000 5.600000,5.600000 -5.600000,5.600000 1.400000,1.400000 5.600000,-5.600000 5.600000,5.600000 1.400000,-1.400000 -5.600000,-5.600000z" + android:fillColor="@android:color/system_on_primary_fixed"/> +</vector> diff --git a/libs/WindowManager/Shell/shared/res/values/dimen.xml b/libs/WindowManager/Shell/shared/res/values/dimen.xml new file mode 100644 index 000000000000..0b1f76f5ce0e --- /dev/null +++ b/libs/WindowManager/Shell/shared/res/values/dimen.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources> + <dimen name="floating_dismiss_icon_size">32dp</dimen> + <dimen name="floating_dismiss_background_size">96dp</dimen> +</resources>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissViewExt.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissViewExt.kt index 00a81727a9ac..2f0b62c20df9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissViewExt.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissViewExt.kt @@ -19,16 +19,17 @@ package com.android.wm.shell.bubbles import com.android.wm.shell.R import com.android.wm.shell.shared.bubbles.DismissView +import com.android.wm.shell.shared.R as SharedR fun DismissView.setup() { setup(DismissView.Config( dismissViewResId = R.id.dismiss_view, - targetSizeResId = R.dimen.dismiss_circle_size, - iconSizeResId = R.dimen.dismiss_target_x_size, + targetSizeResId = SharedR.dimen.floating_dismiss_background_size, + iconSizeResId = SharedR.dimen.floating_dismiss_icon_size, bottomMarginResId = R.dimen.floating_dismiss_bottom_margin, floatingGradientHeightResId = R.dimen.floating_dismiss_gradient_height, floatingGradientColorResId = android.R.color.system_neutral1_900, - backgroundResId = R.drawable.dismiss_circle_background, - iconResId = R.drawable.pip_ic_close_white + backgroundResId = SharedR.drawable.floating_dismiss_background, + iconResId = SharedR.drawable.floating_dismiss_ic_close, )) }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java index 425afbed0742..88f34f3043e1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java @@ -184,7 +184,7 @@ public class BubbleBarLayerView extends FrameLayout } BubbleViewProvider previousBubble = null; if (mExpandedBubble != null && !b.getKey().equals(mExpandedBubble.getKey())) { - if (mIsExpanded) { + if (mIsExpanded && mExpandedBubble.getBubbleBarExpandedView() != null) { // Previous expanded view open, keep it visible to animate the switch previousBubble = mExpandedBubble; } else { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java index f532be6b8277..3a8a7f6e46d3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayTopology; import android.os.RemoteException; import android.util.ArraySet; import android.util.Size; @@ -54,6 +55,7 @@ public class DisplayController { private final ShellExecutor mMainExecutor; private final Context mContext; private final IWindowManager mWmService; + private final DisplayManager mDisplayManager; private final DisplayChangeController mChangeController; private final IDisplayWindowListener mDisplayContainerListener; @@ -61,10 +63,11 @@ public class DisplayController { private final ArrayList<OnDisplaysChangedListener> mDisplayChangedListeners = new ArrayList<>(); public DisplayController(Context context, IWindowManager wmService, ShellInit shellInit, - ShellExecutor mainExecutor) { + ShellExecutor mainExecutor, DisplayManager displayManager) { mMainExecutor = mainExecutor; mContext = context; mWmService = wmService; + mDisplayManager = displayManager; // TODO: Inject this instead mChangeController = new DisplayChangeController(mWmService, shellInit, mainExecutor); mDisplayContainerListener = new DisplayWindowListenerImpl(); @@ -74,7 +77,7 @@ public class DisplayController { } /** - * Initializes the window listener. + * Initializes the window listener and the topology listener. */ public void onInit() { try { @@ -82,6 +85,9 @@ public class DisplayController { for (int i = 0; i < displayIds.length; i++) { onDisplayAdded(displayIds[i]); } + + mDisplayManager.registerTopologyListener(mMainExecutor, this::onDisplayTopologyChanged); + onDisplayTopologyChanged(mDisplayManager.getDisplayTopology()); } catch (RemoteException e) { throw new RuntimeException("Unable to register display controller"); } @@ -91,8 +97,7 @@ public class DisplayController { * Gets a display by id from DisplayManager. */ public Display getDisplay(int displayId) { - final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); - return displayManager.getDisplay(displayId); + return mDisplayManager.getDisplay(displayId); } /** @@ -221,6 +226,14 @@ public class DisplayController { } } + private void onDisplayTopologyChanged(DisplayTopology topology) { + // TODO(b/381472611): Call DisplayTopology#getCoordinates and update values in + // DisplayLayout when DM code is ready. + for (int i = 0; i < mDisplayChangedListeners.size(); ++i) { + mDisplayChangedListeners.get(i).onTopologyChanged(); + } + } + private void onDisplayConfigurationChanged(int displayId, Configuration newConfig) { synchronized (mDisplays) { final DisplayRecord dr = mDisplays.get(displayId); @@ -408,5 +421,10 @@ public class DisplayController { */ default void onKeepClearAreasChanged(int displayId, Set<Rect> restricted, Set<Rect> unrestricted) {} + + /** + * Called when the display topology has changed. + */ + default void onTopologyChanged() {} } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java index b6a1686bd087..4973a6f16409 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java @@ -31,7 +31,9 @@ import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; import android.graphics.Insets; +import android.graphics.PointF; import android.graphics.Rect; +import android.graphics.RectF; import android.os.SystemProperties; import android.provider.Settings; import android.util.DisplayMetrics; @@ -71,9 +73,12 @@ public class DisplayLayout { public static final int NAV_BAR_RIGHT = 1 << 1; public static final int NAV_BAR_BOTTOM = 1 << 2; + private static final String TAG = "DisplayLayout"; + private int mUiMode; private int mWidth; private int mHeight; + private RectF mGlobalBoundsDp; private DisplayCutout mCutout; private int mRotation; private int mDensityDpi; @@ -109,6 +114,7 @@ public class DisplayLayout { return mUiMode == other.mUiMode && mWidth == other.mWidth && mHeight == other.mHeight + && Objects.equals(mGlobalBoundsDp, other.mGlobalBoundsDp) && Objects.equals(mCutout, other.mCutout) && mRotation == other.mRotation && mDensityDpi == other.mDensityDpi @@ -127,8 +133,8 @@ public class DisplayLayout { @Override public int hashCode() { - return Objects.hash(mUiMode, mWidth, mHeight, mCutout, mRotation, mDensityDpi, - mNonDecorInsets, mStableInsets, mHasNavigationBar, mHasStatusBar, + return Objects.hash(mUiMode, mWidth, mHeight, mGlobalBoundsDp, mCutout, mRotation, + mDensityDpi, mNonDecorInsets, mStableInsets, mHasNavigationBar, mHasStatusBar, mNavBarFrameHeight, mTaskbarFrameHeight, mAllowSeamlessRotationDespiteNavBarMoving, mNavigationBarCanMove, mReverseDefaultRotation, mInsetsState); } @@ -170,6 +176,7 @@ public class DisplayLayout { mUiMode = dl.mUiMode; mWidth = dl.mWidth; mHeight = dl.mHeight; + mGlobalBoundsDp = dl.mGlobalBoundsDp; mCutout = dl.mCutout; mRotation = dl.mRotation; mDensityDpi = dl.mDensityDpi; @@ -193,6 +200,7 @@ public class DisplayLayout { mRotation = info.rotation; mCutout = info.displayCutout; mDensityDpi = info.logicalDensityDpi; + mGlobalBoundsDp = new RectF(0, 0, pxToDp(mWidth), pxToDp(mHeight)); mHasNavigationBar = hasNavigationBar; mHasStatusBar = hasStatusBar; mAllowSeamlessRotationDespiteNavBarMoving = res.getBoolean( @@ -255,6 +263,11 @@ public class DisplayLayout { recalcInsets(res); } + /** Update the global bounds of this layout, in DP. */ + public void setGlobalBoundsDp(RectF bounds) { + mGlobalBoundsDp = bounds; + } + /** Get this layout's non-decor insets. */ public Rect nonDecorInsets() { return mNonDecorInsets; @@ -265,16 +278,21 @@ public class DisplayLayout { return mStableInsets; } - /** Get this layout's width. */ + /** Get this layout's width in pixels. */ public int width() { return mWidth; } - /** Get this layout's height. */ + /** Get this layout's height in pixels. */ public int height() { return mHeight; } + /** Get this layout's global bounds in the multi-display coordinate system in DP. */ + public RectF globalBoundsDp() { + return mGlobalBoundsDp; + } + /** Get this layout's display rotation. */ public int rotation() { return mRotation; @@ -486,4 +504,48 @@ public class DisplayLayout { ? R.dimen.navigation_bar_frame_height_landscape : R.dimen.navigation_bar_frame_height); } + + /** + * Converts a pixel value to a density-independent pixel (dp) value. + * + * @param px The pixel value to convert. + * @return The equivalent value in DP units. + */ + public float pxToDp(Number px) { + return px.floatValue() * DisplayMetrics.DENSITY_DEFAULT / mDensityDpi; + } + + /** + * Converts a density-independent pixel (dp) value to a pixel value. + * + * @param dp The DP value to convert. + * @return The equivalent value in pixel units. + */ + public float dpToPx(Number dp) { + return dp.floatValue() * mDensityDpi / DisplayMetrics.DENSITY_DEFAULT; + } + + /** + * Converts local pixel coordinates on this layout to global DP coordinates. + * + * @param xPx The x-coordinate in pixels, relative to the layout's origin. + * @param yPx The y-coordinate in pixels, relative to the layout's origin. + * @return A PointF object representing the coordinates in global DP units. + */ + public PointF localPxToGlobalDp(Number xPx, Number yPx) { + return new PointF(mGlobalBoundsDp.left + pxToDp(xPx), + mGlobalBoundsDp.top + pxToDp(yPx)); + } + + /** + * Converts global DP coordinates to local pixel coordinates on this layout. + * + * @param xDp The x-coordinate in global DP units. + * @param yDp The y-coordinate in global DP units. + * @return A PointF object representing the coordinates in local pixel units on this layout. + */ + public PointF globalDpToLocalPx(Number xDp, Number yDp) { + return new PointF(dpToPx(xDp.floatValue() - mGlobalBoundsDp.left), + dpToPx(yDp.floatValue() - mGlobalBoundsDp.top)); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java index fe6066c8c4fb..b796b411dd1a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java @@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityManager.RunningTaskInfo; import android.app.TaskInfo; import android.content.ComponentName; import android.content.Context; @@ -59,6 +60,7 @@ import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import com.android.wm.shell.sysui.KeyguardChangeListener; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; +import com.android.wm.shell.transition.FocusTransitionObserver; import com.android.wm.shell.transition.Transitions; import dagger.Lazy; @@ -196,6 +198,9 @@ public class CompatUIController implements OnDisplaysChangedListener, private final CompatUIStatusManager mCompatUIStatusManager; @NonNull + private final FocusTransitionObserver mFocusTransitionObserver; + + @NonNull private final Optional<DesktopUserRepositories> mDesktopUserRepositories; public CompatUIController(@NonNull Context context, @@ -212,7 +217,8 @@ public class CompatUIController implements OnDisplaysChangedListener, @NonNull CompatUIShellCommandHandler compatUIShellCommandHandler, @NonNull AccessibilityManager accessibilityManager, @NonNull CompatUIStatusManager compatUIStatusManager, - @NonNull Optional<DesktopUserRepositories> desktopUserRepositories) { + @NonNull Optional<DesktopUserRepositories> desktopUserRepositories, + @NonNull FocusTransitionObserver focusTransitionObserver) { mContext = context; mShellController = shellController; mDisplayController = displayController; @@ -229,6 +235,7 @@ public class CompatUIController implements OnDisplaysChangedListener, DISAPPEAR_DELAY_MS, flags); mCompatUIStatusManager = compatUIStatusManager; mDesktopUserRepositories = desktopUserRepositories; + mFocusTransitionObserver = focusTransitionObserver; shellInit.addInitCallback(this::onInit, this); } @@ -405,7 +412,8 @@ public class CompatUIController implements OnDisplaysChangedListener, // start tracking the buttons visibility for this task. if (mTopActivityTaskId != taskInfo.taskId && !taskInfo.isTopActivityTransparent - && taskInfo.isVisible && taskInfo.isFocused) { + && taskInfo.isVisible + && mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)) { mTopActivityTaskId = taskInfo.taskId; setHasShownUserAspectRatioSettingsButton(false); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index 6c805c87c08f..de0048a68ef9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -25,6 +25,7 @@ import android.annotation.NonNull; import android.app.ActivityTaskManager; import android.content.Context; import android.content.pm.PackageManager; +import android.hardware.display.DisplayManager; import android.os.Handler; import android.os.SystemProperties; import android.provider.Settings; @@ -172,8 +173,9 @@ public abstract class WMShellBaseModule { static DisplayController provideDisplayController(Context context, IWindowManager wmService, ShellInit shellInit, - @ShellMainThread ShellExecutor mainExecutor) { - return new DisplayController(context, wmService, shellInit, mainExecutor); + @ShellMainThread ShellExecutor mainExecutor, + DisplayManager displayManager) { + return new DisplayController(context, wmService, shellInit, mainExecutor, displayManager); } @WMSingleton @@ -272,7 +274,8 @@ public abstract class WMShellBaseModule { @NonNull CompatUIState compatUIState, @NonNull CompatUIComponentIdGenerator componentIdGenerator, @NonNull CompatUIComponentFactory compatUIComponentFactory, - CompatUIStatusManager compatUIStatusManager) { + CompatUIStatusManager compatUIStatusManager, + @NonNull FocusTransitionObserver focusTransitionObserver) { if (!context.getResources().getBoolean(R.bool.config_enableCompatUIController)) { return Optional.empty(); } @@ -297,7 +300,8 @@ public abstract class WMShellBaseModule { compatUIShellCommandHandler.get(), accessibilityManager.get(), compatUIStatusManager, - desktopUserRepositories)); + desktopUserRepositories, + focusTransitionObserver)); } @WMSingleton diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt index ccfbbeef89c9..e975b586c1ee 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt @@ -40,6 +40,7 @@ import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterRe import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskUpdate +import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_HANDLE_MENU_BUTTON import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_KEYBOARD_SHORTCUT @@ -363,7 +364,7 @@ class DesktopModeLoggerTransitionObserver( || (transitionInfo.type == WindowManager.TRANSIT_TO_BACK && wasPreviousTransitionExitByScreenOff) -> EnterReason.SCREEN_ON - transitionInfo.type == Transitions.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP -> + transitionInfo.type == TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP -> EnterReason.APP_HANDLE_DRAG transitionInfo.type == TRANSIT_ENTER_DESKTOP_FROM_APP_HANDLE_MENU_BUTTON -> EnterReason.APP_HANDLE_MENU_BUTTON diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTransitionTypes.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTransitionTypes.kt index 9b3caca7b2d4..2a10edb8a1c2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTransitionTypes.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTransitionTypes.kt @@ -35,6 +35,18 @@ object DesktopModeTransitionTypes { const val TRANSIT_EXIT_DESKTOP_MODE_KEYBOARD_SHORTCUT = TRANSIT_DESKTOP_MODE_TYPES + 7 const val TRANSIT_EXIT_DESKTOP_MODE_UNKNOWN = TRANSIT_DESKTOP_MODE_TYPES + 8 + /** Transition type for starting the drag to desktop mode. */ + const val TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP = TRANSIT_DESKTOP_MODE_TYPES + 9 + + /** Transition type for finalizing the drag to desktop mode. */ + const val TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP = TRANSIT_DESKTOP_MODE_TYPES + 10 + + /** Transition type to cancel the drag to desktop mode. */ + const val TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP = TRANSIT_DESKTOP_MODE_TYPES + 11 + + /** Transition type to animate the toggle resize between the max and default desktop sizes. */ + const val TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE = TRANSIT_DESKTOP_MODE_TYPES + 12 + /** Return whether the [TransitionType] corresponds to a transition to enter desktop mode. */ @JvmStatic fun @receiver:TransitionType Int.isEnterDesktopModeTransition(): Boolean { @@ -92,4 +104,18 @@ object DesktopModeTransitionTypes { else -> TRANSIT_EXIT_DESKTOP_MODE_UNKNOWN } } + + /** + * Returns a string representing the [TransitionType]. If not supported, returns an empty + * string. + */ + @JvmStatic + fun transitTypeToString(transitType: Int): String = + when (transitType) { + TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP -> "DESKTOP_MODE_START_DRAG_TO_DESKTOP" + TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP -> "DESKTOP_MODE_END_DRAG_TO_DESKTOP" + TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP -> "DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP" + TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE -> "DESKTOP_MODE_TOGGLE_RESIZE" + else -> "" + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index a3d3a90fef3e..94955709bf79 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -881,6 +881,12 @@ class DesktopTasksController( applyFreeformDisplayChange(wct, task, displayId) } wct.reparent(task.token, displayAreaInfo.token, true /* onTop */) + if (Flags.enableDisplayFocusInShellTransitions()) { + // Bring the destination display to top with includingParents=true, so that the + // destination display gains the display focus, which makes the top task in the display + // gains the global focus. + wct.reorder(task.token, /* onTop= */ true, /* includingParents= */ true) + } if (Flags.enablePerDisplayDesktopWallpaperActivity()) { performDesktopExitCleanupIfNeeded(task.taskId, task.displayId, wct) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt index d23c9d0b8ffd..72c064248988 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt @@ -37,6 +37,9 @@ import com.android.internal.jank.InteractionJankMonitor import com.android.internal.protolog.ProtoLog import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.animation.FloatProperties +import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP +import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP +import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP import com.android.wm.shell.protolog.ShellProtoLogGroup import com.android.wm.shell.shared.TransitionUtil import com.android.wm.shell.shared.animation.PhysicsAnimator @@ -46,9 +49,6 @@ import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UND import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition import com.android.wm.shell.splitscreen.SplitScreenController import com.android.wm.shell.transition.Transitions -import com.android.wm.shell.transition.Transitions.TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP -import com.android.wm.shell.transition.Transitions.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP -import com.android.wm.shell.transition.Transitions.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP import com.android.wm.shell.transition.Transitions.TransitionHandler import com.android.wm.shell.windowdecor.MoveToDesktopAnimator import com.android.wm.shell.windowdecor.MoveToDesktopAnimator.Companion.DRAG_FREEFORM_SCALE diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt index e683f62644c4..a47e9370b58d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt @@ -30,8 +30,8 @@ import android.window.WindowContainerTransaction import androidx.core.animation.addListener import com.android.internal.jank.Cuj import com.android.internal.jank.InteractionJankMonitor +import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE import com.android.wm.shell.transition.Transitions -import com.android.wm.shell.transition.Transitions.TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE import com.android.wm.shell.windowdecor.OnTaskResizeAnimationListener import java.util.function.Supplier diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java index 1c7e62b71218..b5220c4ffb50 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java @@ -20,7 +20,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.view.Display.DEFAULT_DISPLAY; import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED; -import static com.android.wm.shell.transition.Transitions.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP; +import static com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP; import static com.android.wm.shell.transition.Transitions.TransitionObserver; import android.annotation.NonNull; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index a7d6301ecf06..df81821ff13f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -85,6 +85,7 @@ import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.ExternalInterfaceBinder; import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes; import com.android.wm.shell.keyguard.KeyguardTransitionHandler; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.shared.FocusTransitionListener; @@ -167,22 +168,6 @@ public class Transitions implements RemoteCallable<Transitions>, /** Transition type for maximize to freeform transition. */ public static final int TRANSIT_RESTORE_FROM_MAXIMIZE = WindowManager.TRANSIT_FIRST_CUSTOM + 9; - /** Transition type for starting the drag to desktop mode. */ - public static final int TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP = - WindowManager.TRANSIT_FIRST_CUSTOM + 10; - - /** Transition type for finalizing the drag to desktop mode. */ - public static final int TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP = - WindowManager.TRANSIT_FIRST_CUSTOM + 11; - - /** Transition type to cancel the drag to desktop mode. */ - public static final int TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP = - WindowManager.TRANSIT_FIRST_CUSTOM + 13; - - /** Transition type to animate the toggle resize between the max and default desktop sizes. */ - public static final int TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE = - WindowManager.TRANSIT_FIRST_CUSTOM + 14; - /** Transition to resize PiP task. */ public static final int TRANSIT_RESIZE_PIP = TRANSIT_FIRST_CUSTOM + 16; @@ -1872,11 +1857,6 @@ public class Transitions implements RemoteCallable<Transitions>, case TRANSIT_SPLIT_DISMISS -> "SPLIT_DISMISS"; case TRANSIT_MAXIMIZE -> "MAXIMIZE"; case TRANSIT_RESTORE_FROM_MAXIMIZE -> "RESTORE_FROM_MAXIMIZE"; - case TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP -> "DESKTOP_MODE_START_DRAG_TO_DESKTOP"; - case TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP -> "DESKTOP_MODE_END_DRAG_TO_DESKTOP"; - case TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP -> - "DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP"; - case TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE -> "DESKTOP_MODE_TOGGLE_RESIZE"; case TRANSIT_RESIZE_PIP -> "RESIZE_PIP"; case TRANSIT_TASK_FRAGMENT_DRAG_RESIZE -> "TASK_FRAGMENT_DRAG_RESIZE"; case TRANSIT_SPLIT_PASSTHROUGH -> "SPLIT_PASSTHROUGH"; @@ -1886,6 +1866,9 @@ public class Transitions implements RemoteCallable<Transitions>, case TRANSIT_END_RECENTS_TRANSITION -> "END_RECENTS_TRANSITION"; default -> ""; }; + if (typeStr.isEmpty()) { + typeStr = DesktopModeTransitionTypes.transitTypeToString(transitType); + } return typeStr + "(FIRST_CUSTOM+" + (transitType - TRANSIT_FIRST_CUSTOM) + ")"; } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayControllerTests.java index 1e5e153fdfe1..d3de0f7c09b4 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayControllerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayControllerTests.java @@ -22,6 +22,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.content.Context; +import android.hardware.display.DisplayManager; import android.view.IWindowManager; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -50,12 +51,14 @@ public class DisplayControllerTests extends ShellTestCase { private @Mock IWindowManager mWM; private @Mock ShellInit mShellInit; private @Mock ShellExecutor mMainExecutor; + private @Mock DisplayManager mDisplayManager; private DisplayController mController; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mController = new DisplayController(mContext, mWM, mShellInit, mMainExecutor); + mController = new DisplayController( + mContext, mWM, mShellInit, mMainExecutor, mDisplayManager); } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java index d467b399ebbb..b0a455d1bcf8 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java @@ -33,7 +33,9 @@ import static org.mockito.Mockito.when; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Insets; +import android.graphics.PointF; import android.graphics.Rect; +import android.graphics.RectF; import android.view.DisplayCutout; import android.view.DisplayInfo; @@ -58,6 +60,7 @@ import org.mockito.quality.Strictness; @SmallTest public class DisplayLayoutTest extends ShellTestCase { private MockitoSession mMockitoSession; + private static final float DELTA = 0.1f; // Constant for assertion delta @Before public void setup() { @@ -130,6 +133,39 @@ public class DisplayLayoutTest extends ShellTestCase { assertEquals(new Rect(40, 0, 60, 0), dl.nonDecorInsets()); } + @Test + public void testDpPxConversion() { + int px = 100; + float dp = 53.33f; + int xPx = 100; + int yPx = 200; + float xDp = 164.33f; + float yDp = 328.66f; + + Resources res = createResources(40, 50, false); + DisplayInfo info = createDisplayInfo(1000, 1500, 0, ROTATION_0); + DisplayLayout dl = new DisplayLayout(info, res, false, false); + dl.setGlobalBoundsDp(new RectF(111f, 222f, 300f, 400f)); + + // Test pxToDp + float resultDp = dl.pxToDp(px); + assertEquals(dp, resultDp, DELTA); + + // Test dpToPx + float resultPx = dl.dpToPx(dp); + assertEquals(px, resultPx, DELTA); + + // Test localPxToGlobalDp + PointF resultGlobalDp = dl.localPxToGlobalDp(xPx, yPx); + assertEquals(xDp, resultGlobalDp.x, DELTA); + assertEquals(yDp, resultGlobalDp.y, DELTA); + + // Test globalDpToLocalPx + PointF resultLocalPx = dl.globalDpToLocalPx(xDp, yDp); + assertEquals(xPx, resultLocalPx.x, DELTA); + assertEquals(yPx, resultLocalPx.y, DELTA); + } + private Resources createResources(int navLand, int navPort, boolean navMoves) { Configuration cfg = new Configuration(); cfg.uiMode = UI_MODE_TYPE_NORMAL; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java index ecf766db0be3..784e1907894d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java @@ -62,6 +62,7 @@ import com.android.wm.shell.desktopmode.DesktopRepository; import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; +import com.android.wm.shell.transition.FocusTransitionObserver; import com.android.wm.shell.transition.Transitions; import dagger.Lazy; @@ -127,6 +128,8 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { private DesktopUserRepositories mDesktopUserRepositories; @Mock private DesktopRepository mDesktopRepository; + @Mock + private FocusTransitionObserver mFocusTransitionObserver; @Captor ArgumentCaptor<OnInsetsChangedListener> mOnInsetsChangedListenerCaptor; @@ -162,7 +165,8 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { mMockDisplayController, mMockDisplayInsetsController, mMockImeController, mMockSyncQueue, mMockExecutor, mMockTransitionsLazy, mDockStateReader, mCompatUIConfiguration, mCompatUIShellCommandHandler, mAccessibilityManager, - mCompatUIStatusManager, Optional.of(mDesktopUserRepositories)) { + mCompatUIStatusManager, Optional.of(mDesktopUserRepositories), + mFocusTransitionObserver) { @Override CompatUIWindowManager createCompatUiWindowManager(Context context, TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener) { @@ -280,6 +284,7 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { doReturn(false).when(mMockRestartDialogLayout).updateCompatInfo(any(), any(), anyBoolean()); TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); + when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(true); mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); verify(mController).createCompatUiWindowManager(any(), eq(taskInfo), eq(mMockTaskListener)); @@ -411,6 +416,7 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { // Verify button remains hidden while IME is showing. TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); + when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(false); verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */ false); @@ -443,6 +449,7 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { // Verify button remains hidden while keyguard is showing. TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); + when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(false); verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */ false); @@ -523,6 +530,7 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) public void testRestartLayoutRecreatedIfNeeded() { final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); + when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(false); doReturn(true).when(mMockRestartDialogLayout) .needsToBeRecreated(any(TaskInfo.class), any(ShellTaskOrganizer.TaskListener.class)); @@ -538,6 +546,7 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) public void testRestartLayoutNotRecreatedIfNotNeeded() { final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); + when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(false); doReturn(false).when(mMockRestartDialogLayout) .needsToBeRecreated(any(TaskInfo.class), any(ShellTaskOrganizer.TaskListener.class)); @@ -558,7 +567,8 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { // Create new task final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, - /* isVisible */ true, /* isFocused */ true); + /* isVisible */ true); + when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(true); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo); @@ -574,7 +584,8 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { public void testUpdateActiveTaskInfo_newTask_notVisibleOrFocused_notUpdated() { // Create new task final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, - /* isVisible */ true, /* isFocused */ true); + /* isVisible */ true); + when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(true); // Simulate task being shown mController.updateActiveTaskInfo(taskInfo); @@ -592,7 +603,8 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { // Create visible but NOT focused task final TaskInfo taskInfo1 = createTaskInfo(DISPLAY_ID, newTaskId, /* hasSizeCompat= */ true, - /* isVisible */ true, /* isFocused */ false); + /* isVisible */ true); + when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(false); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo1); @@ -604,7 +616,8 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { // Create focused but NOT visible task final TaskInfo taskInfo2 = createTaskInfo(DISPLAY_ID, newTaskId, /* hasSizeCompat= */ true, - /* isVisible */ false, /* isFocused */ true); + /* isVisible */ false); + when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(true); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo2); @@ -616,7 +629,8 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { // Create NOT focused but NOT visible task final TaskInfo taskInfo3 = createTaskInfo(DISPLAY_ID, newTaskId, /* hasSizeCompat= */ true, - /* isVisible */ false, /* isFocused */ false); + /* isVisible */ false); + when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(false); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo3); @@ -632,7 +646,8 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { public void testUpdateActiveTaskInfo_sameTask_notUpdated() { // Create new task final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, - /* isVisible */ true, /* isFocused */ true); + /* isVisible */ true); + when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(true); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo); @@ -660,7 +675,8 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { public void testUpdateActiveTaskInfo_transparentTask_notUpdated() { // Create new task final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, - /* isVisible */ true, /* isFocused */ true); + /* isVisible */ true); + when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(true); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo); @@ -678,7 +694,8 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { // Create transparent task final TaskInfo taskInfo1 = createTaskInfo(DISPLAY_ID, newTaskId, /* hasSizeCompat= */ true, - /* isVisible */ true, /* isFocused */ true, /* isTopActivityTransparent */ true); + /* isVisible */ true, /* isTopActivityTransparent */ true); + when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(true); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo1); @@ -694,6 +711,7 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { public void testLetterboxEduLayout_notCreatedWhenLetterboxEducationIsDisabled() { TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); taskInfo.appCompatTaskInfo.setLetterboxEducationEnabled(false); + when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(false); mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); @@ -707,6 +725,7 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { public void testUpdateActiveTaskInfo_removeAllComponentWhenInDesktopModeFlagEnabled() { TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); when(mDesktopUserRepositories.getCurrent().getVisibleTaskCount(DISPLAY_ID)).thenReturn(0); + when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(false); mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); @@ -725,6 +744,7 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { public void testUpdateActiveTaskInfo_removeAllComponentWhenInDesktopModeFlagDisabled() { when(mDesktopUserRepositories.getCurrent().getVisibleTaskCount(DISPLAY_ID)).thenReturn(0); TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); + when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(false); mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); @@ -739,23 +759,22 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { private static TaskInfo createTaskInfo(int displayId, int taskId, boolean hasSizeCompat) { return createTaskInfo(displayId, taskId, hasSizeCompat, /* isVisible */ false, - /* isFocused */ false, /* isTopActivityTransparent */ false); + /* isTopActivityTransparent */ false); } private static TaskInfo createTaskInfo(int displayId, int taskId, boolean hasSizeCompat, - boolean isVisible, boolean isFocused) { + boolean isVisible) { return createTaskInfo(displayId, taskId, hasSizeCompat, - isVisible, isFocused, /* isTopActivityTransparent */ false); + isVisible, /* isTopActivityTransparent */ false); } private static TaskInfo createTaskInfo(int displayId, int taskId, boolean hasSizeCompat, - boolean isVisible, boolean isFocused, boolean isTopActivityTransparent) { + boolean isVisible, boolean isTopActivityTransparent) { RunningTaskInfo taskInfo = new RunningTaskInfo(); taskInfo.taskId = taskId; taskInfo.displayId = displayId; taskInfo.appCompatTaskInfo.setTopActivityInSizeCompat(hasSizeCompat); taskInfo.isVisible = isVisible; - taskInfo.isFocused = isFocused; taskInfo.isTopActivityTransparent = isTopActivityTransparent; taskInfo.appCompatTaskInfo.setLetterboxEducationEnabled(true); taskInfo.appCompatTaskInfo.setTopActivityLetterboxed(true); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt index 9d410137fc4a..4317143aebfe 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt @@ -48,6 +48,7 @@ import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterRe import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskUpdate +import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_HANDLE_MENU_BUTTON import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_KEYBOARD_SHORTCUT @@ -175,7 +176,7 @@ class DesktopModeLoggerTransitionObserverTest : ShellTestCase() { val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(WINDOWING_MODE_FREEFORM)) // task change is finalised when drag ends val transitionInfo = - TransitionInfoBuilder(Transitions.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP, 0) + TransitionInfoBuilder(TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP, 0) .addChange(change) .build() @@ -436,7 +437,7 @@ class DesktopModeLoggerTransitionObserverTest : ShellTestCase() { // desktop right after turning the screen on, we move to fullscreen then move another task // to desktop val transitionInfo = - TransitionInfoBuilder(Transitions.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP, 0) + TransitionInfoBuilder(TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP, 0) .addChange(createChange(TRANSIT_TO_FRONT, freeformTask)) .build() callOnTransitionReady(transitionInfo) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index e1c2153014fa..61aec739724a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -82,6 +82,7 @@ import com.android.dx.mockito.inline.extended.StaticMockitoSession import com.android.internal.jank.InteractionJankMonitor import com.android.window.flags.Flags import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE +import com.android.window.flags.Flags.FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS import com.android.window.flags.Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP import com.android.window.flags.Flags.FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT import com.android.window.flags.Flags.FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY @@ -1703,13 +1704,14 @@ class DesktopTasksControllerTest : ShellTestCase() { val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY) controller.moveToNextDisplay(task.taskId) - with(getLatestWct(type = TRANSIT_CHANGE)) { - assertThat(hierarchyOps).hasSize(1) - assertThat(hierarchyOps[0].container).isEqualTo(task.token.asBinder()) - assertThat(hierarchyOps[0].isReparent).isTrue() - assertThat(hierarchyOps[0].newParent).isEqualTo(secondDisplayArea.token.asBinder()) - assertThat(hierarchyOps[0].toTop).isTrue() - } + + val taskChange = + getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find { + it.container == task.token.asBinder() && it.isReparent + } + assertNotNull(taskChange) + assertThat(taskChange.newParent).isEqualTo(secondDisplayArea.token.asBinder()) + assertThat(taskChange.toTop).isTrue() } @Test @@ -1725,13 +1727,13 @@ class DesktopTasksControllerTest : ShellTestCase() { val task = setUpFreeformTask(displayId = SECOND_DISPLAY) controller.moveToNextDisplay(task.taskId) - with(getLatestWct(type = TRANSIT_CHANGE)) { - assertThat(hierarchyOps).hasSize(1) - assertThat(hierarchyOps[0].container).isEqualTo(task.token.asBinder()) - assertThat(hierarchyOps[0].isReparent).isTrue() - assertThat(hierarchyOps[0].newParent).isEqualTo(defaultDisplayArea.token.asBinder()) - assertThat(hierarchyOps[0].toTop).isTrue() - } + val taskChange = + getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find { + it.container == task.token.asBinder() && it.isReparent + } + assertNotNull(taskChange) + assertThat(taskChange.newParent).isEqualTo(defaultDisplayArea.token.asBinder()) + assertThat(taskChange.toTop).isTrue() } @Test @@ -1908,6 +1910,32 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test + @EnableFlags( + FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS, + FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT, + ) + fun moveToNextDisplay_destinationGainGlobalFocus() { + // Set up two display ids + whenever(rootTaskDisplayAreaOrganizer.displayIds) + .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY)) + // Create a mock for the target display area: second display + val secondDisplayArea = DisplayAreaInfo(MockToken().token(), SECOND_DISPLAY, 0) + whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(SECOND_DISPLAY)) + .thenReturn(secondDisplayArea) + + val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY) + controller.moveToNextDisplay(task.taskId) + + val taskChange = + getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find { + it.container == task.token.asBinder() && it.type == HIERARCHY_OP_TYPE_REORDER + } + assertNotNull(taskChange) + assertThat(taskChange.toTop).isTrue() + assertThat(taskChange.includingParents()).isTrue() + } + + @Test fun getTaskWindowingMode() { val fullscreenTask = setUpFullscreenTask() val freeformTask = setUpFreeformTask() diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt index e4eff9f1d592..2216d5452ce5 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt @@ -25,14 +25,14 @@ import com.android.internal.jank.InteractionJankMonitor import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.ShellTestCase import com.android.wm.shell.TestRunningTaskInfoBuilder +import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP +import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP +import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.Companion.DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT import com.android.wm.shell.splitscreen.SplitScreenController import com.android.wm.shell.transition.Transitions -import com.android.wm.shell.transition.Transitions.TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP -import com.android.wm.shell.transition.Transitions.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP -import com.android.wm.shell.transition.Transitions.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP import com.android.wm.shell.windowdecor.MoveToDesktopAnimator import java.util.function.Supplier import junit.framework.Assert.assertEquals diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java index 8dfdfb4dcbcf..8bdefa7cf866 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java @@ -25,7 +25,7 @@ import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; -import static com.android.wm.shell.transition.Transitions.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP; +import static com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.mock; diff --git a/nfc/tests/src/android/nfc/NfcRoutingTableEntryTest.java b/nfc/tests/src/android/nfc/NfcRoutingTableEntryTest.java new file mode 100644 index 000000000000..a90a716b6081 --- /dev/null +++ b/nfc/tests/src/android/nfc/NfcRoutingTableEntryTest.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.nfc; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public final class NfcRoutingTableEntryTest { + + @Test + public void testAidEntry_GetAid() { + String expectedAid = "A00000061A02"; + RoutingTableAidEntry entry = new RoutingTableAidEntry(1, expectedAid, 0); + + assertEquals(expectedAid, entry.getAid()); + } + + @Test + public void testProtocolEntry_GetProtocol() { + RoutingTableProtocolEntry entry = + new RoutingTableProtocolEntry(1, RoutingTableProtocolEntry.PROTOCOL_T1T, 0); + + assertEquals(RoutingTableProtocolEntry.PROTOCOL_T1T, entry.getProtocol()); + } + + @Test + public void testSystemCodeEntry_GetSystemCode() { + byte[] expectedSystemCode = {0x01, 0x02, 0x03}; + RoutingTableSystemCodeEntry entry = + new RoutingTableSystemCodeEntry(1, expectedSystemCode, 0); + + assertArrayEquals(expectedSystemCode, entry.getSystemCode()); + } + + @Test + public void testTechnologyEntry_GetTechnology_A() { + RoutingTableTechnologyEntry entry = + new RoutingTableTechnologyEntry(1, RoutingTableTechnologyEntry.TECHNOLOGY_A, 0); + + assertEquals(RoutingTableTechnologyEntry.TECHNOLOGY_A, entry.getTechnology()); + } +} diff --git a/nfc/tests/src/android/nfc/OemLogItemsTest.java b/nfc/tests/src/android/nfc/OemLogItemsTest.java new file mode 100644 index 000000000000..21ef80485cc4 --- /dev/null +++ b/nfc/tests/src/android/nfc/OemLogItemsTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.nfc; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.time.Instant; + +@RunWith(JUnit4.class) +public final class OemLogItemsTest { + + @Test + public void testGetAction() { + OemLogItems item = new OemLogItems.Builder(OemLogItems.LOG_ACTION_RF_FIELD_STATE_CHANGED) + .build(); + assertEquals(OemLogItems.LOG_ACTION_RF_FIELD_STATE_CHANGED, item.getAction()); + } + + @Test + public void testGetEvent() { + OemLogItems item = new OemLogItems.Builder(OemLogItems.LOG_ACTION_NFC_TOGGLE) + .setCallingEvent(OemLogItems.EVENT_ENABLE) + .build(); + assertEquals(OemLogItems.EVENT_ENABLE, item.getEvent()); + } + + @Test + public void testGetCallingPid() { + OemLogItems item = new OemLogItems.Builder(OemLogItems.LOG_ACTION_NFC_TOGGLE) + .setCallingPid(1234) + .build(); + assertEquals(1234, item.getCallingPid()); + } + + @Test + public void testGetCommandApdu() { + byte[] commandApdu = {0x01, 0x02, 0x03}; + OemLogItems item = new OemLogItems.Builder(OemLogItems.LOG_ACTION_HCE_DATA) + .setApduCommand(commandApdu) + .build(); + assertArrayEquals(commandApdu, item.getCommandApdu()); + } + + @Test + public void testGetResponseApdu() { + byte[] responseApdu = {0x04, 0x05, 0x06}; + OemLogItems item = new OemLogItems.Builder(OemLogItems.LOG_ACTION_HCE_DATA) + .setApduResponse(responseApdu) + .build(); + assertArrayEquals(responseApdu, item.getResponseApdu()); + } + + @Test + public void testGetRfFieldEventTimeMillis() { + Instant expectedTime = Instant.ofEpochSecond(1688768000, 123456789); + OemLogItems item = new OemLogItems.Builder(OemLogItems.LOG_ACTION_RF_FIELD_STATE_CHANGED) + .setRfFieldOnTime(expectedTime) + .build(); + assertEquals(expectedTime, item.getRfFieldEventTimeMillis()); + } + + @Test + public void testGetTag() { + Tag mockTag = mock(Tag.class); + OemLogItems item = new OemLogItems.Builder(OemLogItems.LOG_ACTION_TAG_DETECTED) + .setTag(mockTag) + .build(); + assertEquals(mockTag, item.getTag()); + } +} diff --git a/nfc/tests/src/android/nfc/cardemulation/CardemulationTest.java b/nfc/tests/src/android/nfc/cardemulation/CardemulationTest.java index 6be95adbeba0..a21583542a66 100644 --- a/nfc/tests/src/android/nfc/cardemulation/CardemulationTest.java +++ b/nfc/tests/src/android/nfc/cardemulation/CardemulationTest.java @@ -18,17 +18,25 @@ package android.nfc.cardemulation; 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.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.role.RoleManager; import android.content.ComponentName; +import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager; +import android.nfc.Constants; import android.nfc.INfcCardEmulation; import android.nfc.NfcAdapter; import android.os.RemoteException; import android.os.UserHandle; +import android.provider.Settings; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -61,6 +69,7 @@ public class CardemulationTest { public void setUp() { mMockitoSession = ExtendedMockito.mockitoSession() .mockStatic(NfcAdapter.class) + .mockStatic(Settings.Secure.class) .strictness(Strictness.LENIENT) .startMocking(); MockitoAnnotations.initMocks(this); @@ -110,4 +119,68 @@ public class CardemulationTest { verify(mINfcCardEmulation).isDefaultServiceForAid(1, componentName, "payment"); } + + @Test + public void testCategoryAllowsForegroundPreference() throws Settings.SettingNotFoundException { + when(mContext.createContextAsUser(any(), anyInt())).thenReturn(mContext); + RoleManager roleManager = mock(RoleManager.class); + when(roleManager.isRoleAvailable(RoleManager.ROLE_WALLET)).thenReturn(false); + when(mContext.getSystemService(RoleManager.class)).thenReturn(roleManager); + ContentResolver contentResolver = mock(ContentResolver.class); + when(mContext.getContentResolver()).thenReturn(contentResolver); + when(Settings.Secure.getInt(contentResolver, Constants + .SETTINGS_SECURE_NFC_PAYMENT_FOREGROUND)).thenReturn(1); + boolean result = mCardEmulation.categoryAllowsForegroundPreference("payment"); + assertThat(result).isTrue(); + } + + @Test + public void testGetSelectionModeForCategory() throws RemoteException { + when(mINfcCardEmulation.isDefaultPaymentRegistered()).thenReturn(true); + int result = mCardEmulation.getSelectionModeForCategory("payment"); + assertThat(result).isEqualTo(0); + } + + @Test + public void testSetShouldDefaultToObserveModeForService() throws RemoteException { + UserHandle userHandle = mock(UserHandle.class); + when(userHandle.getIdentifier()).thenReturn(1); + when(mContext.getUser()).thenReturn(userHandle); + ComponentName componentName = mock(ComponentName.class); + when(mINfcCardEmulation.setShouldDefaultToObserveModeForService(1, componentName, true)) + .thenReturn(true); + boolean result = mCardEmulation + .setShouldDefaultToObserveModeForService(componentName, true); + assertThat(result).isTrue(); + verify(mINfcCardEmulation).setShouldDefaultToObserveModeForService(1, componentName, true); + } + + @Test + public void testRegisterPollingLoopFilterForService()throws RemoteException { + UserHandle userHandle = mock(UserHandle.class); + when(userHandle.getIdentifier()).thenReturn(1); + when(mContext.getUser()).thenReturn(userHandle); + ComponentName componentName = mock(ComponentName.class); + when(mINfcCardEmulation.registerPollingLoopFilterForService(anyInt(), + any(), anyString(), anyBoolean())).thenReturn(true); + boolean result = mCardEmulation.registerPollingLoopFilterForService(componentName, + "A0000000041010", true); + assertThat(result).isTrue(); + verify(mINfcCardEmulation) + .registerPollingLoopFilterForService(anyInt(), any(), anyString(), anyBoolean()); + } + + @Test + public void testRemovePollingLoopFilterForService()throws RemoteException { + UserHandle userHandle = mock(UserHandle.class); + when(userHandle.getIdentifier()).thenReturn(1); + when(mContext.getUser()).thenReturn(userHandle); + ComponentName componentName = mock(ComponentName.class); + when(mINfcCardEmulation.removePollingLoopFilterForService(anyInt(), any(), anyString())) + .thenReturn(true); + boolean result = mCardEmulation + .removePollingLoopFilterForService(componentName, "A0000000041010"); + assertThat(result).isTrue(); + verify(mINfcCardEmulation).removePollingLoopFilterForService(anyInt(), any(), anyString()); + } } diff --git a/nfc/tests/src/android/nfc/tech/NfcVTest.java b/nfc/tests/src/android/nfc/tech/NfcVTest.java new file mode 100644 index 000000000000..6a99921b9287 --- /dev/null +++ b/nfc/tests/src/android/nfc/tech/NfcVTest.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2010 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.nfc.tech; + +import static android.nfc.tech.NfcV.EXTRA_DSFID; +import static android.nfc.tech.NfcV.EXTRA_RESP_FLAGS; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.nfc.INfcTag; +import android.nfc.Tag; +import android.nfc.TransceiveResult; +import android.os.Bundle; +import android.os.RemoteException; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.IOException; + +public class NfcVTest { + private final byte mSampleRespFlags = (byte) 1; + private final byte mSampleDsfId = (byte) 2; + @Mock + private Tag mMockTag; + @Mock + private INfcTag mMockTagService; + @Mock + private Bundle mMockBundle; + private NfcV mNfcV; + + @Before + public void setUp() throws RemoteException { + MockitoAnnotations.initMocks(this); + when(mMockBundle.getByte(EXTRA_RESP_FLAGS)).thenReturn(mSampleRespFlags); + when(mMockBundle.getByte(EXTRA_DSFID)).thenReturn(mSampleDsfId); + when(mMockTag.getTechExtras(TagTechnology.NFC_V)).thenReturn(mMockBundle); + + mNfcV = new NfcV(mMockTag); + } + + @Test + public void testGetResponseFlag() { + assertEquals(mSampleRespFlags, mNfcV.getResponseFlags()); + } + + @Test + public void testGetDsfId() { + assertEquals(mSampleDsfId, mNfcV.getDsfId()); + } + + @Test + public void testGetNfcVInstance() { + Tag tag = mock(Tag.class); + when(tag.hasTech(TagTechnology.NFC_V)).thenReturn(true); + when(tag.getTechExtras(TagTechnology.NFC_V)).thenReturn(mMockBundle); + + assertNotNull(NfcV.get(tag)); + verify(tag).getTechExtras(TagTechnology.NFC_V); + verify(tag).hasTech(TagTechnology.NFC_V); + } + + @Test + public void testGetNfcVNullInstance() { + Tag tag = mock(Tag.class); + when(tag.hasTech(TagTechnology.NFC_V)).thenReturn(false); + + assertNull(NfcV.get(tag)); + verify(tag, never()).getTechExtras(TagTechnology.NFC_V); + verify(tag).hasTech(TagTechnology.NFC_V); + } + + @Test + public void testTransceive() throws IOException, RemoteException { + byte[] sampleData = new byte[] {1, 2, 3, 4, 5}; + TransceiveResult mockTransceiveResult = mock(TransceiveResult.class); + when(mMockTag.getConnectedTechnology()).thenReturn(TagTechnology.NFC_V); + when(mMockTag.getTagService()).thenReturn(mMockTagService); + when(mMockTag.getServiceHandle()).thenReturn(1); + when(mMockTagService.transceive(1, sampleData, true)) + .thenReturn(mockTransceiveResult); + when(mockTransceiveResult.getResponseOrThrow()).thenReturn(sampleData); + + mNfcV.transceive(sampleData); + verify(mMockTag).getTagService(); + verify(mMockTag).getServiceHandle(); + } + + @Test + public void testGetMaxTransceiveLength() throws RemoteException { + when(mMockTag.getTagService()).thenReturn(mMockTagService); + when(mMockTagService.getMaxTransceiveLength(TagTechnology.NFC_V)).thenReturn(1); + + mNfcV.getMaxTransceiveLength(); + verify(mMockTag).getTagService(); + } +} diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/Permissions.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/Permissions.kt new file mode 100644 index 000000000000..871642054aef --- /dev/null +++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/Permissions.kt @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.datastore + +import android.content.Context +import android.content.pm.PackageManager.PERMISSION_GRANTED + +/** + * Class to manage permissions, which supports a combination of AND / OR. + * + * Samples: + * - `Permissions.EMPTY`: no permission is required + * - `Permissions.allOf(p1, p2) or p3 or Permissions.allOf(p4, p5)` + * - `Permissions.anyOf(p1, p2) and p3 and Permissions.anyOf(p4, p5)` + * - `Permissions.allOf(p1, p2) or (Permissions.allOf(p3, p4) and p5)`: ALWAYS add `()` explicitly + * when and/or operators are used at the same time. + */ +sealed class Permissions(vararg permissions: Any) { + internal val permissions = mutableSetOf(*permissions) + + val size: Int + get() = permissions.size + + override fun hashCode() = permissions.hashCode() + + override fun equals(other: Any?) = + other is Permissions && + permissions == other.permissions && + (permissions.size == 1 || javaClass == other.javaClass) + + abstract fun check(context: Context, pid: Int, uid: Int): Boolean + + internal fun addForAnd(permission: Any): Permissions = + when { + // ensure empty permissions will never been modified + permissions.isEmpty() -> (permission as? Permissions) ?: AllOfPermissions(permission) + permission is Permissions && permission.permissions.isEmpty() -> this + this is AllOfPermissions -> apply { and(permission) } + permission is AllOfPermissions -> permission.also { it.and(this) } + // anyOf(p1) and p2 => allOf(p1, p2) + permissions.size == 1 && this is AnyOfPermissions && permission is String -> + AllOfPermissions(permissions.first(), permission) + // anyOf(p1) and anyOf(p2) => allOf(p1, p2) + permissions.size == 1 && + permission is AnyOfPermissions && + permission.permissions.size == 1 -> + AllOfPermissions(permissions.first(), permission.permissions.first()) + else -> AllOfPermissions(this, permission) + } + + internal fun addForOr(permission: Any): Permissions = + when { + // ensure empty permissions will never been modified + permissions.isEmpty() -> (permission as? Permissions) ?: AnyOfPermissions(permission) + permission is Permissions && permission.permissions.isEmpty() -> this + this is AnyOfPermissions -> apply { or(permission) } + permission is AnyOfPermissions -> permission.also { it.or(this) } + // allOf(p1) or p2 => anyOf(p1, p2) + permissions.size == 1 && this is AllOfPermissions && permission is String -> + AnyOfPermissions(permissions.first(), permission) + // allOf(p1) or allOf(p2) => anyOf(p1, p2) + permissions.size == 1 && + permission is AllOfPermissions && + permission.permissions.size == 1 -> + AnyOfPermissions(permissions.first(), permission.permissions.first()) + else -> AnyOfPermissions(this, permission) + } + + protected fun Any.check(context: Context, pid: Int, uid: Int) = + when (this) { + is String -> context.checkPermission(this, pid, uid) == PERMISSION_GRANTED + else -> (this as Permissions).check(context, pid, uid) + } + + fun forEach(action: (Any) -> Unit) { + for (permission in permissions) action(permission) + } + + companion object { + /** Returns [Permissions] that requires all of the permissions. */ + fun allOf(vararg permissions: String): Permissions = + if (permissions.isEmpty()) EMPTY else AllOfPermissions(*permissions) + + /** Returns [Permissions] that requires any of the permissions. */ + fun anyOf(vararg permissions: String): Permissions = + if (permissions.isEmpty()) EMPTY else AnyOfPermissions(*permissions) + + /** No permission required. */ + val EMPTY: Permissions = AllOfPermissions() + } +} + +class AllOfPermissions internal constructor(vararg permissions: Any) : Permissions(*permissions) { + + override fun toString() = permissions.joinToString(prefix = "allOf(", postfix = ")") + + override fun check(context: Context, pid: Int, uid: Int): Boolean { + // use for-loop explicitly instead of "all" extension for empty permissions + for (permission in permissions) { + if (!permission.check(context, pid, uid)) return false + } + return true + } + + internal fun and(permission: Any) { + when { + // in-place merge to reduce the hierarchy + permission is AllOfPermissions -> permissions.addAll(permission.permissions) + // allOf(...) and anyOf(p) => allOf(..., p) + permission is AnyOfPermissions && permission.permissions.size == 1 -> + permissions.add(permission.permissions.first()) + + else -> permissions.add(permission) + } + } +} + +class AnyOfPermissions internal constructor(vararg permissions: Any) : Permissions(*permissions) { + + override fun toString() = permissions.joinToString(prefix = "anyOf(", postfix = ")") + + override fun check(context: Context, pid: Int, uid: Int): Boolean { + // use for-loop explicitly instead of "any" extension for empty permissions + for (permission in permissions) { + if (permission.check(context, pid, uid)) return true + } + return permissions.isEmpty() + } + + internal fun or(permission: Any) { + when { + // in-place merge to reduce the hierarchy + permission is AnyOfPermissions -> permissions.addAll(permission.permissions) + // anyOf(...) or allOf(p) => anyOf(..., p) + permission is AllOfPermissions && permission.permissions.size == 1 -> + permissions.add(permission.permissions.first()) + else -> permissions.add(permission) + } + } +} + +infix fun Permissions.and(permission: String): Permissions = addForAnd(permission) + +infix fun Permissions.and(permissions: Permissions): Permissions = addForAnd(permissions) + +infix fun Permissions.or(permission: String): Permissions = addForOr(permission) + +infix fun Permissions.or(permissions: Permissions): Permissions = addForOr(permissions) diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsGlobalStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsGlobalStore.kt index 8335ee43df26..614bcb221780 100644 --- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsGlobalStore.kt +++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsGlobalStore.kt @@ -85,9 +85,9 @@ class SettingsGlobalStore private constructor(contentResolver: ContentResolver) } /** Returns the required permissions to read [Global] settings. */ - fun getReadPermissions() = arrayOf<String>() + fun getReadPermissions() = Permissions.EMPTY /** Returns the required permissions to write [Global] settings. */ - fun getWritePermissions() = arrayOf(Manifest.permission.WRITE_SECURE_SETTINGS) + fun getWritePermissions() = Permissions.allOf(Manifest.permission.WRITE_SECURE_SETTINGS) } } diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSecureStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSecureStore.kt index c117b926d1eb..2621de1fbcb8 100644 --- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSecureStore.kt +++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSecureStore.kt @@ -85,9 +85,9 @@ class SettingsSecureStore private constructor(contentResolver: ContentResolver) } /** Returns the required permissions to read [Secure] settings. */ - fun getReadPermissions() = arrayOf<String>() + fun getReadPermissions() = Permissions.EMPTY /** Returns the required permissions to write [Secure] settings. */ - fun getWritePermissions() = arrayOf(Manifest.permission.WRITE_SECURE_SETTINGS) + fun getWritePermissions() = Permissions.allOf(Manifest.permission.WRITE_SECURE_SETTINGS) } } diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSystemStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSystemStore.kt index f5a2f940bc03..740ac39ec2e9 100644 --- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSystemStore.kt +++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSystemStore.kt @@ -85,9 +85,9 @@ class SettingsSystemStore private constructor(contentResolver: ContentResolver) } /** Returns the required permissions to read [System] settings. */ - fun getReadPermissions() = arrayOf<String>() + fun getReadPermissions() = Permissions.EMPTY /** Returns the required permissions to write [System] settings. */ - fun getWritePermissions() = arrayOf(Manifest.permission.WRITE_SETTINGS) + fun getWritePermissions() = Permissions.allOf(Manifest.permission.WRITE_SETTINGS) } } diff --git a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/PermissionsTest.kt b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/PermissionsTest.kt new file mode 100644 index 000000000000..5641f0d82e57 --- /dev/null +++ b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/PermissionsTest.kt @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.datastore + +import android.content.Context +import android.content.ContextWrapper +import android.content.pm.PackageManager.PERMISSION_DENIED +import android.content.pm.PackageManager.PERMISSION_GRANTED +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settingslib.datastore.Permissions.Companion.EMPTY +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class PermissionsTest { + private val context: Context = ApplicationProvider.getApplicationContext() + + @Test + fun empty() { + assertThat(Permissions.allOf()).isSameInstanceAs(EMPTY) + assertThat(Permissions.anyOf()).isSameInstanceAs(EMPTY) + assertThat(EMPTY.check(context, 0, 0)).isTrue() + assertThat((EMPTY and "a").permissions).containsExactly("a") + assertThat((EMPTY or "a").permissions).containsExactly("a") + } + + @Test + fun allOf_op_empty() { + val allOf = Permissions.allOf("a") + assertThat(allOf and EMPTY).isSameInstanceAs(allOf) + assertThat(EMPTY and allOf).isSameInstanceAs(allOf) + assertThat(EMPTY or allOf).isSameInstanceAs(allOf) + assertThat(allOf or EMPTY).isSameInstanceAs(allOf) + } + + @Test + fun anyOf_op_empty() { + val anyOf = Permissions.anyOf("a") + assertThat(anyOf and EMPTY).isSameInstanceAs(anyOf) + assertThat(EMPTY and anyOf).isSameInstanceAs(anyOf) + assertThat(EMPTY or anyOf).isSameInstanceAs(anyOf) + assertThat(anyOf or EMPTY).isSameInstanceAs(anyOf) + } + + @Test + fun allOf1_and_allOf1() { + val allOf = Permissions.allOf("a") + assertThat(allOf and Permissions.allOf("b")).isSameInstanceAs(allOf) + assertThat(allOf.permissions).containsExactly("a", "b") + } + + @Test + fun allOf1_or_allOf1() { + val merged = Permissions.allOf("a") or Permissions.allOf("b") + assertThat(merged.permissions).containsExactly("a", "b") + assertThat(merged).isInstanceOf(AnyOfPermissions::class.java) + } + + @Test + fun allOf1_and_anyOf1() { + val allOf = Permissions.allOf("a") + val anyOf = Permissions.anyOf("b") + assertThat(allOf and anyOf).isSameInstanceAs(allOf) + assertThat(allOf.permissions).containsExactly("a", "b") + } + + @Test + fun allOf1_or_anyOf1() { + val allOf = Permissions.allOf("a") + val anyOf = Permissions.anyOf("b") + assertThat(allOf or anyOf).isSameInstanceAs(anyOf) + assertThat(anyOf.permissions).containsExactly("a", "b") + } + + @Test + fun anyOf1_and_allOf1() { + val anyOf = Permissions.anyOf("a") + val allOf = Permissions.allOf("b") + assertThat(anyOf and allOf).isSameInstanceAs(allOf) + assertThat(allOf.permissions).containsExactly("a", "b") + } + + @Test + fun anyOf1_or_allOf1() { + val anyOf = Permissions.anyOf("a") + val allOf = Permissions.allOf("b") + assertThat(anyOf or allOf).isSameInstanceAs(anyOf) + assertThat(anyOf.permissions).containsExactly("a", "b") + } + + @Test + fun anyOf1_and_anyOf1() { + val merged = Permissions.anyOf("a") and Permissions.anyOf("b") + assertThat(merged.permissions).containsExactly("a", "b") + assertThat(merged).isInstanceOf(AllOfPermissions::class.java) + } + + @Test + fun anyOf1_or_anyOf1() { + val anyOf = Permissions.anyOf("a") + assertThat(anyOf or Permissions.anyOf("b")).isSameInstanceAs(anyOf) + assertThat(anyOf.permissions).containsExactly("a", "b") + } + + @Test + fun allOf1_and_anyOf2() { + val allOf = Permissions.allOf("a") + val anyOf = Permissions.anyOf("a", "b") + assertThat(allOf and anyOf).isSameInstanceAs(allOf) + assertThat(allOf.permissions).containsExactly("a", anyOf) + } + + @Test + fun allOf1_or_anyOf2() { + val allOf = Permissions.allOf("a") + val anyOf = Permissions.anyOf("a", "b") + assertThat(allOf and anyOf).isSameInstanceAs(allOf) + assertThat(allOf.permissions).containsExactly("a", anyOf) + } + + @Test + fun allOf2_and_anyOf1() { + val allOf = Permissions.allOf("a", "b") + val anyOf = Permissions.anyOf("c") + assertThat(allOf and anyOf).isSameInstanceAs(allOf) + assertThat(allOf.permissions).containsExactly("a", "b", "c") + } + + @Test + fun allOf2_or_anyOf1() { + val allOf = Permissions.allOf("a", "b") + val anyOf = Permissions.anyOf("b") + assertThat(allOf or anyOf).isSameInstanceAs(anyOf) + assertThat(anyOf.permissions).containsExactly("b", allOf) + } + + @Test + fun anyOf1_and_allOf2() { + val anyOf = Permissions.anyOf("c") + val allOf = Permissions.allOf("a", "b") + assertThat(anyOf and allOf).isSameInstanceAs(allOf) + assertThat(allOf.permissions).containsExactly("a", "b", "c") + } + + @Test + fun anyOf1_or_allOf2() { + val anyOf = Permissions.anyOf("a") + val allOf = Permissions.allOf("a", "b") + assertThat(anyOf or allOf).isSameInstanceAs(anyOf) + assertThat(anyOf.permissions).containsExactly("a", allOf) + } + + @Test + fun anyOf2_and_allOf1() { + val anyOf = Permissions.anyOf("a", "b") + val allOf = Permissions.allOf("a") + assertThat(anyOf and allOf).isSameInstanceAs(allOf) + assertThat(allOf.permissions).containsExactly("a", anyOf) + } + + @Test + fun anyOf2_or_allOf1() { + val anyOf = Permissions.anyOf("a", "b") + val allOf = Permissions.allOf("c") + assertThat(anyOf or allOf).isSameInstanceAs(anyOf) + assertThat(anyOf.permissions).containsExactly("a", "b", "c") + } + + @Test + fun allOf2_and_allOf2() { + val allOf = Permissions.allOf("a", "b") + assertThat(allOf and Permissions.allOf("a", "c")).isSameInstanceAs(allOf) + assertThat(allOf.permissions).containsExactly("a", "b", "c") + } + + @Test + fun allOf2_or_allOf2() { + val allOf1 = Permissions.allOf("a", "b") + val allOf2 = Permissions.allOf("a", "c") + assertThat((allOf1 or allOf2).permissions).containsExactly(allOf1, allOf2) + } + + @Test + fun allOf2_and_anyOf2() { + val allOf = Permissions.allOf("a", "b") + val anyOf = Permissions.anyOf("a", "c") + assertThat(allOf and anyOf).isSameInstanceAs(allOf) + assertThat(allOf.permissions).containsExactly("a", "b", anyOf) + } + + @Test + fun allOf2_or_anyOf2() { + val allOf = Permissions.allOf("a", "b") + val anyOf = Permissions.anyOf("a", "c") + assertThat(allOf or anyOf).isSameInstanceAs(anyOf) + assertThat(anyOf.permissions).containsExactly("a", "c", allOf) + } + + @Test + fun anyOf2_and_allOf2() { + val anyOf = Permissions.anyOf("a", "b") + val allOf = Permissions.allOf("a", "c") + assertThat(anyOf and allOf).isSameInstanceAs(allOf) + assertThat(allOf.permissions).containsExactly("a", "c", anyOf) + } + + @Test + fun anyOf2_or_allOf2() { + val anyOf = Permissions.anyOf("a", "b") + val allOf = Permissions.allOf("a", "c") + assertThat(anyOf or allOf).isSameInstanceAs(anyOf) + assertThat(anyOf.permissions).containsExactly("a", "b", allOf) + } + + @Test + fun anyOf2_and_anyOf2() { + val anyOf1 = Permissions.anyOf("a", "b") + val anyOf2 = Permissions.anyOf("a", "c") + assertThat((anyOf1 and anyOf2).permissions).containsExactly(anyOf1, anyOf2) + } + + @Test + fun anyOf2_or_anyOf2() { + val anyOf = Permissions.anyOf("a", "b") + assertThat(anyOf or Permissions.anyOf("a", "c")).isSameInstanceAs(anyOf) + assertThat(anyOf.permissions).containsExactly("a", "b", "c") + } + + @Test + fun check_allOf() { + val permissions = Permissions.allOf("a", "b") + assertThat(permissions.check(PermissionsContext(setOf()), 0, 0)).isFalse() + assertThat(permissions.check(PermissionsContext(setOf("a")), 0, 0)).isFalse() + assertThat(permissions.check(PermissionsContext(setOf("b")), 0, 0)).isFalse() + assertThat(permissions.check(PermissionsContext(setOf("a", "b")), 0, 0)).isTrue() + } + + @Test + fun check_allOf_mixed() { + val permissions = Permissions.allOf("a", "b") or "c" + assertThat(permissions.permissions).hasSize(2) + assertThat(permissions.check(PermissionsContext(setOf()), 0, 0)).isFalse() + assertThat(permissions.check(PermissionsContext(setOf("a")), 0, 0)).isFalse() + assertThat(permissions.check(PermissionsContext(setOf("b")), 0, 0)).isFalse() + assertThat(permissions.check(PermissionsContext(setOf("a", "b")), 0, 0)).isTrue() + assertThat(permissions.check(PermissionsContext(setOf("c")), 0, 0)).isTrue() + assertThat(permissions.check(PermissionsContext(setOf("a", "c")), 0, 0)).isTrue() + assertThat(permissions.check(PermissionsContext(setOf("b", "c")), 0, 0)).isTrue() + assertThat(permissions.check(PermissionsContext(setOf("a", "b", "c")), 0, 0)).isTrue() + } + + @Test + fun check_anyOf() { + val permissions = Permissions.anyOf("a", "b") + assertThat(permissions.check(PermissionsContext(setOf()), 0, 0)).isFalse() + assertThat(permissions.check(PermissionsContext(setOf("a")), 0, 0)).isTrue() + assertThat(permissions.check(PermissionsContext(setOf("b")), 0, 0)).isTrue() + assertThat(permissions.check(PermissionsContext(setOf("a", "b")), 0, 0)).isTrue() + } + + @Test + fun check_anyOf_mixed() { + val permissions = Permissions.anyOf("a", "b") and "c" + assertThat(permissions.permissions).hasSize(2) + assertThat(permissions.check(PermissionsContext(setOf()), 0, 0)).isFalse() + assertThat(permissions.check(PermissionsContext(setOf("a")), 0, 0)).isFalse() + assertThat(permissions.check(PermissionsContext(setOf("b")), 0, 0)).isFalse() + assertThat(permissions.check(PermissionsContext(setOf("a", "b")), 0, 0)).isFalse() + assertThat(permissions.check(PermissionsContext(setOf("c")), 0, 0)).isFalse() + assertThat(permissions.check(PermissionsContext(setOf("a", "c")), 0, 0)).isTrue() + assertThat(permissions.check(PermissionsContext(setOf("b", "c")), 0, 0)).isTrue() + assertThat(permissions.check(PermissionsContext(setOf("a", "b", "c")), 0, 0)).isTrue() + } + + @Test + fun equals() { + assertThat(Permissions.allOf("a")).isEqualTo(Permissions.allOf("a")) + assertThat(Permissions.allOf("a")).isEqualTo(Permissions.anyOf("a")) + assertThat(Permissions.anyOf("a")).isEqualTo(Permissions.allOf("a")) + assertThat(Permissions.anyOf("a")).isEqualTo(Permissions.anyOf("a")) + + assertThat(Permissions.anyOf("a") and "b").isEqualTo(Permissions.allOf("a", "b")) + assertThat(Permissions.allOf("a") or "b").isEqualTo(Permissions.anyOf("a", "b")) + assertThat(Permissions.allOf("a") and "a").isEqualTo(Permissions.allOf("a")) + assertThat(Permissions.anyOf("a") or "a").isEqualTo(Permissions.anyOf("a")) + + assertThat(Permissions.allOf("a", "c") and Permissions.allOf("c", "b")) + .isEqualTo(Permissions.allOf("a", "b", "c")) + assertThat(Permissions.anyOf("a", "c") or Permissions.anyOf("c", "b")) + .isEqualTo(Permissions.anyOf("a", "b", "c")) + + assertThat(Permissions.allOf("a", "c") and Permissions.allOf("c", "b")) + .isEqualTo(Permissions.allOf("b", "c") and Permissions.allOf("c", "a")) + assertThat(Permissions.anyOf("a", "c") or Permissions.anyOf("c", "b")) + .isEqualTo(Permissions.anyOf("b", "c") or Permissions.anyOf("c", "a")) + } + + @Test + fun notEquals() { + assertThat(Permissions.allOf("a")).isNotEqualTo(Permissions.allOf("a", "b")) + assertThat(Permissions.anyOf("a")).isNotEqualTo(Permissions.anyOf("a", "b")) + assertThat(Permissions.allOf("a", "b")).isNotEqualTo(Permissions.anyOf("a", "b")) + } +} + +private class PermissionsContext(private val granted: Set<String>) : + ContextWrapper(ApplicationProvider.getApplicationContext()) { + + override fun checkPermission(permission: String, pid: Int, uid: Int) = + if (permission in granted) PERMISSION_GRANTED else PERMISSION_DENIED +} diff --git a/packages/SettingsLib/Graph/graph.proto b/packages/SettingsLib/Graph/graph.proto index 2aa619aa67f9..33a7df4c6ba8 100644 --- a/packages/SettingsLib/Graph/graph.proto +++ b/packages/SettingsLib/Graph/graph.proto @@ -82,9 +82,9 @@ message PreferenceProto { // Indicate how sensitive of the preference. optional int32 sensitivity_level = 16; // The required permissions to read preference value. - repeated string read_permissions = 17; + optional PermissionsProto read_permissions = 17; // The required permissions to write preference value. - repeated string write_permissions = 18; + optional PermissionsProto write_permissions = 18; // Target of an Intent message ActionTarget { @@ -99,6 +99,20 @@ message PreferenceProto { } } +// Proto of permissions +message PermissionsProto { + repeated PermissionProto all_of = 1; + repeated PermissionProto any_of = 2; +} + +// Proto of permission +message PermissionProto { + oneof kind { + string permission = 1; + PermissionsProto permissions = 2; + } +} + // Proto of string or string resource id. message TextProto { oneof text { diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PermissionsProtos.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PermissionsProtos.kt new file mode 100644 index 000000000000..5971b4255c44 --- /dev/null +++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PermissionsProtos.kt @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.graph + +import com.android.settingslib.datastore.AllOfPermissions +import com.android.settingslib.datastore.AnyOfPermissions +import com.android.settingslib.datastore.Permissions +import com.android.settingslib.datastore.and +import com.android.settingslib.datastore.or +import com.android.settingslib.graph.proto.PermissionProto +import com.android.settingslib.graph.proto.PermissionsProto + +inline fun permissionsProto(init: PermissionsProto.Builder.() -> Unit): PermissionsProto = + PermissionsProto.newBuilder().also(init).build() + +inline fun permissionProto(init: PermissionProto.Builder.() -> Unit): PermissionProto = + PermissionProto.newBuilder().also(init).build() + +fun Permissions.toProto(): PermissionsProto = permissionsProto { + when (this@toProto) { + is AllOfPermissions -> { + forEach { addAllOf(it.toPermissionProto()) } + } + is AnyOfPermissions -> { + forEach { addAnyOf(it.toPermissionProto()) } + } + } +} + +private fun Any.toPermissionProto() = + when { + this is Permissions -> permissionProto { permissions = toProto() } + else -> permissionProto { permission = this@toPermissionProto as String } + } + +fun PermissionsProto.getAllPermissions(): List<String> { + val permissions = mutableSetOf<String>() + fun Permissions.collect() { + forEach { + when { + it is String -> permissions.add(it) + else -> (it as Permissions).collect() + } + } + } + toPermissions().collect() + return permissions.toList() +} + +fun PermissionsProto.toPermissions(): Permissions { + var permissions = Permissions.EMPTY + for (index in 0 until allOfCount) { + val permission = getAllOf(index).toPermission() + permissions = + when (permission) { + is String -> permissions and permission + else -> permissions and (permission as Permissions) + } + } + for (index in 0 until anyOfCount) { + val permission = getAnyOf(index).toPermission() + permissions = + when (permission) { + is String -> permissions or permission + else -> permissions or (permission as Permissions) + } + } + return permissions +} + +private fun PermissionProto.toPermission(): Any = + when { + hasPermissions() -> permissions.toPermissions() + else -> permission + } diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt index 91dec03bf2af..2cf32decd5e2 100644 --- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt +++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt @@ -22,7 +22,6 @@ import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.content.pm.PackageManager -import android.content.pm.PackageManager.PERMISSION_GRANTED import android.content.res.Configuration import android.os.Build import android.os.Bundle @@ -393,10 +392,12 @@ fun PreferenceMetadata.toProto( if (persistent) { if (metadata is PersistentPreference<*>) { sensitivityLevel = metadata.sensitivityLevel - val readPermissions = metadata.getReadPermissions(context) - readPermissions.forEach { addReadPermissions(it) } - val writePermissions = metadata.getWritePermissions(context) - writePermissions.forEach { addWritePermissions(it) } + metadata.getReadPermissions(context)?.let { + if (it.size > 0) readPermissions = it.toProto() + } + metadata.getWritePermissions(context)?.let { + if (it.size > 0) writePermissions = it.toProto() + } } if ( flags.includeValue() && @@ -439,14 +440,12 @@ fun <T> PersistentPreference<T>.evalReadPermit( context: Context, callingPid: Int, callingUid: Int, -): Int { - for (permission in getReadPermissions(context)) { - if (context.checkPermission(permission, callingPid, callingUid) != PERMISSION_GRANTED) { - return ReadWritePermit.REQUIRE_APP_PERMISSION - } +): Int = + when { + getReadPermissions(context)?.check(context, callingPid, callingUid) == false -> + ReadWritePermit.REQUIRE_APP_PERMISSION + else -> getReadPermit(context, callingPid, callingUid) } - return getReadPermit(context, callingPid, callingUid) -} private fun PreferenceMetadata.getTitleTextProto(context: Context, isRoot: Boolean): TextProto? { if (isRoot && this is PreferenceScreenMetadata) { diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt index 83c430488317..bef4bb297654 100644 --- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt +++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt @@ -18,7 +18,6 @@ package com.android.settingslib.graph import android.app.Application import android.content.Context -import android.content.pm.PackageManager.PERMISSION_GRANTED import android.os.Bundle import androidx.annotation.IntDef import com.android.settingslib.graph.proto.PreferenceValueProto @@ -185,14 +184,12 @@ fun <T> PersistentPreference<T>.evalWritePermit( value: T?, callingPid: Int, callingUid: Int, -): Int { - for (permission in getWritePermissions(context)) { - if (context.checkPermission(permission, callingPid, callingUid) != PERMISSION_GRANTED) { - return ReadWritePermit.REQUIRE_APP_PERMISSION - } +): Int = + when { + getWritePermissions(context)?.check(context, callingPid, callingUid) == false -> + ReadWritePermit.REQUIRE_APP_PERMISSION + else -> getWritePermit(context, value, callingPid, callingUid) } - return getWritePermit(context, value, callingPid, callingUid) -} /** Message codec for [PreferenceSetterRequest]. */ object PreferenceSetterRequestCodec : MessageCodec<PreferenceSetterRequest> { diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt index 3dd6c47833fd..e5bf41f87999 100644 --- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt +++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt @@ -20,6 +20,7 @@ import android.content.Context import androidx.annotation.ArrayRes import androidx.annotation.IntDef import com.android.settingslib.datastore.KeyValueStore +import com.android.settingslib.datastore.Permissions /** Permit of read and write request. */ @IntDef( @@ -69,7 +70,7 @@ interface PersistentPreference<T> { PreferenceScreenRegistry.getKeyValueStore(context, this as PreferenceMetadata)!! /** Returns the required permissions to read preference value. */ - fun getReadPermissions(context: Context): Array<String> = arrayOf() + fun getReadPermissions(context: Context): Permissions? = null /** * Returns if the external application (identified by [callingPid] and [callingUid]) is @@ -88,7 +89,7 @@ interface PersistentPreference<T> { ) /** Returns the required permissions to write preference value. */ - fun getWritePermissions(context: Context): Array<String> = arrayOf() + fun getWritePermissions(context: Context): Permissions? = null /** * Returns if the external application (identified by [callingPid] and [callingUid]) is diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt index 08bedf99519d..fcaedd2b80bd 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt @@ -33,9 +33,8 @@ object SettingsDimension { val spinnerHorizontalPadding = paddingExtraLarge val spinnerVerticalPadding = paddingLarge - val actionIconWidth = 32.dp - val actionIconHeight = 40.dp - val actionIconPadding = 4.dp + val actionIconSize = 40.dp + val actionIconPadding = 8.dp val itemIconSize = 24.dp val itemIconContainerSizeSmall = 40.dp diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTypography.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTypography.kt index 965c97124329..701825dd8bbf 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTypography.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTypography.kt @@ -16,6 +16,7 @@ package com.android.settingslib.spa.framework.theme +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Typography import androidx.compose.runtime.Composable import androidx.compose.runtime.remember @@ -29,134 +30,428 @@ private class SettingsTypography(settingsFontFamily: SettingsFontFamily) { private val brand = settingsFontFamily.brand private val plain = settingsFontFamily.plain - val typography = Typography( - displayLarge = TextStyle( - fontFamily = brand, - fontWeight = FontWeight.Normal, - fontSize = 57.sp, - lineHeight = 64.sp, - letterSpacing = (-0.2).sp, - hyphens = Hyphens.Auto, - ), - displayMedium = TextStyle( - fontFamily = brand, - fontWeight = FontWeight.Normal, - fontSize = 45.sp, - lineHeight = 52.sp, - letterSpacing = 0.0.sp, - hyphens = Hyphens.Auto, - ), - displaySmall = TextStyle( - fontFamily = brand, - fontWeight = FontWeight.Normal, - fontSize = 36.sp, - lineHeight = 44.sp, - letterSpacing = 0.0.sp, - hyphens = Hyphens.Auto, - ), - headlineLarge = TextStyle( - fontFamily = brand, - fontWeight = FontWeight.Normal, - fontSize = 32.sp, - lineHeight = 40.sp, - letterSpacing = 0.0.sp, - hyphens = Hyphens.Auto, - ), - headlineMedium = TextStyle( - fontFamily = brand, - fontWeight = FontWeight.Normal, - fontSize = 28.sp, - lineHeight = 36.sp, - letterSpacing = 0.0.sp, - hyphens = Hyphens.Auto, - ), - headlineSmall = TextStyle( - fontFamily = brand, - fontWeight = FontWeight.Normal, - fontSize = 24.sp, - lineHeight = 32.sp, - letterSpacing = 0.0.sp, - hyphens = Hyphens.Auto, - ), - titleLarge = TextStyle( - fontFamily = brand, - fontWeight = FontWeight.Normal, - fontSize = 22.sp, - lineHeight = 28.sp, - letterSpacing = 0.02.em, - hyphens = Hyphens.Auto, - ), - titleMedium = TextStyle( - fontFamily = brand, - fontWeight = FontWeight.Normal, - fontSize = 20.sp, - lineHeight = 24.sp, - letterSpacing = 0.02.em, - hyphens = Hyphens.Auto, - ), - titleSmall = TextStyle( - fontFamily = brand, - fontWeight = FontWeight.Normal, - fontSize = 18.sp, - lineHeight = 20.sp, - letterSpacing = 0.02.em, - hyphens = Hyphens.Auto, - ), - bodyLarge = TextStyle( - fontFamily = plain, - fontWeight = FontWeight.Normal, - fontSize = 16.sp, - lineHeight = 24.sp, - letterSpacing = 0.01.em, - hyphens = Hyphens.Auto, - ), - bodyMedium = TextStyle( - fontFamily = plain, - fontWeight = FontWeight.Normal, - fontSize = 14.sp, - lineHeight = 20.sp, - letterSpacing = 0.01.em, - hyphens = Hyphens.Auto, - ), - bodySmall = TextStyle( - fontFamily = plain, - fontWeight = FontWeight.Normal, - fontSize = 12.sp, - lineHeight = 16.sp, - letterSpacing = 0.01.em, - hyphens = Hyphens.Auto, - ), - labelLarge = TextStyle( - fontFamily = plain, - fontWeight = FontWeight.Medium, - fontSize = 16.sp, - lineHeight = 24.sp, - letterSpacing = 0.01.em, - hyphens = Hyphens.Auto, - ), - labelMedium = TextStyle( - fontFamily = plain, - fontWeight = FontWeight.Medium, - fontSize = 14.sp, - lineHeight = 20.sp, - letterSpacing = 0.01.em, - hyphens = Hyphens.Auto, - ), - labelSmall = TextStyle( - fontFamily = plain, - fontWeight = FontWeight.Medium, - fontSize = 12.sp, - lineHeight = 16.sp, - letterSpacing = 0.01.em, - hyphens = Hyphens.Auto, - ), - ) + val typography = + Typography( + displayLarge = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 57.sp, + lineHeight = 64.sp, + letterSpacing = (-0.2).sp, + hyphens = Hyphens.Auto, + ), + displayMedium = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 45.sp, + lineHeight = 52.sp, + letterSpacing = 0.0.sp, + hyphens = Hyphens.Auto, + ), + displaySmall = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 36.sp, + lineHeight = 44.sp, + letterSpacing = 0.0.sp, + hyphens = Hyphens.Auto, + ), + headlineLarge = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 32.sp, + lineHeight = 40.sp, + letterSpacing = 0.0.sp, + hyphens = Hyphens.Auto, + ), + headlineMedium = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 28.sp, + lineHeight = 36.sp, + letterSpacing = 0.0.sp, + hyphens = Hyphens.Auto, + ), + headlineSmall = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 24.sp, + lineHeight = 32.sp, + letterSpacing = 0.0.sp, + hyphens = Hyphens.Auto, + ), + titleLarge = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.02.em, + hyphens = Hyphens.Auto, + ), + titleMedium = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 20.sp, + lineHeight = 24.sp, + letterSpacing = 0.02.em, + hyphens = Hyphens.Auto, + ), + titleSmall = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 18.sp, + lineHeight = 20.sp, + letterSpacing = 0.02.em, + hyphens = Hyphens.Auto, + ), + bodyLarge = + TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.01.em, + hyphens = Hyphens.Auto, + ), + bodyMedium = + TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Normal, + fontSize = 14.sp, + lineHeight = 20.sp, + letterSpacing = 0.01.em, + hyphens = Hyphens.Auto, + ), + bodySmall = + TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Normal, + fontSize = 12.sp, + lineHeight = 16.sp, + letterSpacing = 0.01.em, + hyphens = Hyphens.Auto, + ), + labelLarge = + TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Medium, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.01.em, + hyphens = Hyphens.Auto, + ), + labelMedium = + TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Medium, + fontSize = 14.sp, + lineHeight = 20.sp, + letterSpacing = 0.01.em, + hyphens = Hyphens.Auto, + ), + labelSmall = + TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Medium, + fontSize = 12.sp, + lineHeight = 16.sp, + letterSpacing = 0.01.em, + hyphens = Hyphens.Auto, + ), + ) + + @OptIn(ExperimentalMaterial3ExpressiveApi::class) + val expressiveTypography = + Typography( + displayLarge = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 57.sp, + lineHeight = 64.sp, + letterSpacing = (-0.2).sp, + hyphens = Hyphens.Auto, + ), + displayLargeEmphasized = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Medium, + fontSize = 57.sp, + lineHeight = 64.sp, + letterSpacing = (-0.2).sp, + hyphens = Hyphens.Auto, + ), + displayMedium = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 45.sp, + lineHeight = 52.sp, + letterSpacing = 0.0.sp, + hyphens = Hyphens.Auto, + ), + displayMediumEmphasized = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Medium, + fontSize = 45.sp, + lineHeight = 52.sp, + letterSpacing = 0.0.sp, + hyphens = Hyphens.Auto, + ), + displaySmall = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 36.sp, + lineHeight = 44.sp, + letterSpacing = 0.0.sp, + hyphens = Hyphens.Auto, + ), + displaySmallEmphasized = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Medium, + fontSize = 36.sp, + lineHeight = 44.sp, + letterSpacing = 0.0.sp, + hyphens = Hyphens.Auto, + ), + headlineLarge = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 32.sp, + lineHeight = 40.sp, + letterSpacing = 0.0.sp, + hyphens = Hyphens.Auto, + ), + headlineLargeEmphasized = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Medium, + fontSize = 32.sp, + lineHeight = 40.sp, + letterSpacing = 0.0.sp, + hyphens = Hyphens.Auto, + ), + headlineMedium = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 28.sp, + lineHeight = 36.sp, + letterSpacing = 0.0.sp, + hyphens = Hyphens.Auto, + ), + headlineMediumEmphasized = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Medium, + fontSize = 28.sp, + lineHeight = 36.sp, + letterSpacing = 0.0.sp, + hyphens = Hyphens.Auto, + ), + headlineSmall = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 24.sp, + lineHeight = 32.sp, + letterSpacing = 0.0.sp, + hyphens = Hyphens.Auto, + ), + headlineSmallEmphasized = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Medium, + fontSize = 24.sp, + lineHeight = 32.sp, + letterSpacing = 0.0.sp, + hyphens = Hyphens.Auto, + ), + titleLarge = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.02.em, + hyphens = Hyphens.Auto, + ), + titleLargeEmphasized = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Medium, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.02.em, + hyphens = Hyphens.Auto, + ), + titleMedium = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Medium, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.02.em, + hyphens = Hyphens.Auto, + ), + titleMediumEmphasized = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.SemiBold, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.02.em, + hyphens = Hyphens.Auto, + ), + titleSmall = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Medium, + fontSize = 14.sp, + lineHeight = 20.sp, + letterSpacing = 0.02.em, + hyphens = Hyphens.Auto, + ), + titleSmallEmphasized = + TextStyle( + fontFamily = brand, + fontWeight = FontWeight.SemiBold, + fontSize = 14.sp, + lineHeight = 20.sp, + letterSpacing = 0.02.em, + hyphens = Hyphens.Auto, + ), + bodyLarge = + TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.01.em, + hyphens = Hyphens.Auto, + ), + bodyLargeEmphasized = + TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Medium, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.01.em, + hyphens = Hyphens.Auto, + ), + bodyMedium = + TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Normal, + fontSize = 14.sp, + lineHeight = 20.sp, + letterSpacing = 0.01.em, + hyphens = Hyphens.Auto, + ), + bodyMediumEmphasized = + TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Medium, + fontSize = 14.sp, + lineHeight = 20.sp, + letterSpacing = 0.01.em, + hyphens = Hyphens.Auto, + ), + bodySmall = + TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Normal, + fontSize = 12.sp, + lineHeight = 16.sp, + letterSpacing = 0.01.em, + hyphens = Hyphens.Auto, + ), + bodySmallEmphasized = + TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Medium, + fontSize = 12.sp, + lineHeight = 16.sp, + letterSpacing = 0.01.em, + hyphens = Hyphens.Auto, + ), + labelLarge = + TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Medium, + fontSize = 14.sp, + lineHeight = 20.sp, + letterSpacing = 0.01.em, + hyphens = Hyphens.Auto, + ), + labelLargeEmphasized = + TextStyle( + fontFamily = plain, + fontWeight = FontWeight.SemiBold, + fontSize = 14.sp, + lineHeight = 20.sp, + letterSpacing = 0.01.em, + hyphens = Hyphens.Auto, + ), + labelMedium = + TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Medium, + fontSize = 12.sp, + lineHeight = 16.sp, + letterSpacing = 0.01.em, + hyphens = Hyphens.Auto, + ), + labelMediumEmphasized = + TextStyle( + fontFamily = plain, + fontWeight = FontWeight.SemiBold, + fontSize = 12.sp, + lineHeight = 16.sp, + letterSpacing = 0.01.em, + hyphens = Hyphens.Auto, + ), + labelSmall = + TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.01.em, + hyphens = Hyphens.Auto, + ), + labelSmallEmphasized = + TextStyle( + fontFamily = plain, + fontWeight = FontWeight.SemiBold, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.01.em, + hyphens = Hyphens.Auto, + ), + ) } @Composable internal fun rememberSettingsTypography(): Typography { val settingsFontFamily = rememberSettingsFontFamily() - return remember { SettingsTypography(settingsFontFamily).typography } + return remember { + if (isSpaExpressiveEnabled) SettingsTypography(settingsFontFamily).expressiveTypography + else SettingsTypography(settingsFontFamily).typography + } } /** Creates a new [TextStyle] which font weight set to medium. */ diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/button/ActionButtons.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/button/ActionButtons.kt index 203a8bd39fae..adebccb2ed26 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/button/ActionButtons.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/button/ActionButtons.kt @@ -56,7 +56,6 @@ import com.android.settingslib.spa.framework.theme.SettingsShape import com.android.settingslib.spa.framework.theme.SettingsTheme import com.android.settingslib.spa.framework.theme.divider import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled -import com.android.settingslib.spa.framework.theme.toSemiBoldWeight data class ActionButton( val text: String, @@ -130,7 +129,7 @@ private fun RowScope.ActionButton(actionButton: ActionButton) { Text( text = actionButton.text, textAlign = TextAlign.Center, - style = MaterialTheme.typography.labelLarge.toSemiBoldWeight(), + style = MaterialTheme.typography.titleSmall, ) } } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/IntroPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/IntroPreference.kt index 6d3f7bc1147d..c786dde4c6a7 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/IntroPreference.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/IntroPreference.kt @@ -36,7 +36,6 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import com.android.settingslib.spa.framework.theme.SettingsDimension -import com.android.settingslib.spa.framework.theme.toSemiBoldWeight @Composable fun IntroPreference( @@ -113,7 +112,7 @@ private fun IntroTitle(title: String) { Text( text = title, textAlign = TextAlign.Center, - style = MaterialTheme.typography.titleLarge.toSemiBoldWeight(), + style = MaterialTheme.typography.titleLarge, color = MaterialTheme.colorScheme.onSurface, ) } @@ -127,7 +126,7 @@ private fun IntroDescription(descriptions: List<String>?) { Text( text = description, textAlign = TextAlign.Center, - style = MaterialTheme.typography.bodyLarge, + style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(top = SettingsDimension.paddingExtraSmall), ) diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ZeroStatePreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ZeroStatePreference.kt index 541922335387..3ebe18d4c342 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ZeroStatePreference.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ZeroStatePreference.kt @@ -23,6 +23,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.History +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -47,8 +48,8 @@ import androidx.graphics.shapes.CornerRounding import androidx.graphics.shapes.RoundedPolygon import androidx.graphics.shapes.star import androidx.graphics.shapes.toPath -import com.android.settingslib.spa.framework.theme.toSemiBoldWeight +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun ZeroStatePreference(icon: ImageVector, text: String? = null, description: String? = null) { val zeroStateShape = remember { @@ -81,7 +82,7 @@ fun ZeroStatePreference(icon: ImageVector, text: String? = null, description: St Text( text = text, textAlign = TextAlign.Center, - style = MaterialTheme.typography.titleMedium.toSemiBoldWeight(), + style = MaterialTheme.typography.titleMediumEmphasized, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(top = 24.dp), ) diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt index f99d20669183..668f683523a6 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt @@ -56,32 +56,27 @@ private fun BackAction(contentDescription: String, onClick: () -> Unit) { IconButton( onClick = onClick, modifier = - if (isSpaExpressiveEnabled) - Modifier - .padding( - start = SettingsDimension.paddingLarge, - end = SettingsDimension.paddingSmall, - top = SettingsDimension.paddingExtraSmall, - bottom = SettingsDimension.paddingExtraSmall, - ) - .size(SettingsDimension.actionIconWidth, SettingsDimension.actionIconHeight) - .clip(SettingsShape.CornerExtraLarge) - else Modifier, + if (isSpaExpressiveEnabled) + Modifier.padding( + start = SettingsDimension.paddingExtraSmall5, + end = SettingsDimension.paddingSmall, + top = SettingsDimension.paddingExtraSmall, + bottom = SettingsDimension.paddingExtraSmall, + ) + .size(SettingsDimension.actionIconSize) + .clip(SettingsShape.CornerExtraLarge) + else Modifier, ) { Icon( imageVector = Icons.AutoMirrored.Outlined.ArrowBack, contentDescription = contentDescription, modifier = - if (isSpaExpressiveEnabled) - Modifier - .size( - SettingsDimension.actionIconWidth, - SettingsDimension.actionIconHeight, - ) - .clip(SettingsShape.CornerExtraLarge) - .background(MaterialTheme.colorScheme.surfaceContainerHighest) - .padding(SettingsDimension.actionIconPadding) - else Modifier, + if (isSpaExpressiveEnabled) + Modifier.size(SettingsDimension.actionIconSize) + .clip(SettingsShape.CornerExtraLarge) + .background(MaterialTheme.colorScheme.surfaceContainerHighest) + .padding(SettingsDimension.actionIconPadding) + else Modifier, ) } } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt index 693fb3541bb8..0c0ece487578 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt @@ -142,10 +142,11 @@ private fun Title(title: String, maxLines: Int = Int.MAX_VALUE) { Text( text = title, modifier = - Modifier.padding( + Modifier + .padding( start = - if (isSpaExpressiveEnabled) SettingsDimension.paddingExtraSmall - else SettingsDimension.itemPaddingAround, + if (isSpaExpressiveEnabled) SettingsDimension.paddingExtraSmall + else SettingsDimension.itemPaddingAround, end = SettingsDimension.itemPaddingEnd, ) .semantics { heading() }, @@ -156,13 +157,22 @@ private fun Title(title: String, maxLines: Int = Int.MAX_VALUE) { @Composable private fun topAppBarColors() = - TopAppBarColors( - containerColor = MaterialTheme.colorScheme.settingsBackground, - scrolledContainerColor = MaterialTheme.colorScheme.surfaceVariant, - navigationIconContentColor = MaterialTheme.colorScheme.onSurface, - titleContentColor = MaterialTheme.colorScheme.onSurface, - actionIconContentColor = MaterialTheme.colorScheme.onSurfaceVariant, - ) + if (isSpaExpressiveEnabled) + TopAppBarColors( + containerColor = MaterialTheme.colorScheme.surfaceContainer, + scrolledContainerColor = MaterialTheme.colorScheme.surfaceContainer, + navigationIconContentColor = MaterialTheme.colorScheme.onSurface, + titleContentColor = MaterialTheme.colorScheme.onSurface, + actionIconContentColor = MaterialTheme.colorScheme.primary, + ) + else + TopAppBarColors( + containerColor = MaterialTheme.colorScheme.settingsBackground, + scrolledContainerColor = MaterialTheme.colorScheme.surfaceVariant, + navigationIconContentColor = MaterialTheme.colorScheme.onSurface, + titleContentColor = MaterialTheme.colorScheme.onSurface, + actionIconContentColor = MaterialTheme.colorScheme.onSurfaceVariant, + ) /** * Represents the colors used by a top app bar in different states. @@ -257,14 +267,16 @@ private fun SingleRowTopAppBar( // Compose a Surface with a TopAppBarLayout content. Box( modifier = - Modifier.drawBehind { drawRect(color = colors.scrolledContainerColor) } + Modifier + .drawBehind { drawRect(color = colors.scrolledContainerColor) } .semantics { isTraversalGroup = true } .pointerInput(Unit) {} ) { val height = LocalDensity.current.run { ContainerHeight.toPx() } TopAppBarLayout( modifier = - Modifier.windowInsetsPadding(windowInsets) + Modifier + .windowInsetsPadding(windowInsets) // clip after padding so we don't show the title over the inset area .clipToBounds(), heightPx = height, @@ -387,7 +399,8 @@ private fun TwoRowsTopAppBar( Column { TopAppBarLayout( modifier = - Modifier.windowInsetsPadding(windowInsets) + Modifier + .windowInsetsPadding(windowInsets) // clip after padding so we don't show the title over the inset area .clipToBounds(), heightPx = pinnedHeightPx, @@ -495,14 +508,17 @@ private fun TopAppBarLayout( ) { Layout( { - Box(Modifier.layoutId("navigationIcon").padding(start = TopAppBarHorizontalPadding)) { + Box(Modifier + .layoutId("navigationIcon") + .padding(start = TopAppBarHorizontalPadding)) { CompositionLocalProvider( LocalContentColor provides navigationIconContentColor, content = navigationIcon, ) } Box( - Modifier.layoutId("title") + Modifier + .layoutId("title") .padding(horizontal = TopAppBarHorizontalPadding) .then(if (hideTitleSemantics) Modifier.clearAndSetSemantics {} else Modifier) .graphicsLayer { alpha = titleAlpha() } @@ -521,7 +537,9 @@ private fun TopAppBarLayout( ) } } - Box(Modifier.layoutId("actionIcons").padding(end = TopAppBarHorizontalPadding)) { + Box(Modifier + .layoutId("actionIcons") + .padding(end = TopAppBarHorizontalPadding)) { CompositionLocalProvider( LocalContentColor provides actionIconContentColor, content = actions, diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt index 62bc00a8b347..f10f96afd389 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt @@ -28,6 +28,7 @@ import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.TouchApp +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -51,6 +52,7 @@ import com.android.settingslib.spa.widget.preference.Preference import com.android.settingslib.spa.widget.preference.PreferenceModel /** A category title that is placed before a group of similar items. */ +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun CategoryTitle(title: String) { Text( @@ -67,7 +69,9 @@ fun CategoryTitle(title: String) { bottom = 8.dp, ), color = MaterialTheme.colorScheme.primary, - style = MaterialTheme.typography.labelMedium, + style = + if (isSpaExpressiveEnabled) MaterialTheme.typography.labelLargeEmphasized + else MaterialTheme.typography.labelMedium, ) } @@ -76,7 +80,11 @@ fun CategoryTitle(title: String) { * visually separates groups of items. */ @Composable -fun Category(title: String? = null, modifier: Modifier = Modifier, content: @Composable ColumnScope.() -> Unit) { +fun Category( + title: String? = null, + modifier: Modifier = Modifier, + content: @Composable ColumnScope.() -> Unit, +) { var displayTitle by remember { mutableStateOf(false) } Column( modifier = @@ -90,7 +98,8 @@ fun Category(title: String? = null, modifier: Modifier = Modifier, content: @Com if (title != null && displayTitle) CategoryTitle(title = title) Column( modifier = - modifier.onGloballyPositioned { coordinates -> + modifier + .onGloballyPositioned { coordinates -> displayTitle = coordinates.size.height > 0 } .then( diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt index 6e4fd78a039b..03777cc49df7 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt @@ -195,7 +195,9 @@ private fun SpinnerText( else Modifier ), color = color, - style = MaterialTheme.typography.labelLarge, + style = + if (isSpaExpressiveEnabled) MaterialTheme.typography.titleMedium + else MaterialTheme.typography.labelLarge, ) } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java index 0c642d7b8f98..3c36c4438bca 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java @@ -30,6 +30,7 @@ import android.net.Uri; import android.provider.DeviceConfig; import android.provider.MediaStore; import android.provider.Settings; +import android.sysprop.BluetoothProperties; import android.text.TextUtils; import android.util.Log; import android.util.Pair; @@ -648,8 +649,10 @@ public class BluetoothUtils { /** Returns if the le audio sharing UI is available. */ public static boolean isAudioSharingUIAvailable(@Nullable Context context) { - return isAudioSharingEnabled() || (context != null && isAudioSharingPreviewEnabled( - context.getContentResolver())); + return (Flags.enableLeAudioSharing() + || (context != null && Flags.audioSharingDeveloperOption() + && getAudioSharingPreviewValue(context.getContentResolver()))) + && isAudioSharingSupported(); } /** Returns if the le audio sharing hysteresis mode fix is available. */ @@ -662,31 +665,39 @@ public class BluetoothUtils { /** Returns if the le audio sharing is enabled. */ public static boolean isAudioSharingEnabled() { - BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - try { - return Flags.enableLeAudioSharing() - && adapter.isLeAudioBroadcastSourceSupported() - == BluetoothStatusCodes.FEATURE_SUPPORTED - && adapter.isLeAudioBroadcastAssistantSupported() - == BluetoothStatusCodes.FEATURE_SUPPORTED; - } catch (IllegalStateException e) { - Log.d(TAG, "Fail to check isAudioSharingEnabled, e = ", e); - return false; - } + return Flags.enableLeAudioSharing() && isAudioSharingSupported(); } /** Returns if the le audio sharing preview is enabled in developer option. */ public static boolean isAudioSharingPreviewEnabled(@Nullable ContentResolver contentResolver) { + return Flags.audioSharingDeveloperOption() + && getAudioSharingPreviewValue(contentResolver) + && isAudioSharingSupported(); + } + + /** Returns if the device has le audio sharing capability */ + private static boolean isAudioSharingSupported() { BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); try { - return Flags.audioSharingDeveloperOption() - && getAudioSharingPreviewValue(contentResolver) - && adapter.isLeAudioBroadcastSourceSupported() - == BluetoothStatusCodes.FEATURE_SUPPORTED - && adapter.isLeAudioBroadcastAssistantSupported() - == BluetoothStatusCodes.FEATURE_SUPPORTED; + // b/381777424 The APIs have to return ERROR_BLUETOOTH_NOT_ENABLED when BT off based on + // CDD definition. + // However, app layer need to gate the feature based on whether the device has audio + // sharing capability regardless of the BT state. + // So here we check the BluetoothProperties when BT off. + // + // TODO: Also check SystemProperties "persist.bluetooth.leaudio_dynamic_switcher.mode" + // and return true if it is in broadcast mode. + // Now SystemUI don't have access to read the value. + int sourceSupportedCode = adapter.isLeAudioBroadcastSourceSupported(); + int assistantSupportedCode = adapter.isLeAudioBroadcastAssistantSupported(); + return (sourceSupportedCode == BluetoothStatusCodes.FEATURE_SUPPORTED + || (sourceSupportedCode == BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED + && BluetoothProperties.isProfileBapBroadcastSourceEnabled().orElse(false))) + && (assistantSupportedCode == BluetoothStatusCodes.FEATURE_SUPPORTED + || (assistantSupportedCode == BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED + && BluetoothProperties.isProfileBapBroadcastAssistEnabled().orElse(false))); } catch (IllegalStateException e) { - Log.d(TAG, "Fail to check isAudioSharingPreviewEnabled, e = ", e); + Log.d(TAG, "Fail to check isAudioSharingSupported, e = ", e); return false; } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java index 2c99a2d4818c..7d5eece6c30e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java @@ -56,6 +56,7 @@ import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import com.android.settingslib.R; +import com.android.settingslib.flags.Flags; import com.google.common.collect.ImmutableList; @@ -1126,6 +1127,10 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { /** Update fallback active device if needed. */ public void updateFallbackActiveDeviceIfNeeded() { + if (Flags.disableAudioSharingAutoPickFallbackInUi()) { + Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded, disable flag is on"); + return; + } if (isWorkProfile(mContext)) { Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded for work profile."); return; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java index 22b315084f3f..b86f4b3715b5 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java @@ -309,6 +309,7 @@ public class BluetoothEventManagerTest { private void setUpAudioSharing(boolean enableFlag, boolean enableFeature, boolean enableProfile, boolean workProfile) { + mSetFlagsRule.disableFlags(Flags.FLAG_DISABLE_AUDIO_SHARING_AUTO_PICK_FALLBACK_IN_UI); if (enableFlag) { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); } else { diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index e01cb84f60ae..a2cc008843a4 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -1053,14 +1053,10 @@ public class SettingsBackupAgent extends BackupAgentHelper { Log.d(TAG, "Restored font scale from: " + toRestore + " to " + value); } - // TODO(b/379861078): Log metrics inside this method. settingsHelper.restoreValue(this, cr, contentValues, destination, key, value, mRestoredFromSdkInt); Log.d(TAG, "Restored setting: " + destination + " : " + key + "=" + value); - if (areAgentMetricsEnabled) { - mBackupRestoreEventLogger.logItemsRestored(finalSettingsKey, /* count= */ 1); - } } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java index ab8d739feb43..4f5203136bbc 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java @@ -81,6 +81,7 @@ public class SettingsHelper { // Error messages for logging metrics. private static final String ERROR_REMOTE_EXCEPTION_SETTING_LOCALE_DATA = "remote_exception_setting_locale_data"; + private static final String ERROR_FAILED_TO_RESTORE_SETTING = "failed_to_restore_setting"; private Context mContext; private AudioManager mAudioManager; @@ -206,6 +207,12 @@ public class SettingsHelper { table = sGlobalLookup; } + // Get datatype for B&R metrics logging. + String datatype = ""; + if (Flags.enableMetricsSettingsBackupAgents()) { + datatype = SettingsBackupRestoreKeys.getKeyFromUri(destination); + } + sendBroadcast = sBroadcastOnRestore.contains(name); sendBroadcastSystemUI = sBroadcastOnRestoreSystemUI.contains(name); sendBroadcastAccessibility = sBroadcastOnRestoreAccessibility.contains(name); @@ -292,12 +299,19 @@ public class SettingsHelper { contentValues.put(Settings.NameValueTable.NAME, name); contentValues.put(Settings.NameValueTable.VALUE, value); cr.insert(destination, contentValues); + if (Flags.enableMetricsSettingsBackupAgents()) { + mBackupRestoreEventLogger.logItemsRestored(datatype, /* count= */ 1); + } } catch (Exception e) { // If we fail to apply the setting, by definition nothing happened sendBroadcast = false; sendBroadcastSystemUI = false; sendBroadcastAccessibility = false; Log.e(TAG, "Failed to restore setting name: " + name + " + value: " + value, e); + if (Flags.enableMetricsSettingsBackupAgents()) { + mBackupRestoreEventLogger.logItemsRestoreFailed( + datatype, /* count= */ 1, ERROR_FAILED_TO_RESTORE_SETTING); + } } finally { // If this was an element of interest, send the "we just restored it" // broadcast with the historical value now that the new value has diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java index 350c149f40de..18c43a704bcc 100644 --- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java +++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java @@ -422,75 +422,6 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { @Test @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) - public void restoreSettings_agentMetricsAreEnabled_agentMetricsAreLogged() { - mAgentUnderTest.onCreate( - UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); - SettingsBackupAgent.SettingsBackupAllowlist allowlist = - new SettingsBackupAgent.SettingsBackupAllowlist( - new String[] {OVERRIDDEN_TEST_SETTING}, - TEST_VALUES_VALIDATORS); - mAgentUnderTest.setSettingsAllowlist(allowlist); - mAgentUnderTest.setBlockedSettings(); - TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext); - mAgentUnderTest.mSettingsHelper = settingsHelper; - - byte[] backupData = generateBackupData(TEST_VALUES); - mAgentUnderTest - .restoreSettings( - backupData, - /* pos= */ 0, - backupData.length, - TEST_URI, - /* movedToGlobal= */ null, - /* movedToSecure= */ null, - /* movedToSystem= */ null, - /* blockedSettingsArrayId= */ 0, - /* dynamicBlockList= */ Collections.emptySet(), - /* settingsToPreserve= */ Collections.emptySet(), - TEST_KEY); - - DataTypeResult loggingResult = - getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest); - assertNotNull(loggingResult); - assertEquals(loggingResult.getSuccessCount(), 1); - } - - @Test - @DisableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) - public void restoreSettings_agentMetricsAreDisabled_agentMetricsAreNotLogged() { - mAgentUnderTest.onCreate( - UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); - SettingsBackupAgent.SettingsBackupAllowlist allowlist = - new SettingsBackupAgent.SettingsBackupAllowlist( - new String[] {OVERRIDDEN_TEST_SETTING}, - TEST_VALUES_VALIDATORS); - mAgentUnderTest.setSettingsAllowlist(allowlist); - mAgentUnderTest.setBlockedSettings(); - TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext); - mAgentUnderTest.mSettingsHelper = settingsHelper; - - byte[] backupData = generateBackupData(TEST_VALUES); - mAgentUnderTest - .restoreSettings( - backupData, - /* pos= */ 0, - backupData.length, - TEST_URI, - /* movedToGlobal= */ null, - /* movedToSecure= */ null, - /* movedToSystem= */ null, - /* blockedSettingsArrayId= */ 0, - /* dynamicBlockList= */ Collections.emptySet(), - /* settingsToPreserve= */ Collections.emptySet(), - TEST_KEY); - - DataTypeResult loggingResult = - getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest); - assertNull(loggingResult); - } - - @Test - @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) public void restoreSettings_agentMetricsAreEnabled_readEntityDataFails_failureIsLogged() throws IOException { when(mBackupDataInput.readEntityData(any(byte[].class), anyInt(), anyInt())) @@ -577,6 +508,40 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { } @Test + @DisableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void + restoreSettings_agentMetricsAreDisabled_settingIsSkippedBySystem_failureIsNotLogged() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + String[] settingBlockedBySystem = new String[] {OVERRIDDEN_TEST_SETTING}; + SettingsBackupAgent.SettingsBackupAllowlist allowlist = + new SettingsBackupAgent.SettingsBackupAllowlist( + settingBlockedBySystem, + TEST_VALUES_VALIDATORS); + mAgentUnderTest.setSettingsAllowlist(allowlist); + mAgentUnderTest.setBlockedSettings(settingBlockedBySystem); + TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext); + mAgentUnderTest.mSettingsHelper = settingsHelper; + + byte[] backupData = generateBackupData(TEST_VALUES); + mAgentUnderTest + .restoreSettings( + backupData, + /* pos= */ 0, + backupData.length, + TEST_URI, + /* movedToGlobal= */ null, + /* movedToSecure= */ null, + /* movedToSystem= */ null, + /* blockedSettingsArrayId= */ 0, + /* dynamicBlockList= */ Collections.emptySet(), + /* settingsToPreserve= */ Collections.emptySet(), + TEST_KEY); + + assertNull(getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest)); + } + + @Test @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) public void restoreSettings_agentMetricsAreEnabled_settingIsSkippedByBlockList_failureIsLogged() { mAgentUnderTest.onCreate( @@ -615,8 +580,9 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { } @Test - @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) - public void restoreSettings_agentMetricsAreEnabled_settingIsPreserved_failureIsLogged() { + @DisableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void + restoreSettings_agentMetricsAreDisabled_settingIsSkippedByBlockList_failureIsNotLogged() { mAgentUnderTest.onCreate( UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); SettingsBackupAgent.SettingsBackupAllowlist allowlist = @@ -627,7 +593,7 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { mAgentUnderTest.setBlockedSettings(); TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext); mAgentUnderTest.mSettingsHelper = settingsHelper; - Set<String> preservedSettings = + Set<String> dynamicBlockList = Set.of(Uri.withAppendedPath(TEST_URI, OVERRIDDEN_TEST_SETTING).toString()); byte[] backupData = generateBackupData(TEST_VALUES); @@ -641,30 +607,28 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { /* movedToSecure= */ null, /* movedToSystem= */ null, /* blockedSettingsArrayId= */ 0, - /* dynamicBlockList = */ Collections.emptySet(), - preservedSettings, + dynamicBlockList, + /* settingsToPreserve= */ Collections.emptySet(), TEST_KEY); - DataTypeResult loggingResult = - getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest); - assertNotNull(loggingResult); - assertEquals(loggingResult.getFailCount(), 1); - assertTrue(loggingResult.getErrors().containsKey(ERROR_SKIPPED_PRESERVED)); + assertNull(getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest)); } @Test @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) - public void restoreSettings_agentMetricsAreEnabled_settingIsNotValid_failureIsLogged() { + public void restoreSettings_agentMetricsAreEnabled_settingIsPreserved_failureIsLogged() { mAgentUnderTest.onCreate( UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); SettingsBackupAgent.SettingsBackupAllowlist allowlist = new SettingsBackupAgent.SettingsBackupAllowlist( new String[] {OVERRIDDEN_TEST_SETTING}, - /* settingsValidators= */ null); + TEST_VALUES_VALIDATORS); mAgentUnderTest.setSettingsAllowlist(allowlist); mAgentUnderTest.setBlockedSettings(); TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext); mAgentUnderTest.mSettingsHelper = settingsHelper; + Set<String> preservedSettings = + Set.of(Uri.withAppendedPath(TEST_URI, OVERRIDDEN_TEST_SETTING).toString()); byte[] backupData = generateBackupData(TEST_VALUES); mAgentUnderTest @@ -678,19 +642,19 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { /* movedToSystem= */ null, /* blockedSettingsArrayId= */ 0, /* dynamicBlockList = */ Collections.emptySet(), - /* settingsToPreserve= */ Collections.emptySet(), + preservedSettings, TEST_KEY); DataTypeResult loggingResult = getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest); assertNotNull(loggingResult); assertEquals(loggingResult.getFailCount(), 1); - assertTrue(loggingResult.getErrors().containsKey(ERROR_DID_NOT_PASS_VALIDATION)); + assertTrue(loggingResult.getErrors().containsKey(ERROR_SKIPPED_PRESERVED)); } @Test - @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) - public void restoreSettings_agentMetricsAreEnabled_settingIsMarkedAsMovedToGlobal_agentMetricsAreLoggedWithGlobalKey() { + @DisableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void restoreSettings_agentMetricsAreDisabled_settingIsPreserved_failureIsNotLogged() { mAgentUnderTest.onCreate( UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); SettingsBackupAgent.SettingsBackupAllowlist allowlist = @@ -701,6 +665,8 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { mAgentUnderTest.setBlockedSettings(); TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext); mAgentUnderTest.mSettingsHelper = settingsHelper; + Set<String> preservedSettings = + Set.of(Uri.withAppendedPath(TEST_URI, OVERRIDDEN_TEST_SETTING).toString()); byte[] backupData = generateBackupData(TEST_VALUES); mAgentUnderTest @@ -709,30 +675,26 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { /* pos= */ 0, backupData.length, TEST_URI, - /* movedToGlobal= */ Set.of(OVERRIDDEN_TEST_SETTING), + /* movedToGlobal= */ null, /* movedToSecure= */ null, /* movedToSystem= */ null, /* blockedSettingsArrayId= */ 0, - /* dynamicBlockList= */ Collections.emptySet(), - /* settingsToPreserve= */ Collections.emptySet(), + /* dynamicBlockList = */ Collections.emptySet(), + preservedSettings, TEST_KEY); - DataTypeResult loggingResult = - getLoggingResultForDatatype(KEY_GLOBAL, mAgentUnderTest); - assertNotNull(loggingResult); - assertEquals(loggingResult.getSuccessCount(), 1); assertNull(getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest)); } @Test @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) - public void restoreSettings_agentMetricsAreEnabled_settingIsMarkedAsMovedToSecure_agentMetricsAreLoggedWithSecureKey() { + public void restoreSettings_agentMetricsAreEnabled_settingIsNotValid_failureIsLogged() { mAgentUnderTest.onCreate( UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); SettingsBackupAgent.SettingsBackupAllowlist allowlist = new SettingsBackupAgent.SettingsBackupAllowlist( new String[] {OVERRIDDEN_TEST_SETTING}, - TEST_VALUES_VALIDATORS); + /* settingsValidators= */ null); mAgentUnderTest.setSettingsAllowlist(allowlist); mAgentUnderTest.setBlockedSettings(); TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext); @@ -746,29 +708,29 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { backupData.length, TEST_URI, /* movedToGlobal= */ null, - /* movedToSecure= */ Set.of(OVERRIDDEN_TEST_SETTING), + /* movedToSecure= */ null, /* movedToSystem= */ null, /* blockedSettingsArrayId= */ 0, - /* dynamicBlockList= */ Collections.emptySet(), + /* dynamicBlockList = */ Collections.emptySet(), /* settingsToPreserve= */ Collections.emptySet(), TEST_KEY); DataTypeResult loggingResult = - getLoggingResultForDatatype(KEY_SECURE, mAgentUnderTest); + getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest); assertNotNull(loggingResult); - assertEquals(loggingResult.getSuccessCount(), 1); - assertNull(getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest)); + assertEquals(loggingResult.getFailCount(), 1); + assertTrue(loggingResult.getErrors().containsKey(ERROR_DID_NOT_PASS_VALIDATION)); } @Test - @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) - public void restoreSettings_agentMetricsAreEnabled_settingIsMarkedAsMovedToSystem_agentMetricsAreLoggedWithSystemKey() { + @DisableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void restoreSettings_agentMetricsAreDisabled_settingIsNotValid_failureIsNotLogged() { mAgentUnderTest.onCreate( UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); SettingsBackupAgent.SettingsBackupAllowlist allowlist = new SettingsBackupAgent.SettingsBackupAllowlist( new String[] {OVERRIDDEN_TEST_SETTING}, - TEST_VALUES_VALIDATORS); + /* settingsValidators= */ null); mAgentUnderTest.setSettingsAllowlist(allowlist); mAgentUnderTest.setBlockedSettings(); TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext); @@ -783,16 +745,12 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { TEST_URI, /* movedToGlobal= */ null, /* movedToSecure= */ null, - /* movedToSystem= */ Set.of(OVERRIDDEN_TEST_SETTING), + /* movedToSystem= */ null, /* blockedSettingsArrayId= */ 0, - /* dynamicBlockList= */ Collections.emptySet(), + /* dynamicBlockList = */ Collections.emptySet(), /* settingsToPreserve= */ Collections.emptySet(), TEST_KEY); - DataTypeResult loggingResult = - getLoggingResultForDatatype(KEY_SYSTEM, mAgentUnderTest); - assertNotNull(loggingResult); - assertEquals(loggingResult.getSuccessCount(), 1); assertNull(getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest)); } diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java index 58200d4f6553..40654b0e2f37 100644 --- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java +++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java @@ -28,6 +28,9 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import android.app.backup.BackupAnnotations.OperationType; +import android.app.backup.BackupRestoreEventLogger; +import android.app.backup.BackupRestoreEventLogger.DataTypeResult; import android.content.ContentProvider; import android.content.ContentValues; import android.content.Context; @@ -42,6 +45,7 @@ import android.media.Utils; import android.net.Uri; import android.os.Bundle; import android.os.LocaleList; +import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.BaseColumns; @@ -65,6 +69,8 @@ import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; /** * Tests for the SettingsHelperTest @@ -91,6 +97,8 @@ public class SettingsHelperTest { @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Rule + public MockitoRule mockitoRule = MockitoJUnit.rule(); @Mock private Context mContext; @Mock private Resources mResources; @@ -100,6 +108,8 @@ public class SettingsHelperTest { @Mock private MockContentResolver mContentResolver; private MockSettingsProvider mSettingsProvider; + private BackupRestoreEventLogger mBackupRestoreEventLogger; + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -115,6 +125,8 @@ public class SettingsHelperTest { when(mContext.getContentResolver()).thenReturn(mContentResolver); mSettingsProvider = new MockSettingsProvider(mContext); mContentResolver.addProvider(Settings.AUTHORITY, mSettingsProvider); + mBackupRestoreEventLogger = new BackupRestoreEventLogger(OperationType.RESTORE); + mSettingsHelper.setBackupRestoreEventLogger(mBackupRestoreEventLogger); } @After @@ -791,6 +803,99 @@ public class SettingsHelperTest { assertThat(mSettingsHelper.getLocaleList()).isEqualTo(LOCALE_LIST); } + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void + restoreValue_metricsFlagIsEnabled_restoresSetting_secureUri_logsSuccessWithSecureDatatype() + { + mSettingsHelper.restoreValue( + mContext, + mContentResolver, + new ContentValues(), + Settings.Secure.CONTENT_URI, + SETTING_KEY, + SETTING_VALUE, + /* restoredFromSdkInt */ 0); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(SettingsBackupRestoreKeys.KEY_SECURE); + assertThat(loggingResult).isNotNull(); + assertThat(loggingResult.getSuccessCount()).isEqualTo(1); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void + restoreValue_metricsFlagIsEnabled_restoresSetting_systemUri_logsSuccessWithSystemDatatype() + { + mSettingsHelper.restoreValue( + mContext, + mContentResolver, + new ContentValues(), + Settings.System.CONTENT_URI, + SETTING_KEY, + SETTING_VALUE, + /* restoredFromSdkInt */ 0); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(SettingsBackupRestoreKeys.KEY_SYSTEM); + assertThat(loggingResult).isNotNull(); + assertThat(loggingResult.getSuccessCount()).isEqualTo(1); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void + restoreValue_metricsFlagIsEnabled_restoresSetting_globalUri_logsSuccessWithGlobalDatatype() + { + mSettingsHelper.restoreValue( + mContext, + mContentResolver, + new ContentValues(), + Settings.Global.CONTENT_URI, + SETTING_KEY, + SETTING_VALUE, + /* restoredFromSdkInt */ 0); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(SettingsBackupRestoreKeys.KEY_GLOBAL); + assertThat(loggingResult).isNotNull(); + assertThat(loggingResult.getSuccessCount()).isEqualTo(1); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void restoreValue_metricsFlagIsEnabled_doesNotRestoreSetting_logsFailure() { + mSettingsHelper.restoreValue( + mContext, + mContentResolver, + new ContentValues(), + Uri.EMPTY, + SETTING_KEY, + SETTING_VALUE, + /* restoredFromSdkInt */ 0); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(SettingsBackupRestoreKeys.KEY_UNKNOWN); + assertThat(loggingResult).isNotNull(); + assertThat(loggingResult.getFailCount()).isEqualTo(1); + } + + @Test + @DisableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void restoreValue_metricsFlagIsDisabled_doesNotLogMetrics() { + mSettingsHelper.restoreValue( + mContext, + mContentResolver, + new ContentValues(), + Uri.EMPTY, + SETTING_KEY, + SETTING_VALUE, + /* restoredFromSdkInt */ 0); + + assertThat(getLoggingResultForDatatype(SettingsBackupRestoreKeys.KEY_UNKNOWN)).isNull(); + } + private int getAutoRotationSettingValue() { return Settings.System.getInt(mContentResolver, Settings.System.ACCELEROMETER_ROTATION, @@ -851,4 +956,13 @@ public class SettingsHelperTest { assertThat(Settings.System.getString(mContentResolver, settings)) .isEqualTo(testRingtoneSettingsValue); } + + private DataTypeResult getLoggingResultForDatatype(String dataType) { + for (DataTypeResult result : mBackupRestoreEventLogger.getLoggingResults()) { + if (result.getDataType().equals(dataType)) { + return result; + } + } + return null; + } } diff --git a/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt b/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt index 029b9cde4da9..35e85a0aa615 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt @@ -41,6 +41,7 @@ import androidx.compose.ui.input.pointer.SuspendingPointerInputModifierNode import androidx.compose.ui.input.pointer.changedToDownIgnoreConsumed import androidx.compose.ui.input.pointer.changedToUpIgnoreConsumed import androidx.compose.ui.input.pointer.positionChange +import androidx.compose.ui.input.pointer.positionChangeIgnoreConsumed import androidx.compose.ui.input.pointer.util.VelocityTracker import androidx.compose.ui.input.pointer.util.addPointerInputChange import androidx.compose.ui.node.CompositionLocalConsumerModifierNode @@ -55,8 +56,7 @@ import androidx.compose.ui.util.fastAny import androidx.compose.ui.util.fastSumBy import com.android.compose.modifiers.thenIf import kotlin.math.sign -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.CoroutineStart +import kotlinx.coroutines.async import kotlinx.coroutines.launch /** @@ -67,6 +67,16 @@ import kotlinx.coroutines.launch */ interface NestedDraggable { /** + * Return whether we should start a drag given the pointer [change]. + * + * This is called when the touch slop is reached. If this returns `true`, then the [change] will + * be consumed and [onDragStarted] will be called. If this returns `false`, then the current + * touch slop detection will be reset and restarted at the current + * [change position][PointerInputChange.position]. + */ + fun shouldStartDrag(change: PointerInputChange): Boolean = true + + /** * Called when a drag is started in the given [position] (*before* dragging the touch slop) and * in the direction given by [sign], with the given number of [pointersDown] when the touch slop * was detected. @@ -161,11 +171,7 @@ private class NestedDraggableNode( } /** The controller created by the nested scroll logic (and *not* the drag logic). */ - private var nestedScrollController: WrappedController? = null - set(value) { - field?.ensureOnDragStoppedIsCalled() - field = value - } + private var nestedScrollController: NestedScrollController? = null /** * The last pointer which was the first down since the last time all pointers were up. @@ -183,6 +189,7 @@ private class NestedDraggableNode( override fun onDetach() { nestedScrollController?.ensureOnDragStoppedIsCalled() + nestedScrollController = null } fun update( @@ -199,6 +206,7 @@ private class NestedDraggableNode( trackDownPositionDelegate?.resetPointerInputHandler() detectDragsDelegate?.resetPointerInputHandler() nestedScrollController?.ensureOnDragStoppedIsCalled() + nestedScrollController = null if (!enabled && trackDownPositionDelegate != null) { check(detectDragsDelegate != null) @@ -248,8 +256,14 @@ private class NestedDraggableNode( var overSlop = 0f val onTouchSlopReached = { change: PointerInputChange, over: Float -> - change.consume() - overSlop = over + if (draggable.shouldStartDrag(change)) { + change.consume() + overSlop = over + } + + // If shouldStartDrag() returned false, then we didn't consume the event and + // awaitTouchSlopOrCancellation() will reset the touch slop detector so that the + // user has to drag by at least the touch slop again. } suspend fun AwaitPointerEventScope.awaitTouchSlopOrCancellation( @@ -288,15 +302,21 @@ private class NestedDraggableNode( if (drag != null) { velocityTracker.resetTracking() - val sign = (drag.position - down.position).toFloat().sign + val sign = drag.positionChangeIgnoreConsumed().toFloat().sign + check(sign != 0f) { + buildString { + append("sign is equal to 0 ") + append("touchSlop ${currentValueOf(LocalViewConfiguration).touchSlop} ") + append("down.position ${down.position} ") + append("drag.position ${drag.position} ") + append("drag.previousPosition ${drag.previousPosition}") + } + } + check(pointersDownCount > 0) { "pointersDownCount is equal to $pointersDownCount" } - val wrappedController = - WrappedController( - coroutineScope, - draggable.onDragStarted(down.position, sign, pointersDownCount), - ) + val controller = draggable.onDragStarted(down.position, sign, pointersDownCount) if (overSlop != 0f) { - onDrag(wrappedController, drag, overSlop, velocityTracker) + onDrag(controller, drag, overSlop, velocityTracker) } // If a drag was started, we cancel any other drag started by a nested scrollable. @@ -304,12 +324,13 @@ private class NestedDraggableNode( // Note: we cancel the nested drag here *after* starting the new drag so that in the // STL case, the cancelled drag will not change the current scene of the STL. nestedScrollController?.ensureOnDragStoppedIsCalled() + nestedScrollController = null val isSuccessful = try { val onDrag = { change: PointerInputChange -> onDrag( - wrappedController, + controller, change, change.positionChange().toFloat(), velocityTracker, @@ -322,19 +343,17 @@ private class NestedDraggableNode( Orientation.Vertical -> verticalDrag(drag.id, onDrag) } } catch (t: Throwable) { - wrappedController.ensureOnDragStoppedIsCalled() + onDragStopped(controller, Velocity.Zero) throw t } if (isSuccessful) { val maxVelocity = currentValueOf(LocalViewConfiguration).maximumFlingVelocity val velocity = - velocityTracker - .calculateVelocity(Velocity(maxVelocity, maxVelocity)) - .toFloat() - onDragStopped(wrappedController, velocity) + velocityTracker.calculateVelocity(Velocity(maxVelocity, maxVelocity)) + onDragStopped(controller, velocity) } else { - onDragStopped(wrappedController, velocity = 0f) + onDragStopped(controller, Velocity.Zero) } } } @@ -348,88 +367,87 @@ private class NestedDraggableNode( ) { velocityTracker.addPointerInputChange(change) - scrollWithOverscroll(delta) { deltaFromOverscroll -> + scrollWithOverscroll(delta.toOffset()) { deltaFromOverscroll -> scrollWithNestedScroll(deltaFromOverscroll) { deltaFromNestedScroll -> - controller.onDrag(deltaFromNestedScroll) + controller.onDrag(deltaFromNestedScroll.toFloat()).toOffset() } } } - private fun onDragStopped(controller: WrappedController, velocity: Float) { - coroutineScope.launch(start = CoroutineStart.UNDISPATCHED) { - try { - flingWithOverscroll(velocity) { velocityFromOverscroll -> - flingWithNestedScroll(velocityFromOverscroll) { velocityFromNestedScroll -> - controller.onDragStopped(velocityFromNestedScroll) - } + private fun onDragStopped(controller: NestedDraggable.Controller, velocity: Velocity) { + // We launch in the scope of the dispatcher so that the fling is not cancelled if this node + // is removed right after onDragStopped() is called. + nestedScrollDispatcher.coroutineScope.launch { + flingWithOverscroll(velocity) { velocityFromOverscroll -> + flingWithNestedScroll(velocityFromOverscroll) { velocityFromNestedScroll -> + controller.onDragStopped(velocityFromNestedScroll.toFloat()).toVelocity() } - } finally { - controller.ensureOnDragStoppedIsCalled() } } } - private fun scrollWithOverscroll(delta: Float, performScroll: (Float) -> Float): Float { + private fun scrollWithOverscroll(delta: Offset, performScroll: (Offset) -> Offset): Offset { val effect = overscrollEffect return if (effect != null) { - effect - .applyToScroll(delta.toOffset(), source = NestedScrollSource.UserInput) { - performScroll(it.toFloat()).toOffset() - } - .toFloat() + effect.applyToScroll(delta, source = NestedScrollSource.UserInput) { performScroll(it) } } else { performScroll(delta) } } - private fun scrollWithNestedScroll(delta: Float, performScroll: (Float) -> Float): Float { + private fun scrollWithNestedScroll(delta: Offset, performScroll: (Offset) -> Offset): Offset { val preConsumed = - nestedScrollDispatcher - .dispatchPreScroll( - available = delta.toOffset(), - source = NestedScrollSource.UserInput, - ) - .toFloat() + nestedScrollDispatcher.dispatchPreScroll( + available = delta, + source = NestedScrollSource.UserInput, + ) val available = delta - preConsumed val consumed = performScroll(available) val left = available - consumed val postConsumed = - nestedScrollDispatcher - .dispatchPostScroll( - consumed = (preConsumed + consumed).toOffset(), - available = left.toOffset(), - source = NestedScrollSource.UserInput, - ) - .toFloat() + nestedScrollDispatcher.dispatchPostScroll( + consumed = preConsumed + consumed, + available = left, + source = NestedScrollSource.UserInput, + ) return consumed + preConsumed + postConsumed } private suspend fun flingWithOverscroll( - velocity: Float, - performFling: suspend (Float) -> Float, - ) { + velocity: Velocity, + performFling: suspend (Velocity) -> Velocity, + ): Velocity { val effect = overscrollEffect - if (effect != null) { - effect.applyToFling(velocity.toVelocity()) { performFling(it.toFloat()).toVelocity() } + return flingWithOverscroll(effect, velocity, performFling) + } + + private suspend fun flingWithOverscroll( + overscrollEffect: OverscrollEffect?, + velocity: Velocity, + performFling: suspend (Velocity) -> Velocity, + ): Velocity { + return if (overscrollEffect != null) { + overscrollEffect.applyToFling(velocity) { performFling(it) } + + // Effects always consume the whole velocity. + velocity } else { performFling(velocity) } } private suspend fun flingWithNestedScroll( - velocity: Float, - performFling: suspend (Float) -> Float, - ): Float { - val preConsumed = nestedScrollDispatcher.dispatchPreFling(available = velocity.toVelocity()) - val available = velocity - preConsumed.toFloat() + velocity: Velocity, + performFling: suspend (Velocity) -> Velocity, + ): Velocity { + val preConsumed = nestedScrollDispatcher.dispatchPreFling(available = velocity) + val available = velocity - preConsumed val consumed = performFling(available) val left = available - consumed - return nestedScrollDispatcher - .dispatchPostFling( - consumed = consumed.toVelocity() + preConsumed, - available = left.toVelocity(), - ) - .toFloat() + return nestedScrollDispatcher.dispatchPostFling( + consumed = consumed + preConsumed, + available = left, + ) } /* @@ -459,8 +477,7 @@ private class NestedDraggableNode( override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { val controller = nestedScrollController ?: return Offset.Zero - val consumed = controller.onDrag(available.toFloat()) - return consumed.toOffset() + return scrollWithOverscroll(controller, available) } override fun onPostScroll( @@ -485,49 +502,43 @@ private class NestedDraggableNode( // TODO(b/382665591): Replace this by check(pointersDownCount > 0). val pointersDown = pointersDownCount.coerceAtLeast(1) nestedScrollController = - WrappedController( - coroutineScope, + NestedScrollController( + overscrollEffect, draggable.onDragStarted(startedPosition, sign, pointersDown), ) } val controller = nestedScrollController ?: return Offset.Zero - return controller.onDrag(offset).toOffset() + return scrollWithOverscroll(controller, available) + } + + private fun scrollWithOverscroll(controller: NestedScrollController, offset: Offset): Offset { + return scrollWithOverscroll(offset) { + controller.controller.onDrag(it.toFloat()).toOffset() + } } override suspend fun onPreFling(available: Velocity): Velocity { val controller = nestedScrollController ?: return Velocity.Zero nestedScrollController = null - val consumed = controller.onDragStopped(available.toFloat()) - return consumed.toVelocity() + return nestedScrollDispatcher.coroutineScope + .async { controller.flingWithOverscroll(available) } + .await() } -} -/** - * A controller that wraps [delegate] and can be used to ensure that [onDragStopped] is called, but - * not more than once. - */ -private class WrappedController( - private val coroutineScope: CoroutineScope, - private val delegate: NestedDraggable.Controller, -) : NestedDraggable.Controller by delegate { - private var onDragStoppedCalled = false - - override fun onDrag(delta: Float): Float { - if (onDragStoppedCalled) return 0f - return delegate.onDrag(delta) - } - - override suspend fun onDragStopped(velocity: Float): Float { - if (onDragStoppedCalled) return 0f - onDragStoppedCalled = true - return delegate.onDragStopped(velocity) - } + private inner class NestedScrollController( + private val overscrollEffect: OverscrollEffect?, + val controller: NestedDraggable.Controller, + ) { + fun ensureOnDragStoppedIsCalled() { + nestedScrollDispatcher.coroutineScope.launch { flingWithOverscroll(Velocity.Zero) } + } - fun ensureOnDragStoppedIsCalled() { - // Start with UNDISPATCHED so that onDragStopped() is always run until its first suspension - // point, even if coroutineScope is cancelled. - coroutineScope.launch(start = CoroutineStart.UNDISPATCHED) { onDragStopped(velocity = 0f) } + suspend fun flingWithOverscroll(velocity: Velocity): Velocity { + return flingWithOverscroll(overscrollEffect, velocity) { + controller.onDragStopped(it.toFloat()).toVelocity() + } + } } } diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt index 735ab68bc6a6..f98b090e77fd 100644 --- a/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt +++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt @@ -32,6 +32,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.input.pointer.PointerInputChange import androidx.compose.ui.platform.LocalViewConfiguration import androidx.compose.ui.test.junit4.ComposeContentTestRule import androidx.compose.ui.test.junit4.createComposeRule @@ -42,7 +43,8 @@ import androidx.compose.ui.test.swipeLeft import androidx.compose.ui.unit.Velocity import com.google.common.truth.Truth.assertThat import kotlin.math.ceil -import kotlinx.coroutines.awaitCancellation +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.delay import org.junit.Ignore import org.junit.Rule import org.junit.Test @@ -62,9 +64,10 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw @Test fun simpleDrag() { val draggable = TestDraggable() + val effect = TestOverscrollEffect(orientation) { 0f } val touchSlop = rule.setContentWithTouchSlop { - Box(Modifier.fillMaxSize().nestedDraggable(draggable, orientation)) + Box(Modifier.fillMaxSize().nestedDraggable(draggable, orientation, effect)) } assertThat(draggable.onDragStartedCalled).isFalse() @@ -89,6 +92,7 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw assertThat(draggable.onDragDelta).isEqualTo(30f) assertThat(draggable.onDragStoppedCalled).isFalse() + assertThat(effect.applyToFlingDone).isFalse() rule.onRoot().performTouchInput { moveBy((-15f).toOffset()) @@ -97,16 +101,18 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw assertThat(draggable.onDragDelta).isEqualTo(15f) assertThat(draggable.onDragStoppedCalled).isTrue() + assertThat(effect.applyToFlingDone).isTrue() } @Test fun nestedScrollable() { val draggable = TestDraggable() + val effect = TestOverscrollEffect(orientation) { 0f } val touchSlop = rule.setContentWithTouchSlop { Box( Modifier.fillMaxSize() - .nestedDraggable(draggable, orientation) + .nestedDraggable(draggable, orientation, effect) .nestedScrollable(rememberScrollState()) ) } @@ -135,6 +141,7 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw assertThat(draggable.onDragCalled).isTrue() assertThat(draggable.onDragDelta).isEqualTo(-30f) assertThat(draggable.onDragStoppedCalled).isFalse() + assertThat(effect.applyToFlingDone).isFalse() rule.onRoot().performTouchInput { moveBy(15f.toOffset()) @@ -145,15 +152,17 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw assertThat(draggable.onDragCalled).isTrue() assertThat(draggable.onDragDelta).isEqualTo(-15f) assertThat(draggable.onDragStoppedCalled).isTrue() + assertThat(effect.applyToFlingDone).isTrue() } @Test fun onDragStoppedIsCalledWhenDraggableIsUpdatedAndReset() { val draggable = TestDraggable() + val effect = TestOverscrollEffect(orientation) { 0f } var orientation by mutableStateOf(orientation) val touchSlop = rule.setContentWithTouchSlop { - Box(Modifier.fillMaxSize().nestedDraggable(draggable, orientation)) + Box(Modifier.fillMaxSize().nestedDraggable(draggable, orientation, effect)) } assertThat(draggable.onDragStartedCalled).isFalse() @@ -165,6 +174,7 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw assertThat(draggable.onDragStartedCalled).isTrue() assertThat(draggable.onDragStoppedCalled).isFalse() + assertThat(effect.applyToFlingDone).isFalse() orientation = when (orientation) { @@ -173,17 +183,19 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw } rule.waitForIdle() assertThat(draggable.onDragStoppedCalled).isTrue() + assertThat(effect.applyToFlingDone).isTrue() } @Test fun onDragStoppedIsCalledWhenDraggableIsUpdatedAndReset_nestedScroll() { val draggable = TestDraggable() + val effect = TestOverscrollEffect(orientation) { 0f } var orientation by mutableStateOf(orientation) val touchSlop = rule.setContentWithTouchSlop { Box( Modifier.fillMaxSize() - .nestedDraggable(draggable, orientation) + .nestedDraggable(draggable, orientation, effect) .nestedScrollable(rememberScrollState()) ) } @@ -197,6 +209,7 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw assertThat(draggable.onDragStartedCalled).isTrue() assertThat(draggable.onDragStoppedCalled).isFalse() + assertThat(effect.applyToFlingDone).isFalse() orientation = when (orientation) { @@ -205,16 +218,34 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw } rule.waitForIdle() assertThat(draggable.onDragStoppedCalled).isTrue() + assertThat(effect.applyToFlingDone).isTrue() } @Test fun onDragStoppedIsCalledWhenDraggableIsRemovedDuringDrag() { val draggable = TestDraggable() + val postFlingDelay = 10 * 16L + val effect = + TestOverscrollEffect( + orientation, + onPostFling = { + // We delay the fling so that we can check that the draggable node methods are + // still called until completion even when the node is removed. + delay(postFlingDelay) + it + }, + ) { + 0f + } var composeContent by mutableStateOf(true) val touchSlop = rule.setContentWithTouchSlop { - if (composeContent) { - Box(Modifier.fillMaxSize().nestedDraggable(draggable, orientation)) + // We add an empty nested scroll connection here from which the scope will be used + // when dispatching the flings. + Box(Modifier.nestedScroll(remember { object : NestedScrollConnection {} })) { + if (composeContent) { + Box(Modifier.fillMaxSize().nestedDraggable(draggable, orientation, effect)) + } } } @@ -227,24 +258,44 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw assertThat(draggable.onDragStartedCalled).isTrue() assertThat(draggable.onDragStoppedCalled).isFalse() + assertThat(effect.applyToFlingDone).isFalse() composeContent = false rule.waitForIdle() + rule.mainClock.advanceTimeBy(postFlingDelay) assertThat(draggable.onDragStoppedCalled).isTrue() + assertThat(effect.applyToFlingDone).isTrue() } @Test fun onDragStoppedIsCalledWhenDraggableIsRemovedDuringDrag_nestedScroll() { val draggable = TestDraggable() + val postFlingDelay = 10 * 16L + val effect = + TestOverscrollEffect( + orientation, + onPostFling = { + // We delay the fling so that we can check that the draggable node methods are + // still called until completion even when the node is removed. + delay(postFlingDelay) + it + }, + ) { + 0f + } var composeContent by mutableStateOf(true) val touchSlop = rule.setContentWithTouchSlop { - if (composeContent) { - Box( - Modifier.fillMaxSize() - .nestedDraggable(draggable, orientation) - .nestedScrollable(rememberScrollState()) - ) + // We add an empty nested scroll connection here from which the scope will be used + // when dispatching the flings. + Box(Modifier.nestedScroll(remember { object : NestedScrollConnection {} })) { + if (composeContent) { + Box( + Modifier.fillMaxSize() + .nestedDraggable(draggable, orientation, effect) + .nestedScrollable(rememberScrollState()) + ) + } } } @@ -257,17 +308,22 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw assertThat(draggable.onDragStartedCalled).isTrue() assertThat(draggable.onDragStoppedCalled).isFalse() + assertThat(effect.applyToFlingDone).isFalse() composeContent = false rule.waitForIdle() + rule.mainClock.advanceTimeBy(postFlingDelay) assertThat(draggable.onDragStoppedCalled).isTrue() + assertThat(effect.applyToFlingDone).isTrue() } @Test fun onDragStoppedIsCalledWhenDraggableIsRemovedDuringFling() { val draggable = TestDraggable() + val effect = TestOverscrollEffect(orientation) { 0f } var composeContent by mutableStateOf(true) var preFlingCalled = false + val unblockPrefling = CompletableDeferred<Velocity>() rule.setContent { if (composeContent) { Box( @@ -281,12 +337,12 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw object : NestedScrollConnection { override suspend fun onPreFling(available: Velocity): Velocity { preFlingCalled = true - awaitCancellation() + return unblockPrefling.await() } } } ) - .nestedDraggable(draggable, orientation) + .nestedDraggable(draggable, orientation, effect) ) } } @@ -303,11 +359,14 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw assertThat(draggable.onDragStartedCalled).isTrue() assertThat(draggable.onDragStoppedCalled).isFalse() + assertThat(effect.applyToFlingDone).isFalse() assertThat(preFlingCalled).isTrue() composeContent = false + unblockPrefling.complete(Velocity.Zero) rule.waitForIdle() assertThat(draggable.onDragStoppedCalled).isTrue() + assertThat(effect.applyToFlingDone).isTrue() } @Test @@ -457,6 +516,83 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw assertThat(draggable.onDragStartedPointersDown).isEqualTo(6) } + @Test + fun shouldStartDrag() { + val draggable = TestDraggable() + val touchSlop = + rule.setContentWithTouchSlop { + Box(Modifier.fillMaxSize().nestedDraggable(draggable, orientation)) + } + + // Drag in one direction. + draggable.shouldStartDrag = false + rule.onRoot().performTouchInput { + down(center) + moveBy(touchSlop.toOffset()) + } + assertThat(draggable.onDragStartedCalled).isFalse() + + // Drag in the other direction. + draggable.shouldStartDrag = true + rule.onRoot().performTouchInput { moveBy(-touchSlop.toOffset()) } + assertThat(draggable.onDragStartedCalled).isTrue() + assertThat(draggable.onDragStartedSign).isEqualTo(-1f) + assertThat(draggable.onDragDelta).isEqualTo(0f) + } + + @Test + fun overscrollEffectIsUsedDuringNestedScroll() { + var consumeDrag = true + var consumedByDrag = 0f + var consumedByEffect = 0f + val draggable = + TestDraggable( + onDrag = { + if (consumeDrag) { + consumedByDrag += it + it + } else { + 0f + } + } + ) + val effect = + TestOverscrollEffect(orientation) { delta -> + /* Consumes everything. */ + consumedByEffect += delta + delta + } + + val touchSlop = + rule.setContentWithTouchSlop { + Box( + Modifier.fillMaxSize() + .nestedDraggable(draggable, orientation, overscrollEffect = effect) + .nestedScrollable(rememberScrollState()) + ) + } + + // Swipe on the nested scroll. The draggable consumes the scrolls. + rule.onRoot().performTouchInput { + down(center) + moveBy((touchSlop + 10f).toOffset()) + } + assertThat(draggable.onDragStartedCalled).isTrue() + assertThat(consumedByDrag).isEqualTo(10f) + assertThat(consumedByEffect).isEqualTo(0f) + + // Stop consuming the scrolls in the draggable. The overscroll effect should now consume + // the scrolls. + consumeDrag = false + rule.onRoot().performTouchInput { moveBy(20f.toOffset()) } + assertThat(consumedByDrag).isEqualTo(10f) + assertThat(consumedByEffect).isEqualTo(20f) + + assertThat(effect.applyToFlingDone).isFalse() + rule.onRoot().performTouchInput { up() } + assertThat(effect.applyToFlingDone).isTrue() + } + private fun ComposeContentTestRule.setContentWithTouchSlop( content: @Composable () -> Unit ): Float { @@ -481,6 +617,7 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw private val onDragStopped: suspend (Float) -> Float = { it }, private val shouldConsumeNestedScroll: (Float) -> Boolean = { true }, ) : NestedDraggable { + var shouldStartDrag = true var onDragStartedCalled = false var onDragCalled = false var onDragStoppedCalled = false @@ -490,6 +627,8 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw var onDragStartedPointersDown = 0 var onDragDelta = 0f + override fun shouldStartDrag(change: PointerInputChange): Boolean = shouldStartDrag + override fun onDragStarted( position: Offset, sign: Float, diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/TestOverscrollEffect.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/TestOverscrollEffect.kt new file mode 100644 index 000000000000..8bf9c21639f4 --- /dev/null +++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/TestOverscrollEffect.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.compose.gesture + +import androidx.compose.foundation.OverscrollEffect +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.input.nestedscroll.NestedScrollSource +import androidx.compose.ui.unit.Velocity + +class TestOverscrollEffect( + override val orientation: Orientation, + private val onPostFling: suspend (Float) -> Float = { it }, + private val onPostScroll: (Float) -> Float, +) : OverscrollEffect, OrientationAware { + override val isInProgress: Boolean = false + var applyToFlingDone = false + private set + + override fun applyToScroll( + delta: Offset, + source: NestedScrollSource, + performScroll: (Offset) -> Offset, + ): Offset { + val consumedByScroll = performScroll(delta) + val available = delta - consumedByScroll + val consumedByEffect = onPostScroll(available.toFloat()).toOffset() + return consumedByScroll + consumedByEffect + } + + override suspend fun applyToFling( + velocity: Velocity, + performFling: suspend (Velocity) -> Velocity, + ) { + val consumedByFling = performFling(velocity) + val available = velocity - consumedByFling + onPostFling(available.toFloat()) + applyToFlingDone = true + } +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt index beaf9631ae5a..9ab281217fbd 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt @@ -8,7 +8,6 @@ import androidx.compose.animation.core.rememberInfiniteTransition import androidx.compose.animation.core.tween import androidx.compose.foundation.background import androidx.compose.foundation.focusable -import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope @@ -128,9 +127,6 @@ val sceneTransitions = transitions { fade(Communal.Elements.Grid) } } - // Disable horizontal overscroll. If the scene is overscrolled too soon after showing, this - // can lead to inconsistent KeyguardState changes. - overscrollDisabled(CommunalScenes.Communal, Orientation.Horizontal) } /** @@ -205,7 +201,6 @@ fun CommunalContainer( colors = colors, content = content, viewModel = viewModel, - modifier = Modifier.horizontalNestedScrollToScene(), ) } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt index fab0ca318fbf..9bc334391ef9 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt @@ -76,6 +76,8 @@ import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.AutoSize +import androidx.compose.foundation.text.BasicText import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add @@ -1024,11 +1026,14 @@ private fun EmptyStateCta(contentPadding: PaddingValues, viewModel: BaseCommunal horizontalAlignment = Alignment.CenterHorizontally, ) { val titleForEmptyStateCTA = stringResource(R.string.title_for_empty_state_cta) - Text( + BasicText( text = titleForEmptyStateCTA, - style = MaterialTheme.typography.displaySmall, - textAlign = TextAlign.Center, - color = colors.onPrimary, + style = + MaterialTheme.typography.displaySmall.merge( + color = colors.onPrimary, + textAlign = TextAlign.Center, + ), + autoSize = AutoSize.StepBased(maxFontSize = 36.sp, stepSize = 0.1.sp), modifier = Modifier.focusable().semantics(mergeDescendants = true) { contentDescription = titleForEmptyStateCTA diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt index a88ad946d95b..88b651019c4a 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt @@ -66,7 +66,6 @@ constructor( colors = communalColors, content = communalContent, viewModel = contentViewModel, - modifier = modifier.horizontalNestedScrollToScene(), ) } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt index b54de784a202..957fdf7bcd8f 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt @@ -88,7 +88,6 @@ import com.android.compose.animation.scene.ContentKey import com.android.compose.animation.scene.ContentScope import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.LowestZIndexContentPicker -import com.android.compose.animation.scene.NestedScrollBehavior import com.android.compose.animation.scene.SceneTransitionLayoutState import com.android.compose.animation.scene.content.state.TransitionState import com.android.compose.modifiers.thenIf @@ -236,10 +235,7 @@ fun ContentScope.SnoozeableHeadsUpNotificationSpace( ) } .thenIf(isHeadsUp) { - Modifier.verticalNestedScrollToScene( - bottomBehavior = NestedScrollBehavior.EdgeAlways - ) - .nestedScroll(nestedScrollConnection) + Modifier.nestedScroll(nestedScrollConnection) .scrollable(orientation = Orientation.Vertical, state = scrollableState) }, ) @@ -571,11 +567,7 @@ fun ContentScope.NotificationScrollingStack( ) { Column( modifier = - Modifier.verticalNestedScrollToScene( - topBehavior = NestedScrollBehavior.EdgeWithPreview, - isExternalOverscrollGesture = { isCurrentGestureOverscroll.value }, - ) - .thenIf(supportNestedScrolling) { + Modifier.thenIf(supportNestedScrolling) { Modifier.nestedScroll(scrimNestedScrollConnection) } .stackVerticalOverscroll(coroutineScope) { scrollState.canScrollForward } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt index f6c5f588aa95..4a28d2862988 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt @@ -202,9 +202,7 @@ fun SceneScope.QuickSettingsLayout( ) Box( modifier = - Modifier.requiredHeightIn(max = GridMaxHeight) - .verticalNestedScrollToScene() - .verticalScroll(rememberScrollState()) + Modifier.requiredHeightIn(max = GridMaxHeight).verticalScroll(rememberScrollState()) ) { GridAnchor() TileGrid(viewModel = viewModel.tileGridViewModel, modifier = Modifier.fillMaxWidth()) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt index 8907aec7fd48..ee8535eff3ae 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt @@ -1,8 +1,6 @@ package com.android.systemui.scene.ui.composable import androidx.compose.animation.core.spring -import androidx.compose.foundation.gestures.Orientation -import com.android.compose.animation.scene.ProgressConverter import com.android.compose.animation.scene.TransitionKey import com.android.compose.animation.scene.transitions import com.android.systemui.notifications.ui.composable.Notifications @@ -50,7 +48,6 @@ val SceneContainerTransitions = transitions { interruptionHandler = SceneContainerInterruptionHandler // Overscroll progress starts linearly with some resistance (3f) and slowly approaches 0.2f - defaultOverscrollProgressConverter = ProgressConverter.tanh(maxProgress = 0.2f, tilt = 3f) defaultSwipeSpec = spring(stiffness = 300f, dampingRatio = 0.8f, visibilityThreshold = 0.5f) // Scene transitions @@ -126,13 +123,4 @@ val SceneContainerTransitions = transitions { from(Scenes.Lockscreen, to = Overlays.QuickSettingsShade, key = SlightlyFasterShadeCollapse) { toQuickSettingsShadeTransition(durationScale = 0.9) } - - // Scene overscroll - // TODO(b/382477212) Remove STL Overscroll DSL - overscrollDisabled(Scenes.Gone, Orientation.Vertical) - overscrollDisabled(Scenes.Lockscreen, Orientation.Vertical) - overscrollDisabled(Scenes.Bouncer, Orientation.Vertical) - overscrollDisabled(Scenes.Shade, Orientation.Vertical) - overscrollDisabled(Overlays.NotificationsShade, Orientation.Vertical) - overscrollDisabled(Overlays.QuickSettingsShade, Orientation.Vertical) } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt index 79fd1d7ddd8f..a53c6b29338f 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt @@ -65,7 +65,6 @@ import androidx.compose.ui.zIndex import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.LowestZIndexContentPicker -import com.android.compose.animation.scene.NestedScrollBehavior import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult @@ -400,10 +399,6 @@ private fun SceneScope.SingleShade( .height(navBarHeight) // Intercepts touches, prevents the scrollable container behind from scrolling. .clickable(interactionSource = null, indication = null) { /* do nothing */ } - .verticalNestedScrollToScene( - topBehavior = NestedScrollBehavior.EdgeAlways, - isExternalOverscrollGesture = { false }, - ) ) { NotificationStackCutoffGuideline( stackScrollView = notificationStackScrollView, diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt index a4237f36ab58..8777ff924bc1 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt @@ -418,15 +418,11 @@ private class AnimatedStateImpl<T, Delta>( return fromValue } - val overscrollSpec = transition.currentOverscrollSpec val progress = - when { - overscrollSpec == null -> { - if (canOverflow) transition.progress - else transition.progress.fastCoerceIn(0f, 1f) - } - overscrollSpec.content == transition.toContent -> 1f - else -> 0f + if (canOverflow) { + transition.progress + } else { + transition.progress.fastCoerceIn(0f, 1f) } return sharedValue.type.lerp(fromValue, toValue, progress) diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt index 141736f46ee4..6bb579d18bf9 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt @@ -23,7 +23,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.round import androidx.compose.ui.util.fastCoerceIn import com.android.compose.animation.scene.content.Content -import com.android.compose.animation.scene.content.state.TransitionState.DirectionProperties.Companion.DistanceUnspecified +import com.android.compose.animation.scene.content.state.TransitionState.Companion.DistanceUnspecified import com.android.compose.nestedscroll.OnStopScope import com.android.compose.nestedscroll.PriorityNestedScrollConnection import com.android.compose.nestedscroll.ScrollController @@ -77,8 +77,6 @@ internal class DraggableHandlerImpl( internal val layoutImpl: SceneTransitionLayoutImpl, internal val orientation: Orientation, ) : DraggableHandler { - internal val nestedScrollKey = Any() - /** The [DraggableHandler] can only have one active [DragController] at a time. */ private var dragController: DragControllerImpl? = null @@ -464,41 +462,20 @@ internal class Swipes(val upOrLeft: Swipe.Resolved, val downOrRight: Swipe.Resol internal class NestedScrollHandlerImpl( private val draggableHandler: DraggableHandlerImpl, - internal var topOrLeftBehavior: NestedScrollBehavior, - internal var bottomOrRightBehavior: NestedScrollBehavior, - internal var isExternalOverscrollGesture: () -> Boolean, private val pointersInfoOwner: PointersInfoOwner, ) { val connection: PriorityNestedScrollConnection = nestedScrollConnection() private fun nestedScrollConnection(): PriorityNestedScrollConnection { - // If we performed a long gesture before entering priority mode, we would have to avoid - // moving on to the next scene. - var canChangeScene = false - var lastPointersDown: PointersInfo.PointersDown? = null - fun shouldEnableSwipes(): Boolean { - return draggableHandler.layoutImpl - .contentForUserActions() - .shouldEnableSwipes(draggableHandler.orientation) - } - return PriorityNestedScrollConnection( orientation = draggableHandler.orientation, canStartPreScroll = { _, _, _ -> false }, - canStartPostScroll = { offsetAvailable, offsetBeforeStart, _ -> - val behavior: NestedScrollBehavior = - when { - offsetAvailable > 0f -> topOrLeftBehavior - offsetAvailable < 0f -> bottomOrRightBehavior - else -> return@PriorityNestedScrollConnection false - } - - val isZeroOffset = - if (isExternalOverscrollGesture()) false else offsetBeforeStart == 0f + canStartPostScroll = { offsetAvailable, _, _ -> + if (offsetAvailable == 0f) return@PriorityNestedScrollConnection false - val pointersDown: PointersInfo.PointersDown? = + lastPointersDown = when (val info = pointersInfoOwner.pointersInfo()) { PointersInfo.MouseWheel -> { // Do not support mouse wheel interactions @@ -508,24 +485,10 @@ internal class NestedScrollHandlerImpl( is PointersInfo.PointersDown -> info null -> null } - lastPointersDown = pointersDown - when (behavior) { - NestedScrollBehavior.EdgeNoPreview -> { - canChangeScene = isZeroOffset - isZeroOffset && shouldEnableSwipes() - } - - NestedScrollBehavior.EdgeWithPreview -> { - canChangeScene = isZeroOffset - shouldEnableSwipes() - } - - NestedScrollBehavior.EdgeAlways -> { - canChangeScene = true - shouldEnableSwipes() - } - } + draggableHandler.layoutImpl + .contentForUserActions() + .shouldEnableSwipes(draggableHandler.orientation) }, onStart = { firstScroll -> scrollController( @@ -534,7 +497,6 @@ internal class NestedScrollHandlerImpl( pointersDown = lastPointersDown, overSlop = firstScroll, ), - canChangeScene = canChangeScene, pointersInfoOwner = pointersInfoOwner, ) }, @@ -544,7 +506,6 @@ internal class NestedScrollHandlerImpl( private fun scrollController( dragController: DragController, - canChangeScene: Boolean, pointersInfoOwner: PointersInfoOwner, ): ScrollController { return object : ScrollController { @@ -558,14 +519,11 @@ private fun scrollController( } override suspend fun OnStopScope.onStop(initialVelocity: Float): Float { - return dragController.onStop( - velocity = initialVelocity, - canChangeContent = canChangeScene, - ) + return dragController.onStop(velocity = initialVelocity, canChangeContent = true) } override fun onCancel() { - dragController.onCancel(canChangeScene) + dragController.onCancel(canChangeContent = true) } /** diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt index 07a19d83c995..16b4322411ac 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt @@ -388,32 +388,6 @@ internal class ElementNode( val transition = elementState as? TransitionState.Transition - // If this element is not supposed to be laid out now, either because it is not part of any - // ongoing transition or the other content of its transition is overscrolling, then lay out - // the element normally and don't place it. - val overscrollContent = transition?.currentOverscrollSpec?.content - if (overscrollContent != null && overscrollContent != content.key) { - when (transition) { - is TransitionState.Transition.ChangeScene -> - return doNotPlace(measurable, constraints) - - // If we are overscrolling an overlay that does not contain an element that is in - // the current scene, place it in that scene otherwise the element won't be placed - // at all. - is TransitionState.Transition.ShowOrHideOverlay, - is TransitionState.Transition.ReplaceOverlay -> { - if ( - content.key == transition.currentScene && - overscrollContent !in element.stateByContent - ) { - return placeNormally(measurable, constraints) - } else { - return doNotPlace(measurable, constraints) - } - } - } - } - val placeable = measure(layoutImpl, element, transition, stateInContent, measurable, constraints) stateInContent.lastSize = placeable.size() @@ -1257,53 +1231,6 @@ private inline fun <T> computeValue( } val currentContent = currentContentState.content - if (transition is TransitionState.DirectionProperties) { - val overscroll = transition.currentOverscrollSpec - if (overscroll?.content == currentContent) { - val elementSpec = - overscroll.transformationSpec.transformations(element.key, currentContent) - val propertySpec = transformation(elementSpec) ?: return currentValue() - val overscrollState = - checkNotNull(if (currentContent == toContent) toState else fromState) - val idleValue = contentValue(overscrollState) - val targetValue = - with( - propertySpec.transformation.requireInterpolatedTransformation( - element, - transition, - ) { - "Custom transformations in overscroll specs should not be possible" - } - ) { - layoutImpl.propertyTransformationScope.transform( - currentContent, - element.key, - transition, - idleValue, - ) - } - - // Make sure we don't read progress if values are the same and we don't need to - // interpolate, so we don't invalidate the phase where this is read. - if (targetValue == idleValue) { - return targetValue - } - - // TODO(b/290184746): Make sure that we don't overflow transformations associated to a - // range. - val directionSign = if (transition.isUpOrLeft) -1 else 1 - val isToContent = overscroll.content == transition.toContent - val linearProgress = transition.progress.let { if (isToContent) it - 1f else it } - val progressConverter = - overscroll.progressConverter - ?: layoutImpl.state.transitions.defaultProgressConverter - val progress = directionSign * progressConverter.convert(linearProgress) - val rangeProgress = propertySpec.range?.progress(progress) ?: progress - - // Interpolate between the value at rest and the over scrolled value. - return lerp(idleValue, targetValue, rangeProgress) - } - } // The element is shared: interpolate between the value in fromContent and the value in // toContent. diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt index 17510c732e65..388456e8893a 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt @@ -196,13 +196,7 @@ private fun shouldComposeMovableElement( is TransitionState.Transition -> { // During transitions, always compose movable elements in the scene picked by their // content picker. - shouldComposeMoveableElement( - layoutImpl, - content, - element, - elementState, - element.contentPicker.contents, - ) + shouldComposeMoveableElement(layoutImpl, content, element, elementState) } } } @@ -212,26 +206,7 @@ private fun shouldComposeMoveableElement( content: ContentKey, elementKey: ElementKey, transition: TransitionState.Transition, - containingContents: Set<ContentKey>, ): Boolean { - val overscrollContent = transition.currentOverscrollSpec?.content - if (overscrollContent != null) { - return when (transition) { - // If we are overscrolling between scenes, only place/compose the element in the - // overscrolling scene. - is TransitionState.Transition.ChangeScene -> content == overscrollContent - - // If we are overscrolling an overlay, place/compose the element if [content] is the - // overscrolling content or if [content] is the current scene and the overscrolling - // overlay does not contain the element. - is TransitionState.Transition.ReplaceOverlay, - is TransitionState.Transition.ShowOrHideOverlay -> - content == overscrollContent || - (content == transition.currentScene && - !containingContents.contains(overscrollContent)) - } - } - val scenePicker = elementKey.contentPicker val pickedScene = scenePicker.contentDuringTransition( diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt deleted file mode 100644 index 9622fc151bb7..000000000000 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt +++ /dev/null @@ -1,178 +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.compose.animation.scene - -import androidx.compose.ui.Modifier -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.input.nestedscroll.NestedScrollConnection -import androidx.compose.ui.input.nestedscroll.NestedScrollSource -import androidx.compose.ui.input.nestedscroll.nestedScrollModifierNode -import androidx.compose.ui.node.DelegatingNode -import androidx.compose.ui.node.ModifierNodeElement -import androidx.compose.ui.platform.InspectorInfo - -/** - * Defines the behavior of the [SceneTransitionLayout] when a scrollable component is scrolled. - * - * By default, scrollable elements within the scene have priority during the user's gesture and are - * not consumed by the [SceneTransitionLayout] unless specifically requested via - * [nestedScrollToScene]. - */ -enum class NestedScrollBehavior { - /** - * Overscroll will only be used by the [SceneTransitionLayout] to move to the next scene if the - * gesture begins at the edge of the scrollable component (so that a scroll in that direction - * can no longer be consumed). If the gesture is partially consumed by the scrollable component, - * there will be NO preview of the next scene. - * - * In addition, during scene transitions, scroll events are consumed by the - * [SceneTransitionLayout] instead of the scrollable component. - */ - EdgeNoPreview, - - /** - * Overscroll will only be used by the [SceneTransitionLayout] to move to the next scene if the - * gesture begins at the edge of the scrollable component. If the gesture is partially consumed - * by the scrollable component, there will be a preview of the next scene. - * - * In addition, during scene transitions, scroll events are consumed by the - * [SceneTransitionLayout] instead of the scrollable component. - */ - @Deprecated("This will be removed, see b/378470603") EdgeWithPreview, - - /** - * Any overscroll will be used by the [SceneTransitionLayout] to move to the next scene. - * - * In addition, during scene transitions, scroll events are consumed by the - * [SceneTransitionLayout] instead of the scrollable component. - */ - EdgeAlways; - - companion object { - val Default = EdgeNoPreview - } -} - -internal fun Modifier.nestedScrollToScene( - draggableHandler: DraggableHandlerImpl, - topOrLeftBehavior: NestedScrollBehavior, - bottomOrRightBehavior: NestedScrollBehavior, - isExternalOverscrollGesture: () -> Boolean, -) = - this then - NestedScrollToSceneElement( - draggableHandler = draggableHandler, - topOrLeftBehavior = topOrLeftBehavior, - bottomOrRightBehavior = bottomOrRightBehavior, - isExternalOverscrollGesture = isExternalOverscrollGesture, - ) - -private data class NestedScrollToSceneElement( - private val draggableHandler: DraggableHandlerImpl, - private val topOrLeftBehavior: NestedScrollBehavior, - private val bottomOrRightBehavior: NestedScrollBehavior, - private val isExternalOverscrollGesture: () -> Boolean, -) : ModifierNodeElement<NestedScrollToSceneNode>() { - override fun create() = - NestedScrollToSceneNode( - draggableHandler = draggableHandler, - topOrLeftBehavior = topOrLeftBehavior, - bottomOrRightBehavior = bottomOrRightBehavior, - isExternalOverscrollGesture = isExternalOverscrollGesture, - ) - - override fun update(node: NestedScrollToSceneNode) { - node.update( - draggableHandler = draggableHandler, - topOrLeftBehavior = topOrLeftBehavior, - bottomOrRightBehavior = bottomOrRightBehavior, - isExternalOverscrollGesture = isExternalOverscrollGesture, - ) - } - - override fun InspectorInfo.inspectableProperties() { - name = "nestedScrollToScene" - properties["draggableHandler"] = draggableHandler - properties["topOrLeftBehavior"] = topOrLeftBehavior - properties["bottomOrRightBehavior"] = bottomOrRightBehavior - } -} - -private class NestedScrollToSceneNode( - private var draggableHandler: DraggableHandlerImpl, - private var topOrLeftBehavior: NestedScrollBehavior, - private var bottomOrRightBehavior: NestedScrollBehavior, - private var isExternalOverscrollGesture: () -> Boolean, -) : DelegatingNode() { - private var scrollBehaviorOwner: ScrollBehaviorOwner? = null - - private fun findScrollBehaviorOwner(): ScrollBehaviorOwner? { - return scrollBehaviorOwner - ?: findScrollBehaviorOwner(draggableHandler).also { scrollBehaviorOwner = it } - } - - private val updateScrollBehaviorsConnection = - object : NestedScrollConnection { - /** - * When using [NestedScrollConnection.onPostScroll], we can specify the desired behavior - * before our parent components. This gives them the option to override our behavior if - * they choose. - * - * The behavior can be communicated at every scroll gesture to ensure that the hierarchy - * is respected, even if one of our descendant nodes changes behavior after we set it. - */ - override fun onPostScroll( - consumed: Offset, - available: Offset, - source: NestedScrollSource, - ): Offset { - // If we have some remaining scroll, that scroll can be used to initiate a - // transition between scenes. We can assume that the behavior is only needed if - // there is some remaining amount. - if (available != Offset.Zero) { - findScrollBehaviorOwner() - ?.updateScrollBehaviors( - topOrLeftBehavior = topOrLeftBehavior, - bottomOrRightBehavior = bottomOrRightBehavior, - isExternalOverscrollGesture = isExternalOverscrollGesture, - ) - } - - return Offset.Zero - } - } - - init { - delegate(nestedScrollModifierNode(updateScrollBehaviorsConnection, dispatcher = null)) - } - - override fun onDetach() { - scrollBehaviorOwner = null - } - - fun update( - draggableHandler: DraggableHandlerImpl, - topOrLeftBehavior: NestedScrollBehavior, - bottomOrRightBehavior: NestedScrollBehavior, - isExternalOverscrollGesture: () -> Boolean, - ) { - this.draggableHandler = draggableHandler - this.topOrLeftBehavior = topOrLeftBehavior - this.bottomOrRightBehavior = bottomOrRightBehavior - this.isExternalOverscrollGesture = isExternalOverscrollGesture - } -} diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt index bf7e8e823658..ce385abea627 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt @@ -26,7 +26,6 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.pointer.PointerType import androidx.compose.ui.layout.LookaheadScope import androidx.compose.ui.platform.LocalDensity @@ -233,32 +232,6 @@ interface BaseContentScope : ElementStateScope { ) /** - * Adds a [NestedScrollConnection] to intercept scroll events not handled by the scrollable - * component. - * - * @param leftBehavior when we should perform the overscroll animation at the left. - * @param rightBehavior when we should perform the overscroll animation at the right. - */ - fun Modifier.horizontalNestedScrollToScene( - leftBehavior: NestedScrollBehavior = NestedScrollBehavior.Default, - rightBehavior: NestedScrollBehavior = NestedScrollBehavior.Default, - isExternalOverscrollGesture: () -> Boolean = { false }, - ): Modifier - - /** - * Adds a [NestedScrollConnection] to intercept scroll events not handled by the scrollable - * component. - * - * @param topBehavior when we should perform the overscroll animation at the top. - * @param bottomBehavior when we should perform the overscroll animation at the bottom. - */ - fun Modifier.verticalNestedScrollToScene( - topBehavior: NestedScrollBehavior = NestedScrollBehavior.Default, - bottomBehavior: NestedScrollBehavior = NestedScrollBehavior.Default, - isExternalOverscrollGesture: () -> Boolean = { false }, - ): Modifier - - /** * Don't resize during transitions. This can for instance be used to make sure that scrollable * lists keep a constant size during transitions even if its elements are growing/shrinking. */ diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt index d7bac147d8f2..e1cecc750d3d 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt @@ -558,15 +558,7 @@ private class LayoutNode(var layoutImpl: SceneTransitionLayoutImpl) : width = fromSize.width height = fromSize.height } else { - val overscrollSpec = transition.currentOverscrollSpec - val progress = - when { - overscrollSpec == null -> transition.progress - overscrollSpec.content == transition.toScene -> 1f - else -> 0f - } - - val size = lerp(fromSize, toSize, progress) + val size = lerp(fromSize, toSize, transition.progress) width = size.width.coerceAtLeast(0) height = size.height.coerceAtLeast(0) } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt index e8b2b09da377..568a358e4a7e 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt @@ -382,7 +382,6 @@ internal class MutableSceneTransitionLayoutStateImpl( // Compute the [TransformationSpec] when the transition starts. val fromContent = transition.fromContent val toContent = transition.toContent - val orientation = (transition as? TransitionState.DirectionProperties)?.orientation // Update the transition specs. transition.transformationSpec = @@ -393,14 +392,6 @@ internal class MutableSceneTransitionLayoutStateImpl( transitions .transitionSpec(fromContent, toContent, key = transition.key) .previewTransformationSpec(transition) - if (orientation != null) { - transition.updateOverscrollSpecs( - fromSpec = transitions.overscrollSpec(fromContent, orientation), - toSpec = transitions.overscrollSpec(toContent, orientation), - ) - } else { - transition.updateOverscrollSpecs(fromSpec = null, toSpec = null) - } } private fun startTransitionInternal(transition: TransitionState.Transition, chain: Boolean) { diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt index 8df3f2d932b3..6479e69a2aac 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt @@ -21,7 +21,6 @@ import androidx.compose.animation.core.Spring import androidx.compose.animation.core.SpringSpec import androidx.compose.animation.core.snap import androidx.compose.animation.core.spring -import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.IntSize import androidx.compose.ui.util.fastForEach @@ -36,9 +35,7 @@ class SceneTransitions internal constructor( internal val defaultSwipeSpec: SpringSpec<Float>, internal val transitionSpecs: List<TransitionSpecImpl>, - internal val overscrollSpecs: List<OverscrollSpecImpl>, internal val interruptionHandler: InterruptionHandler, - internal val defaultProgressConverter: ProgressConverter, ) { private val transitionCache = mutableMapOf< @@ -46,9 +43,6 @@ internal constructor( MutableMap<ContentKey, MutableMap<TransitionKey?, TransitionSpecImpl>>, >() - private val overscrollCache = - mutableMapOf<ContentKey, MutableMap<Orientation, OverscrollSpecImpl?>>() - internal fun transitionSpec( from: ContentKey, to: ContentKey, @@ -119,28 +113,6 @@ internal constructor( private fun defaultTransition(from: ContentKey, to: ContentKey) = TransitionSpecImpl(key = null, from, to, null, null, TransformationSpec.EmptyProvider) - internal fun overscrollSpec(scene: ContentKey, orientation: Orientation): OverscrollSpecImpl? = - overscrollCache - .getOrPut(scene) { mutableMapOf() } - .getOrPut(orientation) { overscroll(scene, orientation) { it.content == scene } } - - private fun overscroll( - scene: ContentKey, - orientation: Orientation, - filter: (OverscrollSpecImpl) -> Boolean, - ): OverscrollSpecImpl? { - var match: OverscrollSpecImpl? = null - overscrollSpecs.fastForEach { spec -> - if (spec.orientation == orientation && filter(spec)) { - if (match != null) { - error("Found multiple overscroll specs for overscroll $scene") - } - match = spec - } - } - return match - } - companion object { internal val DefaultSwipeSpec = spring( @@ -153,9 +125,7 @@ internal constructor( SceneTransitions( defaultSwipeSpec = DefaultSwipeSpec, transitionSpecs = emptyList(), - overscrollSpecs = emptyList(), interruptionHandler = DefaultInterruptionHandler, - defaultProgressConverter = ProgressConverter.Default, ) } } @@ -286,36 +256,6 @@ internal class TransitionSpecImpl( ): TransformationSpecImpl? = previewTransformationSpec?.invoke(transition) } -/** The definition of the overscroll behavior of the [content]. */ -internal interface OverscrollSpec { - /** The scene we are over scrolling. */ - val content: ContentKey - - /** The orientation of this [OverscrollSpec]. */ - val orientation: Orientation - - /** The [TransformationSpec] associated to this [OverscrollSpec]. */ - val transformationSpec: TransformationSpec - - /** - * Function that takes a linear overscroll progress value ranging from 0 to +/- infinity and - * outputs the desired **overscroll progress value**. - * - * When the progress value is: - * - 0, the user is not overscrolling. - * - 1, the user overscrolled by exactly the [OverscrollBuilder.distance]. - * - Greater than 1, the user overscrolled more than the [OverscrollBuilder.distance]. - */ - val progressConverter: ProgressConverter? -} - -internal class OverscrollSpecImpl( - override val content: ContentKey, - override val orientation: Orientation, - override val transformationSpec: TransformationSpecImpl, - override val progressConverter: ProgressConverter?, -) : OverscrollSpec - /** * An implementation of [TransformationSpec] that allows the quick retrieval of an element * [ElementTransformations]. diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt index 167928b38e90..9de297f3ad5a 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt @@ -56,24 +56,6 @@ internal fun shouldPlaceSharedElement( return element.shouldBeRenderedBy(content) } - val overscrollContent = transition.currentOverscrollSpec?.content - if (overscrollContent != null) { - return when (transition) { - // If we are overscrolling between scenes, only place/compose the element in the - // overscrolling scene. - is TransitionState.Transition.ChangeScene -> content == overscrollContent - - // If we are overscrolling an overlay, place/compose the element if [content] is the - // overscrolling content or if [content] is the current scene and the overscrolling - // overlay does not contain the element. - is TransitionState.Transition.ReplaceOverlay, - is TransitionState.Transition.ShowOrHideOverlay -> - content == overscrollContent || - (content == transition.currentScene && - overscrollContent !in element.stateByContent) - } - } - val scenePicker = elementKey.contentPicker val pickedScene = scenePicker.contentDuringTransition( diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt index 47daa76b61d0..607e4fadc256 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt @@ -25,7 +25,7 @@ import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import com.android.compose.animation.scene.content.state.TransitionState -import com.android.compose.animation.scene.content.state.TransitionState.DirectionProperties.Companion.DistanceUnspecified +import com.android.compose.animation.scene.content.state.TransitionState.Companion.DistanceUnspecified import kotlin.math.absoluteValue import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.launch @@ -116,7 +116,6 @@ private fun createSwipeAnimation( val fromScene = layoutState.currentScene val toScene = result.toScene ChangeSceneSwipeTransition( - layoutState = layoutState, swipeAnimation = swipeAnimation(fromContent = fromScene, toContent = toScene), key = result.transitionKey, replacedTransition = null, @@ -127,10 +126,9 @@ private fun createSwipeAnimation( val fromScene = layoutState.currentScene val overlay = result.overlay ShowOrHideOverlaySwipeTransition( - layoutState = layoutState, - fromOrToScene = fromScene, - overlay = overlay, swipeAnimation = swipeAnimation(fromContent = fromScene, toContent = overlay), + overlay = overlay, + fromOrToScene = fromScene, key = result.transitionKey, replacedTransition = null, ) @@ -140,10 +138,9 @@ private fun createSwipeAnimation( val toScene = layoutState.currentScene val overlay = result.overlay ShowOrHideOverlaySwipeTransition( - layoutState = layoutState, - fromOrToScene = toScene, - overlay = overlay, swipeAnimation = swipeAnimation(fromContent = overlay, toContent = toScene), + overlay = overlay, + fromOrToScene = toScene, key = result.transitionKey, replacedTransition = null, ) @@ -159,7 +156,6 @@ private fun createSwipeAnimation( val toOverlay = result.overlay ReplaceOverlaySwipeTransition( - layoutState = layoutState, swipeAnimation = swipeAnimation(fromContent = fromOverlay, toContent = toOverlay), key = result.transitionKey, @@ -170,34 +166,18 @@ private fun createSwipeAnimation( } } -internal fun createSwipeAnimation(old: SwipeAnimation<*>): SwipeAnimation<*> { - return when (val transition = old.contentTransition) { - is TransitionState.Transition.ChangeScene -> { - ChangeSceneSwipeTransition(transition as ChangeSceneSwipeTransition).swipeAnimation - } - is TransitionState.Transition.ShowOrHideOverlay -> { - ShowOrHideOverlaySwipeTransition(transition as ShowOrHideOverlaySwipeTransition) - .swipeAnimation - } - is TransitionState.Transition.ReplaceOverlay -> { - ReplaceOverlaySwipeTransition(transition as ReplaceOverlaySwipeTransition) - .swipeAnimation - } - } -} - /** A helper class that contains the main logic for swipe transitions. */ internal class SwipeAnimation<T : ContentKey>( val layoutState: MutableSceneTransitionLayoutStateImpl, val fromContent: T, val toContent: T, - override val orientation: Orientation, - override val isUpOrLeft: Boolean, + val orientation: Orientation, + val isUpOrLeft: Boolean, val requiresFullDistanceSwipe: Boolean, private val distance: (SwipeAnimation<T>) -> Float, currentContent: T = fromContent, dragOffset: Float = 0f, -) : TransitionState.DirectionProperties { +) { /** The [TransitionState.Transition] whose implementation delegates to this [SwipeAnimation]. */ lateinit var contentTransition: TransitionState.Transition @@ -264,8 +244,6 @@ internal class SwipeAnimation<T : ContentKey>( val isInPreviewStage: Boolean get() = contentTransition.previewTransformationSpec != null && currentContent == fromContent - override var bouncingContent: ContentKey? = null - /** The current offset caused by the drag gesture. */ var dragOffset by mutableFloatStateOf(dragOffset) @@ -276,23 +254,6 @@ internal class SwipeAnimation<T : ContentKey>( val isUserInputOngoing: Boolean get() = offsetAnimation == null - override val absoluteDistance: Float - get() = distance().absoluteValue - - constructor( - other: SwipeAnimation<T> - ) : this( - layoutState = other.layoutState, - fromContent = other.fromContent, - toContent = other.toContent, - orientation = other.orientation, - isUpOrLeft = other.isUpOrLeft, - requiresFullDistanceSwipe = other.requiresFullDistanceSwipe, - distance = other.distance, - currentContent = other.currentContent, - dragOffset = other.offsetAnimation?.value ?: other.dragOffset, - ) - suspend fun run() { // This animation will first be driven by finger, then when the user lift their finger we // start an animation to the target offset (progress = 1f or progress = 0f). We await() for @@ -401,10 +362,6 @@ internal class SwipeAnimation<T : ContentKey>( return 0f } - val isTargetGreater = targetOffset > animatable.value - val startedWhenOvercrollingTargetContent = - if (targetContent == fromContent) initialProgress < 0f else initialProgress > 1f - val swipeSpec = spec ?: contentTransition.transformationSpec.swipeSpec @@ -419,34 +376,13 @@ internal class SwipeAnimation<T : ContentKey>( animationSpec = swipeSpec, initialVelocity = initialVelocity, ) { - if (bouncingContent == null) { - val isBouncing = - if (isTargetGreater) { - if (startedWhenOvercrollingTargetContent) { - value >= targetOffset - } else { - value > targetOffset - } - } else { - if (startedWhenOvercrollingTargetContent) { - value <= targetOffset - } else { - value < targetOffset - } - } - - if (isBouncing) { - bouncingContent = targetContent - - // Immediately stop this transition if we are bouncing on a content that - // does not bounce. - if (!contentTransition.isWithinProgressRange(progress)) { - // We are no longer able to consume the velocity, the rest can be - // consumed by another component in the hierarchy. - velocityConsumed.complete(initialVelocity - velocity) - throw SnapException() - } - } + // Immediately stop this transition if we are bouncing on a content that + // does not bounce. + if (!contentTransition.isWithinProgressRange(progress)) { + // We are no longer able to consume the velocity, the rest can be + // consumed by another component in the hierarchy. + velocityConsumed.complete(initialVelocity - velocity) + throw SnapException() } } } catch (_: SnapException) { @@ -514,7 +450,6 @@ private object DefaultSwipeDistance : UserActionDistance { } private class ChangeSceneSwipeTransition( - val layoutState: MutableSceneTransitionLayoutStateImpl, val swipeAnimation: SwipeAnimation<SceneKey>, override val key: TransitionKey?, replacedTransition: ChangeSceneSwipeTransition?, @@ -523,17 +458,7 @@ private class ChangeSceneSwipeTransition( swipeAnimation.fromContent, swipeAnimation.toContent, replacedTransition, - ), - TransitionState.DirectionProperties by swipeAnimation { - - constructor( - other: ChangeSceneSwipeTransition - ) : this( - layoutState = other.layoutState, - swipeAnimation = SwipeAnimation(other.swipeAnimation), - key = other.key, - replacedTransition = other, - ) + ) { init { swipeAnimation.contentTransition = this @@ -572,7 +497,6 @@ private class ChangeSceneSwipeTransition( } private class ShowOrHideOverlaySwipeTransition( - val layoutState: MutableSceneTransitionLayoutStateImpl, val swipeAnimation: SwipeAnimation<ContentKey>, overlay: OverlayKey, fromOrToScene: SceneKey, @@ -585,18 +509,7 @@ private class ShowOrHideOverlaySwipeTransition( swipeAnimation.fromContent, swipeAnimation.toContent, replacedTransition, - ), - TransitionState.DirectionProperties by swipeAnimation { - constructor( - other: ShowOrHideOverlaySwipeTransition - ) : this( - layoutState = other.layoutState, - swipeAnimation = SwipeAnimation(other.swipeAnimation), - overlay = other.overlay, - fromOrToScene = other.fromOrToScene, - key = other.key, - replacedTransition = other, - ) + ) { init { swipeAnimation.contentTransition = this @@ -635,7 +548,6 @@ private class ShowOrHideOverlaySwipeTransition( } private class ReplaceOverlaySwipeTransition( - val layoutState: MutableSceneTransitionLayoutStateImpl, val swipeAnimation: SwipeAnimation<OverlayKey>, override val key: TransitionKey?, replacedTransition: ReplaceOverlaySwipeTransition?, @@ -644,16 +556,7 @@ private class ReplaceOverlaySwipeTransition( swipeAnimation.fromContent, swipeAnimation.toContent, replacedTransition, - ), - TransitionState.DirectionProperties by swipeAnimation { - constructor( - other: ReplaceOverlaySwipeTransition - ) : this( - layoutState = other.layoutState, - swipeAnimation = SwipeAnimation(other.swipeAnimation), - key = other.key, - replacedTransition = other, - ) + ) { init { swipeAnimation.contentTransition = this diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt index 6ef8b86cf72a..c5b3df222855 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt @@ -23,12 +23,9 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollDispatcher import androidx.compose.ui.input.nestedscroll.nestedScrollModifierNode import androidx.compose.ui.input.pointer.PointerEvent import androidx.compose.ui.input.pointer.PointerEventPass -import androidx.compose.ui.node.DelegatableNode import androidx.compose.ui.node.DelegatingNode import androidx.compose.ui.node.ModifierNodeElement import androidx.compose.ui.node.PointerInputModifierNode -import androidx.compose.ui.node.TraversableNode -import androidx.compose.ui.node.findNearestAncestor import androidx.compose.ui.unit.IntSize import com.android.compose.animation.scene.content.Content @@ -165,15 +162,11 @@ private class SwipeToSceneNode( private val nestedScrollHandlerImpl = NestedScrollHandlerImpl( draggableHandler = draggableHandler, - topOrLeftBehavior = NestedScrollBehavior.Default, - bottomOrRightBehavior = NestedScrollBehavior.Default, - isExternalOverscrollGesture = { false }, pointersInfoOwner = { multiPointerDraggableNode.pointersInfo() }, ) init { delegate(nestedScrollModifierNode(nestedScrollHandlerImpl.connection, dispatcher)) - delegate(ScrollBehaviorOwnerNode(draggableHandler.nestedScrollKey, nestedScrollHandlerImpl)) } private fun onFirstPointerDown() { @@ -198,40 +191,3 @@ private class SwipeToSceneNode( override fun onCancelPointerInput() = multiPointerDraggableNode.onCancelPointerInput() } - -/** Find the [ScrollBehaviorOwner] for the current orientation. */ -internal fun DelegatableNode.findScrollBehaviorOwner( - draggableHandler: DraggableHandlerImpl -): ScrollBehaviorOwner? { - // If there are no scenes in a particular orientation, the corresponding ScrollBehaviorOwnerNode - // is removed from the composition. - return findNearestAncestor(draggableHandler.nestedScrollKey) as? ScrollBehaviorOwner -} - -internal fun interface ScrollBehaviorOwner { - fun updateScrollBehaviors( - topOrLeftBehavior: NestedScrollBehavior, - bottomOrRightBehavior: NestedScrollBehavior, - isExternalOverscrollGesture: () -> Boolean, - ) -} - -/** - * We need a node that receives the desired behavior. - * - * TODO(b/353234530) move this logic into [SwipeToSceneNode] - */ -private class ScrollBehaviorOwnerNode( - override val traverseKey: Any, - val nestedScrollHandlerImpl: NestedScrollHandlerImpl, -) : Modifier.Node(), TraversableNode, ScrollBehaviorOwner { - override fun updateScrollBehaviors( - topOrLeftBehavior: NestedScrollBehavior, - bottomOrRightBehavior: NestedScrollBehavior, - isExternalOverscrollGesture: () -> Boolean, - ) { - nestedScrollHandlerImpl.topOrLeftBehavior = topOrLeftBehavior - nestedScrollHandlerImpl.bottomOrRightBehavior = bottomOrRightBehavior - nestedScrollHandlerImpl.isExternalOverscrollGesture = isExternalOverscrollGesture - } -} diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt index 952668ab49ff..8794df0cf884 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt @@ -20,9 +20,7 @@ import androidx.compose.animation.core.AnimationSpec import androidx.compose.animation.core.Easing import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.SpringSpec -import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.android.compose.animation.scene.content.state.TransitionState @@ -51,12 +49,6 @@ interface SceneTransitionsBuilder { var interruptionHandler: InterruptionHandler /** - * Default [ProgressConverter] used during overscroll. It lets you change a linear progress into - * a function of your choice. Defaults to [ProgressConverter.Default]. - */ - var defaultOverscrollProgressConverter: ProgressConverter - - /** * Define the default animation to be played when transitioning [to] the specified content, from * any content. For the animation specification to apply only when transitioning between two * specific contents, use [from] instead. @@ -103,28 +95,6 @@ interface SceneTransitionsBuilder { reversePreview: (TransitionBuilder.() -> Unit)? = null, builder: TransitionBuilder.() -> Unit = {}, ) - - /** - * Define the animation to be played when the [content] is overscrolled in the given - * [orientation]. - * - * The overscroll animation always starts from a progress of 0f, and reaches 1f when moving the - * [distance] down/right, -1f when moving in the opposite direction. - */ - @Deprecated( - "Use verticalOverscrollEffect (or horizontalOverscrollEffect) directly from SceneScope." - ) - fun overscroll( - content: ContentKey, - orientation: Orientation, - builder: OverscrollBuilder.() -> Unit, - ) - - /** - * Prevents overscroll the [content] in the given [orientation], allowing ancestors to - * eventually consume the remaining gesture. - */ - fun overscrollDisabled(content: ContentKey, orientation: Orientation) } interface BaseTransitionBuilder : PropertyTransformationBuilder { @@ -228,35 +198,6 @@ interface TransitionBuilder : BaseTransitionBuilder { fun reversed(builder: TransitionBuilder.() -> Unit) } -@TransitionDsl -interface OverscrollBuilder : BaseTransitionBuilder { - /** - * Function that takes a linear overscroll progress value ranging from 0 to +/- infinity and - * outputs the desired **overscroll progress value**. - * - * When the progress value is: - * - 0, the user is not overscrolling. - * - 1, the user overscrolled by exactly the [distance]. - * - Greater than 1, the user overscrolled more than the [distance]. - */ - var progressConverter: ProgressConverter? - - /** Translate the element(s) matching [matcher] by ([x], [y]) pixels. */ - fun translate( - matcher: ElementMatcher, - x: OverscrollScope.() -> Float = { 0f }, - y: OverscrollScope.() -> Float = { 0f }, - ) -} - -interface OverscrollScope : Density { - /** - * Return the absolute distance between fromScene and toScene, if available, otherwise - * [DistanceUnspecified]. - */ - val absoluteDistance: Float -} - /** * An interface to decide where we should draw shared Elements or compose MovableElements. * diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt index 6742b3200ac4..a1649964ec13 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt @@ -22,9 +22,7 @@ import androidx.compose.animation.core.Easing import androidx.compose.animation.core.Spring import androidx.compose.animation.core.SpringSpec import androidx.compose.animation.core.VectorConverter -import androidx.compose.animation.core.snap import androidx.compose.animation.core.spring -import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.Dp import com.android.compose.animation.scene.content.state.TransitionState @@ -33,7 +31,6 @@ import com.android.compose.animation.scene.transformation.AnchoredTranslate import com.android.compose.animation.scene.transformation.DrawScale import com.android.compose.animation.scene.transformation.EdgeTranslate import com.android.compose.animation.scene.transformation.Fade -import com.android.compose.animation.scene.transformation.OverscrollTranslate import com.android.compose.animation.scene.transformation.ScaleSize import com.android.compose.animation.scene.transformation.SharedElementTransformation import com.android.compose.animation.scene.transformation.Transformation @@ -43,22 +40,14 @@ import com.android.compose.animation.scene.transformation.Translate internal fun transitionsImpl(builder: SceneTransitionsBuilder.() -> Unit): SceneTransitions { val impl = SceneTransitionsBuilderImpl().apply(builder) - return SceneTransitions( - impl.defaultSwipeSpec, - impl.transitionSpecs, - impl.transitionOverscrollSpecs, - impl.interruptionHandler, - impl.defaultOverscrollProgressConverter, - ) + return SceneTransitions(impl.defaultSwipeSpec, impl.transitionSpecs, impl.interruptionHandler) } private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder { override var defaultSwipeSpec: SpringSpec<Float> = SceneTransitions.DefaultSwipeSpec override var interruptionHandler: InterruptionHandler = DefaultInterruptionHandler - override var defaultOverscrollProgressConverter: ProgressConverter = ProgressConverter.Default val transitionSpecs = mutableListOf<TransitionSpecImpl>() - val transitionOverscrollSpecs = mutableListOf<OverscrollSpecImpl>() override fun to( to: ContentKey, @@ -81,45 +70,6 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder { transition(from = from, to = to, key = key, preview, reversePreview, builder) } - override fun overscroll( - content: ContentKey, - orientation: Orientation, - builder: OverscrollBuilder.() -> Unit, - ) { - val impl = OverscrollBuilderImpl().apply(builder) - check(impl.transformationMatchers.isNotEmpty()) { - "This method does not allow empty transformations. " + - "Use overscrollDisabled($content, $orientation) instead." - } - overscrollSpec(content, orientation, impl) - } - - override fun overscrollDisabled(content: ContentKey, orientation: Orientation) { - overscrollSpec(content, orientation, OverscrollBuilderImpl()) - } - - private fun overscrollSpec( - content: ContentKey, - orientation: Orientation, - impl: OverscrollBuilderImpl, - ): OverscrollSpec { - val spec = - OverscrollSpecImpl( - content = content, - orientation = orientation, - transformationSpec = - TransformationSpecImpl( - progressSpec = snap(), - swipeSpec = null, - distance = impl.distance, - transformationMatchers = impl.transformationMatchers, - ), - progressConverter = impl.progressConverter, - ) - transitionOverscrollSpecs.add(spec) - return spec - } - private fun transition( from: ContentKey?, to: ContentKey?, @@ -295,15 +245,3 @@ internal class TransitionBuilderImpl(override val transition: TransitionState.Tr fractionRange(start, end, easing, builder) } } - -internal open class OverscrollBuilderImpl : BaseTransitionBuilderImpl(), OverscrollBuilder { - override var progressConverter: ProgressConverter? = null - - override fun translate( - matcher: ElementMatcher, - x: OverscrollScope.() -> Float, - y: OverscrollScope.() -> Float, - ) { - addTransformation(matcher, OverscrollTranslate.Factory(x, y)) - } -} diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt index 152f05eb5cc7..3716df5b5a35 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt @@ -42,7 +42,6 @@ import com.android.compose.animation.scene.ElementStateScope import com.android.compose.animation.scene.MovableElement import com.android.compose.animation.scene.MovableElementContentScope import com.android.compose.animation.scene.MovableElementKey -import com.android.compose.animation.scene.NestedScrollBehavior import com.android.compose.animation.scene.SceneTransitionLayoutForTesting import com.android.compose.animation.scene.SceneTransitionLayoutImpl import com.android.compose.animation.scene.SceneTransitionLayoutScope @@ -57,7 +56,6 @@ import com.android.compose.animation.scene.effect.OffsetOverscrollEffect import com.android.compose.animation.scene.effect.VisualEffect import com.android.compose.animation.scene.element import com.android.compose.animation.scene.modifiers.noResizeDuringTransitions -import com.android.compose.animation.scene.nestedScrollToScene import com.android.compose.modifiers.thenIf import com.android.compose.ui.graphics.ContainerState import com.android.compose.ui.graphics.container @@ -173,32 +171,6 @@ internal class ContentScopeImpl( ) } - override fun Modifier.horizontalNestedScrollToScene( - leftBehavior: NestedScrollBehavior, - rightBehavior: NestedScrollBehavior, - isExternalOverscrollGesture: () -> Boolean, - ): Modifier { - return nestedScrollToScene( - draggableHandler = layoutImpl.horizontalDraggableHandler, - topOrLeftBehavior = leftBehavior, - bottomOrRightBehavior = rightBehavior, - isExternalOverscrollGesture = isExternalOverscrollGesture, - ) - } - - override fun Modifier.verticalNestedScrollToScene( - topBehavior: NestedScrollBehavior, - bottomBehavior: NestedScrollBehavior, - isExternalOverscrollGesture: () -> Boolean, - ): Modifier { - return nestedScrollToScene( - draggableHandler = layoutImpl.verticalDraggableHandler, - topOrLeftBehavior = topBehavior, - bottomOrRightBehavior = bottomBehavior, - isExternalOverscrollGesture = isExternalOverscrollGesture, - ) - } - override fun Modifier.noResizeDuringTransitions(): Modifier { return noResizeDuringTransitions(layoutState = layoutImpl.state) } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt index 29be445e82bb..e7ca51114b93 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt @@ -20,15 +20,12 @@ import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.AnimationVector1D import androidx.compose.animation.core.Spring import androidx.compose.animation.core.spring -import androidx.compose.foundation.gestures.Orientation import androidx.compose.runtime.Stable -import androidx.compose.runtime.State import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import com.android.compose.animation.scene.ContentKey import com.android.compose.animation.scene.MutableSceneTransitionLayoutState import com.android.compose.animation.scene.OverlayKey -import com.android.compose.animation.scene.OverscrollSpecImpl import com.android.compose.animation.scene.ProgressVisibilityThreshold import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.SceneTransitionLayoutImpl @@ -254,40 +251,13 @@ sealed interface TransitionState { internal open val isInPreviewStage: Boolean = false /** - * The current [TransformationSpecImpl] and [OverscrollSpecImpl] associated to this - * transition. + * The current [TransformationSpecImpl] associated to this transition. * * Important: These will be set exactly once, when this transition is * [started][MutableSceneTransitionLayoutStateImpl.startTransition]. */ internal var transformationSpec: TransformationSpecImpl = TransformationSpec.Empty internal var previewTransformationSpec: TransformationSpecImpl? = null - private var fromOverscrollSpec: OverscrollSpecImpl? = null - private var toOverscrollSpec: OverscrollSpecImpl? = null - - /** - * The current [OverscrollSpecImpl], if this transition is currently overscrolling. - * - * Note: This is backed by a State<OverscrollSpecImpl?> because the overscroll spec is - * derived from progress, and we don't want readers of currentOverscrollSpec to recompose - * every time progress is changed. - */ - private val _currentOverscrollSpec: State<OverscrollSpecImpl?>? = - if (this !is DirectionProperties) { - null - } else { - derivedStateOf { - val progress = progress - val bouncingContent = bouncingContent - when { - progress < 0f || bouncingContent == fromContent -> fromOverscrollSpec - progress > 1f || bouncingContent == toContent -> toOverscrollSpec - else -> null - } - } - } - internal val currentOverscrollSpec: OverscrollSpecImpl? - get() = _currentOverscrollSpec?.value /** * An animatable that animates from 1f to 0f. This will be used to nicely animate the sudden @@ -395,27 +365,13 @@ sealed interface TransitionState { } } - internal fun updateOverscrollSpecs( - fromSpec: OverscrollSpecImpl?, - toSpec: OverscrollSpecImpl?, - ) { - fromOverscrollSpec = fromSpec - toOverscrollSpec = toSpec - } - - /** Returns if the [progress] value of this transition can go beyond range `[0; 1]` */ + /** + * Checks if the given [progress] value is within the valid range for this transition. + * + * The valid range is between 0f and 1f, inclusive. + */ internal fun isWithinProgressRange(progress: Float): Boolean { - // If the properties are missing we assume that every [Transition] can overscroll - if (this !is DirectionProperties) return true - // [OverscrollSpec] for the current scene, even if it hasn't started overscrolling yet. - val specForCurrentScene = - when { - progress <= 0f -> fromOverscrollSpec - progress >= 1f -> toOverscrollSpec - else -> null - } ?: return true - - return specForCurrentScene.transformationSpec.transformationMatchers.isNotEmpty() + return progress >= 0f && progress <= 1f } internal open fun interruptionProgress(layoutImpl: SceneTransitionLayoutImpl): Float { @@ -444,36 +400,7 @@ sealed interface TransitionState { } } - interface DirectionProperties { - /** - * The position of the [Transition.toContent]. - * - * Used to understand the direction of the overscroll. - */ - val isUpOrLeft: Boolean - - /** - * The relative orientation between [Transition.fromContent] and [Transition.toContent]. - * - * Used to understand the orientation of the overscroll. - */ - val orientation: Orientation - - /** - * Return the absolute distance between fromScene and toScene, if available, otherwise - * [DistanceUnspecified]. - */ - val absoluteDistance: Float - - /** - * The content (scene or overlay) around which the transition is currently bouncing. When - * not `null`, this transition is currently oscillating around this content and will soon - * settle to that content. - */ - val bouncingContent: ContentKey? - - companion object { - const val DistanceUnspecified = 0f - } + companion object { + const val DistanceUnspecified = 0f } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt index 944bd85991c9..7c4dbf153013 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt @@ -156,12 +156,7 @@ private class VerticalContainerRevealSizeTransformation( // implement HasOverscrollProperties if the transition is triggered and not gesture based. val idleSize = checkNotNull(element.targetSize(content)) val userActionDistance = idleSize.height - val progress = - when ((transition as? TransitionState.DirectionProperties)?.bouncingContent) { - null -> transition.progressTo(content) - content -> 1f - else -> 0f - } + val progress = transition.progressTo(content) val distance = (progress * userActionDistance).fastCoerceAtLeast(0f) val threshold = distanceThreshold.toPx() @@ -256,19 +251,7 @@ private class ContainerRevealAlphaTransformation( private fun targetAlpha(transition: TransitionState.Transition, content: ContentKey): Float { if (transition.isUserInputOngoing) { - if (transition !is TransitionState.DirectionProperties) { - error( - "Unsupported transition driven by user input but that does not have " + - "overscroll properties: $transition" - ) - } - - val bouncingContent = transition.bouncingContent - return if (bouncingContent != null) { - if (bouncingContent == content) 1f else 0f - } else { - if (transition.progressTo(content) > 0f) 1f else 0f - } + return if (transition.progressTo(content) > 0f) 1f else 0f } // The transition was committed (the user released their finger), so the alpha depends on diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt index 432add38385a..30d2de61d9bb 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt @@ -17,11 +17,9 @@ package com.android.compose.animation.scene.transformation import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.Dp import com.android.compose.animation.scene.ContentKey import com.android.compose.animation.scene.ElementKey -import com.android.compose.animation.scene.OverscrollScope import com.android.compose.animation.scene.content.state.TransitionState internal class Translate private constructor(private val x: Dp, private val y: Dp) : @@ -41,71 +39,3 @@ internal class Translate private constructor(private val x: Dp, private val y: D override fun create(): Transformation = Translate(x, y) } } - -internal class OverscrollTranslate -private constructor( - private val x: OverscrollScope.() -> Float, - private val y: OverscrollScope.() -> Float, -) : InterpolatedPropertyTransformation<Offset> { - override val property = PropertyTransformation.Property.Offset - - private val cachedOverscrollScope = CachedOverscrollScope() - - override fun PropertyTransformationScope.transform( - content: ContentKey, - element: ElementKey, - transition: TransitionState.Transition, - value: Offset, - ): Offset { - // As this object is created by OverscrollBuilderImpl and we retrieve the current - // OverscrollSpec only when the transition implements HasOverscrollProperties, we can assume - // that this method was invoked after performing this check. - val overscrollProperties = transition as TransitionState.DirectionProperties - val overscrollScope = - cachedOverscrollScope.getFromCacheOrCompute(density = this, overscrollProperties) - - return Offset(x = value.x + overscrollScope.x(), y = value.y + overscrollScope.y()) - } - - class Factory( - private val x: OverscrollScope.() -> Float, - private val y: OverscrollScope.() -> Float, - ) : Transformation.Factory { - override fun create(): Transformation = OverscrollTranslate(x, y) - } -} - -/** - * A helper class to cache a [OverscrollScope] given a [Density] and - * [TransitionState.DirectionProperties]. This helps avoid recreating a scope every frame whenever - * an overscroll transition is computed. - */ -private class CachedOverscrollScope { - private var previousScope: OverscrollScope? = null - private var previousDensity: Density? = null - private var previousOverscrollProperties: TransitionState.DirectionProperties? = null - - fun getFromCacheOrCompute( - density: Density, - overscrollProperties: TransitionState.DirectionProperties, - ): OverscrollScope { - if ( - previousScope == null || - density != previousDensity || - previousOverscrollProperties != overscrollProperties - ) { - val scope = - object : OverscrollScope, Density by density { - override val absoluteDistance: Float - get() = overscrollProperties.absoluteDistance - } - - previousScope = scope - previousDensity = density - previousOverscrollProperties = overscrollProperties - return scope - } - - return checkNotNull(previousScope) - } -} diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt index 2fd1d8d8573a..62ec2215ca14 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt @@ -19,15 +19,12 @@ package com.android.compose.animation.scene import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.tween import androidx.compose.foundation.background -import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.SideEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -447,59 +444,6 @@ class AnimatedSharedAsStateTest { } @Test - fun animatedValueDoesNotOverscrollWhenOverscrollIsSpecified() { - val state = - rule.runOnUiThread { - MutableSceneTransitionLayoutStateImpl( - SceneA, - transitions { overscrollDisabled(SceneB, Orientation.Horizontal) }, - ) - } - - val key = ValueKey("foo") - val lastValues = mutableMapOf<ContentKey, Float>() - - @Composable - fun ContentScope.animateFloat(value: Float, key: ValueKey) { - val animatedValue = animateContentFloatAsState(value, key) - LaunchedEffect(animatedValue) { - snapshotFlow { animatedValue.value }.collect { lastValues[contentKey] = it } - } - } - - val scope = - rule.setContentAndCreateMainScope { - SceneTransitionLayout(state) { - scene(SceneA) { animateFloat(0f, key) } - scene(SceneB) { animateFloat(100f, key) } - } - } - - // Overscroll on A at -100%: value should be interpolated given that there is no overscroll - // defined for scene A. - var progress by mutableStateOf(-1f) - scope.launch { - state.startTransition(transition(from = SceneA, to = SceneB, progress = { progress })) - } - rule.waitForIdle() - assertThat(lastValues[SceneA]).isWithin(0.001f).of(-100f) - assertThat(lastValues[SceneB]).isWithin(0.001f).of(-100f) - - // Middle of the transition. - progress = 0.5f - rule.waitForIdle() - assertThat(lastValues[SceneA]).isWithin(0.001f).of(50f) - assertThat(lastValues[SceneB]).isWithin(0.001f).of(50f) - - // Overscroll on B at 200%: value should not be interpolated given that there is an - // overscroll defined for scene B. - progress = 2f - rule.waitForIdle() - assertThat(lastValues[SceneA]).isWithin(0.001f).of(100f) - assertThat(lastValues[SceneB]).isWithin(0.001f).of(100f) - } - - @Test fun interpolatedColor() { val a = Color.Red val b = Color.Green diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt index 6985644579f6..5a35d11c0b29 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt @@ -18,7 +18,6 @@ package com.android.compose.animation.scene import androidx.compose.animation.core.Spring import androidx.compose.animation.core.spring -import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.overscroll import androidx.compose.material3.Text import androidx.compose.ui.Modifier @@ -31,9 +30,6 @@ import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.Velocity import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.android.compose.animation.scene.NestedScrollBehavior.EdgeAlways -import com.android.compose.animation.scene.NestedScrollBehavior.EdgeNoPreview -import com.android.compose.animation.scene.NestedScrollBehavior.EdgeWithPreview import com.android.compose.animation.scene.TestOverlays.OverlayA import com.android.compose.animation.scene.TestOverlays.OverlayB import com.android.compose.animation.scene.TestScenes.SceneA @@ -141,15 +137,9 @@ class DraggableHandlerTest { var pointerInfoOwner: () -> PointersInfo = { pointersDown() } - fun nestedScrollConnection( - nestedScrollBehavior: NestedScrollBehavior, - isExternalOverscrollGesture: Boolean = false, - ) = + fun nestedScrollConnection() = NestedScrollHandlerImpl( draggableHandler = draggableHandler, - topOrLeftBehavior = nestedScrollBehavior, - bottomOrRightBehavior = nestedScrollBehavior, - isExternalOverscrollGesture = { isExternalOverscrollGesture }, pointersInfoOwner = { pointerInfoOwner() }, ) .connection @@ -270,13 +260,12 @@ class DraggableHandlerTest { velocity: Float, canChangeScene: Boolean = true, onAnimationStart: () -> Unit, - expectedConsumedVelocity: Float, ) = onDragStoppedAnimateNow( velocity = velocity, canChangeScene = canChangeScene, onAnimationStart = onAnimationStart, - onAnimationEnd = { assertThat(it).isEqualTo(expectedConsumedVelocity) }, + onAnimationEnd = {}, ) fun DragController.onDragStoppedAnimateLater( @@ -358,7 +347,6 @@ class DraggableHandlerTest { dragController.onDragStoppedAnimateNow( velocity = velocityThreshold - 0.01f, onAnimationStart = { assertTransition(currentScene = SceneA) }, - expectedConsumedVelocity = velocityThreshold - 0.01f, ) assertIdle(currentScene = SceneA) @@ -386,7 +374,6 @@ class DraggableHandlerTest { progress = 0f, ) }, - expectedConsumedVelocity = velocityThreshold - 0.01f, ) assertIdle(currentScene = SceneA) @@ -400,7 +387,6 @@ class DraggableHandlerTest { dragController.onDragStoppedAnimateNow( velocity = velocityThreshold, onAnimationStart = { assertTransition(currentScene = SceneC) }, - expectedConsumedVelocity = velocityThreshold, ) assertIdle(currentScene = SceneC) } @@ -413,7 +399,6 @@ class DraggableHandlerTest { dragController.onDragStoppedAnimateNow( velocity = 0f, onAnimationStart = { assertTransition(currentScene = SceneA) }, - expectedConsumedVelocity = 0f, ) assertIdle(currentScene = SceneA) } @@ -462,13 +447,11 @@ class DraggableHandlerTest { ) // Reverse drag direction, it does not replace the previous transition. - dragController.onDragDelta(pixels = down(fractionOfScreen = 0.5f)) - assertTransition( - currentScene = SceneA, - fromScene = SceneA, - toScene = SceneB, - progress = -0.3f, + dragController.onDragDelta( + pixels = down(fractionOfScreen = 0.5f), + expectedConsumed = down(0.2f), ) + assertTransition(currentScene = SceneA, fromScene = SceneA, toScene = SceneB, progress = 0f) } @Test @@ -515,7 +498,6 @@ class DraggableHandlerTest { onAnimationStart = { assertTransition(currentScene = SceneC, fromScene = SceneA, toScene = SceneC) }, - expectedConsumedVelocity = 0f, ) assertIdle(currentScene = SceneC) } @@ -535,7 +517,6 @@ class DraggableHandlerTest { onAnimationStart = { assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.2f) }, - expectedConsumedVelocity = down(fractionOfScreen = 0.1f), ) assertIdle(SceneA) @@ -575,293 +556,6 @@ class DraggableHandlerTest { } @Test - fun onInitialPreScroll_EdgeWithOverscroll_doNotChangeState() = runGestureTest { - val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeWithPreview) - nestedScroll.onPreScroll( - available = downOffset(fractionOfScreen = 0.1f), - source = UserInput, - ) - assertIdle(currentScene = SceneA) - } - - @Test - fun onPostScrollWithNothingAvailable_EdgeWithOverscroll_doNotChangeState() = runGestureTest { - val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeWithPreview) - val consumed = - nestedScroll.onPostScroll( - consumed = Offset.Zero, - available = Offset.Zero, - source = UserInput, - ) - - assertIdle(currentScene = SceneA) - assertThat(consumed).isEqualTo(Offset.Zero) - } - - @Test - fun onPostScrollWithSomethingAvailable_startSceneTransition() = runGestureTest { - val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeWithPreview) - val consumed = - nestedScroll.onPostScroll( - consumed = Offset.Zero, - available = downOffset(fractionOfScreen = 0.1f), - source = UserInput, - ) - - assertTransition(currentScene = SceneA) - assertThat(progress).isEqualTo(0.1f) - assertThat(consumed).isEqualTo(downOffset(fractionOfScreen = 0.1f)) - } - - @Test - fun afterSceneTransitionIsStarted_interceptPreScrollEvents() = runGestureTest { - val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeWithPreview) - nestedScroll.scroll(available = downOffset(fractionOfScreen = 0.1f)) - assertTransition(currentScene = SceneA) - - assertThat(progress).isEqualTo(0.1f) - - // start intercept preScroll - val consumed = - nestedScroll.onPreScroll( - available = downOffset(fractionOfScreen = 0.1f), - source = UserInput, - ) - assertThat(progress).isEqualTo(0.2f) - - // do nothing on postScroll - nestedScroll.onPostScroll(consumed = consumed, available = Offset.Zero, source = UserInput) - assertThat(progress).isEqualTo(0.2f) - - nestedScroll.scroll(available = downOffset(fractionOfScreen = 0.1f)) - assertThat(progress).isEqualTo(0.3f) - assertTransition(currentScene = SceneA) - } - - private fun TestGestureScope.preScrollAfterSceneTransition( - firstScroll: Float, - secondScroll: Float, - ) { - val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeWithPreview) - // start scene transition - nestedScroll.scroll(available = Offset(0f, firstScroll)) - - // stop scene transition (start the "stop animation") - nestedScroll.preFling(available = Velocity.Zero) - - // a pre scroll event, that could be intercepted by DraggableHandlerImpl - nestedScroll.onPreScroll(available = Offset(0f, secondScroll), source = UserInput) - } - - @Test - fun scrollAndFling_scrollMoreThanInterceptable_goToIdleOnNextScene() = runGestureTest { - val firstScroll = -(1f - transitionInterceptionThreshold + 0.0001f) * SCREEN_SIZE - val secondScroll = -0.01f - - preScrollAfterSceneTransition(firstScroll = firstScroll, secondScroll = secondScroll) - - advanceUntilIdle() - assertIdle(SceneB) - } - - @Test - fun duringATransition_aNewScrollGesture_shouldTakeControl() = runGestureTest { - val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeWithPreview) - // First gesture - nestedScroll.scroll(available = downOffset(fractionOfScreen = 0.1f)) - assertTransition(currentScene = SceneA) - nestedScroll.preFling(available = Velocity.Zero) - assertTransition(currentScene = SceneA) - - // Second gesture, it starts during onStop() animation - nestedScroll.scroll(downOffset(0.1f)) - assertTransition(currentScene = SceneA) - - // Allows onStop() to complete or cancel - advanceUntilIdle() - - // Second gesture continues - nestedScroll.scroll(downOffset(0.1f)) - assertTransition(currentScene = SceneA) - - // Second gesture ends - nestedScroll.preFling(available = Velocity.Zero) - assertTransition(currentScene = SceneA) - - advanceUntilIdle() - assertIdle(currentScene = SceneA) - } - - @Test - fun onPreFling_velocityLowerThanThreshold_remainSameScene() = runGestureTest { - val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeWithPreview) - nestedScroll.scroll(available = downOffset(fractionOfScreen = 0.1f)) - assertTransition(currentScene = SceneA) - - nestedScroll.preFling(available = Velocity.Zero) - assertTransition(currentScene = SceneA) - - // wait for the stop animation - advanceUntilIdle() - assertIdle(currentScene = SceneA) - } - - private fun TestGestureScope.flingAfterScroll( - use: NestedScrollBehavior, - idleAfterScroll: Boolean, - ) { - val nestedScroll = nestedScrollConnection(nestedScrollBehavior = use) - nestedScroll.scroll(available = downOffset(fractionOfScreen = 0.1f)) - if (idleAfterScroll) assertIdle(SceneA) else assertTransition(SceneA) - - nestedScroll.preFling(available = Velocity(0f, velocityThreshold)) - } - - @Test - fun flingAfterScroll_EdgeNoOverscroll_goToNextScene() = runGestureTest { - flingAfterScroll(use = EdgeNoPreview, idleAfterScroll = false) - - assertTransition(currentScene = SceneC) - - // wait for the stop animation - advanceUntilIdle() - assertIdle(currentScene = SceneC) - } - - @Test - fun flingAfterScroll_EdgeWithOverscroll_goToNextScene() = runGestureTest { - flingAfterScroll(use = EdgeWithPreview, idleAfterScroll = false) - - assertTransition(currentScene = SceneC) - - // wait for the stop animation - advanceUntilIdle() - assertIdle(currentScene = SceneC) - } - - @Test - fun flingAfterScroll_Always_goToNextScene() = runGestureTest { - flingAfterScroll(use = EdgeAlways, idleAfterScroll = false) - - assertTransition(currentScene = SceneC) - - // wait for the stop animation - advanceUntilIdle() - assertIdle(currentScene = SceneC) - } - - /** we started the scroll in the scene, then fling with the velocityThreshold */ - private fun TestGestureScope.flingAfterScrollStartedInScene( - use: NestedScrollBehavior, - idleAfterScroll: Boolean, - ) { - val nestedScroll = nestedScrollConnection(nestedScrollBehavior = use) - // scroll consumed in child - nestedScroll.scroll( - available = downOffset(fractionOfScreen = 0.1f), - consumedByScroll = downOffset(fractionOfScreen = 0.1f), - ) - - // scroll offsetY10 is all available for parents - nestedScroll.scroll(available = downOffset(fractionOfScreen = 0.1f)) - if (idleAfterScroll) assertIdle(SceneA) else assertTransition(SceneA) - - nestedScroll.preFling(available = Velocity(0f, velocityThreshold)) - } - - @Test - fun flingAfterScrollStartedInScene_EdgeNoOverscroll_doNothing() = runGestureTest { - flingAfterScrollStartedInScene(use = EdgeNoPreview, idleAfterScroll = true) - - assertIdle(currentScene = SceneA) - } - - @Test - fun flingAfterScrollStartedInScene_EdgeWithOverscroll_doOverscrollAnimation() = runGestureTest { - flingAfterScrollStartedInScene(use = EdgeWithPreview, idleAfterScroll = false) - - assertTransition(currentScene = SceneA) - - // wait for the stop animation - advanceUntilIdle() - assertIdle(currentScene = SceneA) - } - - @Test - fun flingAfterScrollStartedInScene_Always_goToNextScene() = runGestureTest { - flingAfterScrollStartedInScene(use = EdgeAlways, idleAfterScroll = false) - - assertTransition(currentScene = SceneC) - - // wait for the stop animation - advanceUntilIdle() - assertIdle(currentScene = SceneC) - } - - @Test - fun flingAfterScrollStartedByExternalOverscrollGesture() = runGestureTest { - val nestedScroll = - nestedScrollConnection( - nestedScrollBehavior = EdgeWithPreview, - isExternalOverscrollGesture = true, - ) - - // scroll not consumed in child - nestedScroll.scroll(available = downOffset(fractionOfScreen = 0.1f)) - - // scroll offsetY10 is all available for parents - nestedScroll.scroll(available = downOffset(fractionOfScreen = 0.1f)) - assertTransition(SceneA) - - nestedScroll.preFling(available = Velocity(0f, velocityThreshold)) - } - - @Test - fun beforeNestedScrollStart_stop_shouldBeIgnored() = runGestureTest { - val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeWithPreview) - nestedScroll.preFling(available = Velocity(0f, velocityThreshold)) - assertIdle(currentScene = SceneA) - } - - @Test - fun startNestedScrollWhileDragging() = runGestureTest { - val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeAlways) - - val offsetY10 = downOffset(fractionOfScreen = 0.1f) - - // Start a drag and then stop it, given that - val dragController = onDragStarted(overSlop = up(0.1f)) - - assertTransition(currentScene = SceneA) - assertThat(progress).isEqualTo(0.1f) - - // now we can intercept the scroll events - nestedScroll.scroll(available = -offsetY10) - assertThat(progress).isEqualTo(0.1f) - - // this should be ignored, we are scrolling now! - dragController.onDragStoppedAnimateNow( - velocity = -velocityThreshold, - onAnimationStart = { assertTransition(currentScene = SceneA) }, - expectedConsumedVelocity = 0f, - ) - assertTransition(currentScene = SceneA) - - nestedScroll.scroll(available = -offsetY10) - assertThat(progress).isEqualTo(0.2f) - - nestedScroll.scroll(available = -offsetY10) - assertThat(progress).isEqualTo(0.3f) - - nestedScroll.preFling(available = Velocity(0f, -velocityThreshold)) - assertTransition(currentScene = SceneB) - - // wait for the stop animation - advanceUntilIdle() - assertIdle(currentScene = SceneB) - } - - @Test fun freezeAndAnimateToCurrentState() = runGestureTest { // Start at scene C. navigateToSceneC() @@ -893,7 +587,6 @@ class DraggableHandlerTest { dragController.onDragStoppedAnimateNow( velocity = -velocityThreshold, onAnimationStart = { assertTransition(fromScene = SceneA, toScene = SceneB) }, - expectedConsumedVelocity = -velocityThreshold, ) assertIdle(SceneA) } @@ -901,7 +594,6 @@ class DraggableHandlerTest { @Test fun blockTransition_animated() = runGestureTest { assertIdle(SceneA) - layoutState.transitions = transitions { overscrollDisabled(SceneB, Orientation.Vertical) } // Swipe up to scene B. Overscroll 50%. val dragController = onDragStarted(overSlop = up(1.5f), expectedConsumedOverSlop = up(1.0f)) @@ -916,7 +608,7 @@ class DraggableHandlerTest { assertTransition(currentScene = SceneA, fromScene = SceneA, toScene = SceneB, progress = 1f) val consumed = velocityConsumed.await() - assertThat(consumed).isEqualTo(-velocityThreshold) + assertThat(consumed).isNotEqualTo(0f) assertIdle(SceneA) } @@ -924,7 +616,7 @@ class DraggableHandlerTest { fun nestedScrollUseFromSourceInfo() = runGestureTest { // Start at scene C. navigateToSceneC() - val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeAlways) + val nestedScroll = nestedScrollConnection() // Drag from the **top** of the screen pointerInfoOwner = { pointersDown() } @@ -961,7 +653,7 @@ class DraggableHandlerTest { fun ignoreMouseWheel() = runGestureTest { // Start at scene C. navigateToSceneC() - val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeAlways) + val nestedScroll = nestedScrollConnection() // Use mouse wheel pointerInfoOwner = { PointersInfo.MouseWheel } @@ -983,40 +675,7 @@ class DraggableHandlerTest { } @Test - fun emptyOverscrollImmediatelyAbortsSettleAnimationWhenOverProgress() = runGestureTest { - // Overscrolling on scene B does nothing. - layoutState.transitions = transitions { overscrollDisabled(SceneB, Orientation.Vertical) } - - // Swipe up to scene B at progress = 200%. - val middle = pointersDown(startedPosition = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f)) - val dragController = - onDragStarted( - pointersInfo = middle, - overSlop = up(2f), - // Overscroll is disabled, it will scroll up to 100% - expectedConsumedOverSlop = up(1f), - ) - - // The progress value is coerced in `[0..1]` - assertTransition(fromScene = SceneA, toScene = SceneB, progress = 1f) - - // Release the finger. - dragController.onDragStoppedAnimateNow( - velocity = -velocityThreshold, - onAnimationStart = { - // Given that we are at progress >= 100% and that the overscroll on scene B is doing - // nothing, we are already idle. - assertIdle(SceneB) - }, - expectedConsumedVelocity = 0f, - ) - } - - @Test fun emptyOverscrollAbortsSettleAnimationAndExposeTheConsumedVelocity() = runGestureTest { - // Overscrolling on scene B does nothing. - layoutState.transitions = transitions { overscrollDisabled(SceneB, Orientation.Vertical) } - // Swipe up to scene B at progress = 200%. val middle = pointersDown(startedPosition = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f)) val dragController = onDragStarted(pointersInfo = middle, overSlop = up(0.99f)) @@ -1027,7 +686,7 @@ class DraggableHandlerTest { velocity = -velocityThreshold, onAnimationStart = { assertTransition(fromScene = SceneA, toScene = SceneB) }, onAnimationEnd = { consumedVelocity -> - // Our progress value was 0.99f and it is coerced in `[0..1]` (overscrollDisabled). + // Our progress value was 0.99f and it is coerced in `[0..1]`. // Some of the velocity will be used for animation, but not all of it. assertThat(consumedVelocity).isLessThan(0f) assertThat(consumedVelocity).isGreaterThan(-velocityThreshold) @@ -1037,9 +696,7 @@ class DraggableHandlerTest { @Test fun scrollKeepPriorityEvenIfWeCanNoLongerScrollOnThatDirection() = runGestureTest { - // Overscrolling on scene B does nothing. - layoutState.transitions = transitions { overscrollDisabled(SceneB, Orientation.Vertical) } - val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeAlways) + val nestedScroll = nestedScrollConnection() // Overscroll is disabled, it will scroll up to 100% nestedScroll.scroll(available = upOffset(fractionOfScreen = 2f)) @@ -1061,7 +718,6 @@ class DraggableHandlerTest { layoutState.transitions = transitions { defaultSwipeSpec = spring(dampingRatio = Spring.DampingRatioNoBouncy) from(SceneA, to = SceneB) {} - overscroll(SceneB, Orientation.Vertical) { fade(TestElements.Foo) } } val middle = pointersDown(startedPosition = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f)) @@ -1078,13 +734,11 @@ class DraggableHandlerTest { onAnimationStart = { assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.5f) }, - expectedConsumedVelocity = -velocityThreshold, ) // We didn't overscroll at the end of the transition. assertIdle(SceneB) assertThat(transition).hasProgress(1f) - assertThat(transition).hasNoOverscrollSpec() } @Test @@ -1093,7 +747,6 @@ class DraggableHandlerTest { layoutState.transitions = transitions { defaultSwipeSpec = spring(dampingRatio = Spring.DampingRatioNoBouncy) from(SceneA, to = SceneC) {} - overscroll(SceneC, Orientation.Vertical) { fade(TestElements.Foo) } } val middle = pointersDown(startedPosition = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f)) @@ -1110,13 +763,11 @@ class DraggableHandlerTest { onAnimationStart = { assertTransition(fromScene = SceneA, toScene = SceneC, progress = 0.5f) }, - expectedConsumedVelocity = velocityThreshold, ) // We didn't overscroll at the end of the transition. assertIdle(SceneC) assertThat(transition).hasProgress(1f) - assertThat(transition).hasNoOverscrollSpec() } @Test @@ -1124,31 +775,33 @@ class DraggableHandlerTest { // Make scene B overscrollable. layoutState.transitions = transitions { from(SceneA, to = SceneB) { spec = spring(dampingRatio = Spring.DampingRatioNoBouncy) } - overscroll(SceneB, Orientation.Vertical) { fade(TestElements.Foo) } } val middle = pointersDown(startedPosition = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f)) - val dragController = onDragStarted(pointersInfo = middle, overSlop = up(1.5f)) + val dragController = + onDragStarted( + pointersInfo = middle, + overSlop = up(1.5f), + expectedConsumedOverSlop = up(1f), + ) val transition = assertThat(transitionState).isSceneTransition() assertThat(transition).hasFromScene(SceneA) assertThat(transition).hasToScene(SceneB) - assertThat(transition).hasProgress(1.5f) + assertThat(transition).hasProgress(1f) // Release to B. dragController.onDragStoppedAnimateNow( velocity = 0f, onAnimationStart = { - assertTransition(fromScene = SceneA, toScene = SceneB, progress = 1.5f) + assertTransition(fromScene = SceneA, toScene = SceneB, progress = 1f) }, - expectedConsumedVelocity = 0f, ) // We kept the overscroll at 100% so that the placement logic didn't change at the end of // the animation. assertIdle(SceneB) assertThat(transition).hasProgress(1f) - assertThat(transition).hasOverscrollSpec() } @Test @@ -1156,31 +809,33 @@ class DraggableHandlerTest { // Make scene C overscrollable. layoutState.transitions = transitions { from(SceneA, to = SceneC) { spec = spring(dampingRatio = Spring.DampingRatioNoBouncy) } - overscroll(SceneC, Orientation.Vertical) { fade(TestElements.Foo) } } val middle = pointersDown(startedPosition = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f)) - val dragController = onDragStarted(pointersInfo = middle, overSlop = down(1.5f)) + val dragController = + onDragStarted( + pointersInfo = middle, + overSlop = down(1.5f), + expectedConsumedOverSlop = down(1f), + ) val transition = assertThat(transitionState).isSceneTransition() assertThat(transition).hasFromScene(SceneA) assertThat(transition).hasToScene(SceneC) - assertThat(transition).hasProgress(1.5f) + assertThat(transition).hasProgress(1f) // Release to C. dragController.onDragStoppedAnimateNow( velocity = 0f, onAnimationStart = { - assertTransition(fromScene = SceneA, toScene = SceneC, progress = 1.5f) + assertTransition(fromScene = SceneA, toScene = SceneC, progress = 1f) }, - expectedConsumedVelocity = 0f, ) // We kept the overscroll at 100% so that the placement logic didn't change at the end of // the animation. assertIdle(SceneC) assertThat(transition).hasProgress(1f) - assertThat(transition).hasOverscrollSpec() } @Test @@ -1196,7 +851,6 @@ class DraggableHandlerTest { onAnimationStart = { assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.9f) }, - expectedConsumedVelocity = 0f, ) assertIdle(SceneA) @@ -1207,7 +861,6 @@ class DraggableHandlerTest { onAnimationStart = { assertTransition(fromScene = SceneA, toScene = SceneB, progress = 1f) }, - expectedConsumedVelocity = 0f, ) assertIdle(SceneB) } @@ -1234,7 +887,6 @@ class DraggableHandlerTest { controller.onDragStoppedAnimateNow( velocity = velocityThreshold, onAnimationStart = { assertThat(transition).hasCurrentOverlays(OverlayA) }, - expectedConsumedVelocity = velocityThreshold, ) assertThat(layoutState.transitionState).isIdle() assertThat(layoutState.transitionState).hasCurrentScene(SceneA) @@ -1264,7 +916,6 @@ class DraggableHandlerTest { controller.onDragStoppedAnimateNow( velocity = -velocityThreshold, onAnimationStart = { assertThat(transition).hasCurrentOverlays(/* empty */ ) }, - expectedConsumedVelocity = -velocityThreshold, ) assertThat(layoutState.transitionState).isIdle() assertThat(layoutState.transitionState).hasCurrentScene(SceneA) @@ -1294,7 +945,6 @@ class DraggableHandlerTest { controller.onDragStoppedAnimateNow( velocity = velocityThreshold, onAnimationStart = { assertThat(transition).hasCurrentOverlays(OverlayB) }, - expectedConsumedVelocity = velocityThreshold, ) assertThat(layoutState.transitionState).isIdle() assertThat(layoutState.transitionState).hasCurrentScene(SceneA) @@ -1313,7 +963,7 @@ class DraggableHandlerTest { // Swipe down to replace overlay A by overlay B. - val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeWithPreview) + val nestedScroll = nestedScrollConnection() nestedScroll.scroll(downOffset(0.1f)) val transition = assertThat(layoutState.transitionState).isReplaceOverlayTransition() assertThat(transition).hasCurrentScene(SceneA) diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt index ffba63988cfc..c69129b38bdd 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt @@ -17,8 +17,6 @@ package com.android.compose.animation.scene import androidx.compose.animation.core.LinearEasing -import androidx.compose.animation.core.Spring -import androidx.compose.animation.core.spring import androidx.compose.animation.core.tween import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.rememberScrollableState @@ -33,7 +31,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.overscroll import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.PagerState -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.SideEffect @@ -57,7 +54,6 @@ import androidx.compose.ui.test.assertPositionInRootIsEqualTo import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo import androidx.compose.ui.test.hasParent import androidx.compose.ui.test.hasTestTag -import androidx.compose.ui.test.hasText import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onRoot @@ -74,7 +70,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.compose.animation.scene.TestScenes.SceneA import com.android.compose.animation.scene.TestScenes.SceneB import com.android.compose.animation.scene.TestScenes.SceneC -import com.android.compose.animation.scene.content.state.TransitionState import com.android.compose.animation.scene.effect.OffsetOverscrollEffect import com.android.compose.animation.scene.subjects.assertThat import com.android.compose.test.assertSizeIsEqualTo @@ -653,122 +648,6 @@ class ElementTest { rule.onNode(isElement(TestElements.Foo)).assertSizeIsEqualTo(20.dp, 20.dp) } - private fun setupOverscrollScenario( - layoutWidth: Dp, - layoutHeight: Dp, - sceneTransitions: SceneTransitionsBuilder.() -> Unit, - firstScroll: Float, - animatedFloatRange: ClosedFloatingPointRange<Float>, - onAnimatedFloat: (Float) -> Unit, - ): MutableSceneTransitionLayoutStateImpl { - // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is - // detected as a drag event. - var touchSlop = 0f - - val state = - rule.runOnUiThread { - MutableSceneTransitionLayoutState( - initialScene = SceneA, - transitions = transitions(sceneTransitions), - ) - as MutableSceneTransitionLayoutStateImpl - } - - rule.setContent { - touchSlop = LocalViewConfiguration.current.touchSlop - SceneTransitionLayout( - state = state, - modifier = Modifier.size(layoutWidth, layoutHeight), - ) { - scene(key = SceneA, userActions = mapOf(Swipe.Down to SceneB)) { - animateContentFloatAsState( - value = animatedFloatRange.start, - key = TestValues.Value1, - false, - ) - Spacer(Modifier.fillMaxSize()) - } - scene(SceneB) { - val animatedFloat by - animateContentFloatAsState( - value = animatedFloatRange.endInclusive, - key = TestValues.Value1, - canOverflow = false, - ) - Spacer(Modifier.element(TestElements.Foo).fillMaxSize()) - LaunchedEffect(Unit) { - snapshotFlow { animatedFloat }.collect { onAnimatedFloat(it) } - } - } - } - } - - assertThat(state.transitionState).isIdle() - - // Swipe by half of verticalSwipeDistance. - rule.onRoot().performTouchInput { - val middleTop = Offset((layoutWidth / 2).toPx(), 0f) - down(middleTop) - val firstScrollHeight = layoutHeight.toPx() * firstScroll - moveBy(Offset(0f, touchSlop + firstScrollHeight), delayMillis = 1_000) - } - return state - } - - @Test - fun elementTransitionDuringOverscrollWithOverscrollDSL() { - val layoutWidth = 200.dp - val layoutHeight = 400.dp - val overscrollTranslateY = 10.dp - var animatedFloat = 0f - - val state = - setupOverscrollScenario( - layoutWidth = layoutWidth, - layoutHeight = layoutHeight, - sceneTransitions = { - overscroll(SceneB, Orientation.Vertical) { - progressConverter = ProgressConverter.linear() - // On overscroll 100% -> Foo should translate by overscrollTranslateY - translate(TestElements.Foo, y = overscrollTranslateY) - } - }, - firstScroll = 0.5f, // Scroll 50% - animatedFloatRange = 0f..100f, - onAnimatedFloat = { animatedFloat = it }, - ) - - val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag) - fooElement.assertTopPositionInRootIsEqualTo(0.dp) - val transition = assertThat(state.transitionState).isSceneTransition() - assertThat(transition).isNotNull() - assertThat(transition).hasProgress(0.5f) - assertThat(animatedFloat).isEqualTo(50f) - - rule.onRoot().performTouchInput { - // Scroll another 100% - moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000) - } - - // Scroll 150% (Scene B overscroll by 50%) - assertThat(transition).hasProgress(1.5f) - assertThat(transition).hasOverscrollSpec() - fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 0.5f) - // animatedFloat cannot overflow (canOverflow = false) - assertThat(animatedFloat).isEqualTo(100f) - - rule.onRoot().performTouchInput { - // Scroll another 100% - moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000) - } - - // Scroll 250% (Scene B overscroll by 150%) - assertThat(transition).hasProgress(2.5f) - assertThat(transition).hasOverscrollSpec() - fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 1.5f) - assertThat(animatedFloat).isEqualTo(100f) - } - private fun expectedOffset(currentOffset: Dp, density: Density): Dp { return with(density) { OffsetOverscrollEffect.computeOffset(density, currentOffset.toPx()).toDp() @@ -784,13 +663,7 @@ class ElementTest { // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is // detected as a drag event. var touchSlop = 0f - val state = - rule.runOnUiThread { - MutableSceneTransitionLayoutState( - initialScene = SceneA, - transitions = transitions { overscrollDisabled(SceneB, Orientation.Vertical) }, - ) - } + val state = rule.runOnUiThread { MutableSceneTransitionLayoutState(initialScene = SceneA) } rule.setContent { density = LocalDensity.current touchSlop = LocalViewConfiguration.current.touchSlop @@ -845,17 +718,7 @@ class ElementTest { // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is // detected as a drag event. var touchSlop = 0f - val state = - rule.runOnUiThread { - MutableSceneTransitionLayoutState( - initialScene = SceneA, - transitions = - transitions { - overscrollDisabled(SceneA, Orientation.Vertical) - overscrollDisabled(SceneB, Orientation.Vertical) - }, - ) - } + val state = rule.runOnUiThread { MutableSceneTransitionLayoutState(initialScene = SceneA) } rule.setContent { density = LocalDensity.current touchSlop = LocalViewConfiguration.current.touchSlop @@ -950,17 +813,7 @@ class ElementTest { // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is // detected as a drag event. var touchSlop = 0f - val state = - rule.runOnUiThread { - MutableSceneTransitionLayoutState( - initialScene = SceneA, - transitions = - transitions { - defaultOverscrollProgressConverter = ProgressConverter.linear() - overscrollDisabled(SceneB, Orientation.Vertical) - }, - ) - } + val state = rule.runOnUiThread { MutableSceneTransitionLayoutState(initialScene = SceneA) } rule.setContent { density = LocalDensity.current touchSlop = LocalViewConfiguration.current.touchSlop @@ -1013,13 +866,7 @@ class ElementTest { val layoutWidth = 200.dp val layoutHeight = 400.dp - val state = - rule.runOnUiThread { - MutableSceneTransitionLayoutState( - initialScene = SceneA, - transitions = transitions { overscrollDisabled(SceneB, Orientation.Vertical) }, - ) - } + val state = rule.runOnUiThread { MutableSceneTransitionLayoutState(initialScene = SceneA) } rule.setContent { density = LocalDensity.current @@ -1146,262 +993,6 @@ class ElementTest { } @Test - fun elementTransitionWithDistanceDuringOverscroll() { - val layoutWidth = 200.dp - val layoutHeight = 400.dp - var animatedFloat = 0f - val state = - setupOverscrollScenario( - layoutWidth = layoutWidth, - layoutHeight = layoutHeight, - sceneTransitions = { - overscroll(SceneB, Orientation.Vertical) { - progressConverter = ProgressConverter.linear() - // On overscroll 100% -> Foo should translate by layoutHeight - translate(TestElements.Foo, y = { absoluteDistance }) - } - }, - firstScroll = 1f, // 100% scroll - animatedFloatRange = 0f..100f, - onAnimatedFloat = { animatedFloat = it }, - ) - - val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag) - fooElement.assertTopPositionInRootIsEqualTo(0.dp) - assertThat(animatedFloat).isEqualTo(100f) - - rule.onRoot().performTouchInput { - // Scroll another 50% - moveBy(Offset(0f, layoutHeight.toPx() * 0.5f), delayMillis = 1_000) - } - - val transition = assertThat(state.transitionState).isSceneTransition() - assertThat(animatedFloat).isEqualTo(100f) - - // Scroll 150% (100% scroll + 50% overscroll) - assertThat(transition).hasProgress(1.5f) - assertThat(transition).hasOverscrollSpec() - fooElement.assertTopPositionInRootIsEqualTo(layoutHeight * 0.5f) - assertThat(animatedFloat).isEqualTo(100f) - - rule.onRoot().performTouchInput { - // Scroll another 100% - moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000) - } - - // Scroll 250% (100% scroll + 150% overscroll) - assertThat(transition).hasProgress(2.5f) - assertThat(transition).hasOverscrollSpec() - fooElement.assertTopPositionInRootIsEqualTo(layoutHeight * 1.5f) - assertThat(animatedFloat).isEqualTo(100f) - } - - @Test - fun elementTransitionWithDistanceDuringOverscrollWithDefaultProgressConverter() { - val layoutWidth = 200.dp - val layoutHeight = 400.dp - var animatedFloat = 0f - val state = - setupOverscrollScenario( - layoutWidth = layoutWidth, - layoutHeight = layoutHeight, - sceneTransitions = { - // Overscroll progress will be halved - defaultOverscrollProgressConverter = ProgressConverter { it / 2f } - - overscroll(SceneB, Orientation.Vertical) { - // On overscroll 100% -> Foo should translate by layoutHeight - translate(TestElements.Foo, y = { absoluteDistance }) - } - }, - firstScroll = 1f, // 100% scroll - animatedFloatRange = 0f..100f, - onAnimatedFloat = { animatedFloat = it }, - ) - - val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag) - fooElement.assertTopPositionInRootIsEqualTo(0.dp) - assertThat(animatedFloat).isEqualTo(100f) - - rule.onRoot().performTouchInput { - // Scroll another 100% - moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000) - } - - val transition = assertThat(state.transitionState).isSceneTransition() - assertThat(animatedFloat).isEqualTo(100f) - - // Scroll 200% (100% scroll + 100% overscroll) - assertThat(transition).hasProgress(2f) - assertThat(transition).hasOverscrollSpec() - - // Overscroll progress is halved, we are at 50% of the overscroll progress. - fooElement.assertTopPositionInRootIsEqualTo(layoutHeight * 0.5f) - assertThat(animatedFloat).isEqualTo(100f) - } - - @Test - fun elementTransitionWithDistanceDuringOverscrollWithOverrideDefaultProgressConverter() { - val layoutWidth = 200.dp - val layoutHeight = 400.dp - var animatedFloat = 0f - val state = - setupOverscrollScenario( - layoutWidth = layoutWidth, - layoutHeight = layoutHeight, - sceneTransitions = { - // Overscroll progress will be linear (by default) - defaultOverscrollProgressConverter = ProgressConverter.linear() - - overscroll(SceneB, Orientation.Vertical) { - // This override the defaultOverscrollProgressConverter - // Overscroll progress will be halved - progressConverter = ProgressConverter { it / 2f } - // On overscroll 100% -> Foo should translate by layoutHeight - translate(TestElements.Foo, y = { absoluteDistance }) - } - }, - firstScroll = 1f, // 100% scroll - animatedFloatRange = 0f..100f, - onAnimatedFloat = { animatedFloat = it }, - ) - - val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag) - fooElement.assertTopPositionInRootIsEqualTo(0.dp) - assertThat(animatedFloat).isEqualTo(100f) - - rule.onRoot().performTouchInput { - // Scroll another 100% - moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000) - } - - val transition = assertThat(state.transitionState).isSceneTransition() - assertThat(animatedFloat).isEqualTo(100f) - - // Scroll 200% (100% scroll + 100% overscroll) - assertThat(transition).hasProgress(2f) - assertThat(transition).hasOverscrollSpec() - - // Overscroll progress is halved, we are at 50% of the overscroll progress. - fooElement.assertTopPositionInRootIsEqualTo(layoutHeight * 0.5f) - assertThat(animatedFloat).isEqualTo(100f) - } - - @Test - fun elementTransitionWithDistanceDuringOverscrollWithProgressConverter() { - val layoutWidth = 200.dp - val layoutHeight = 400.dp - var animatedFloat = 0f - val state = - setupOverscrollScenario( - layoutWidth = layoutWidth, - layoutHeight = layoutHeight, - sceneTransitions = { - overscroll(SceneB, Orientation.Vertical) { - // Overscroll progress will be halved - progressConverter = ProgressConverter { it / 2f } - - // On overscroll 100% -> Foo should translate by layoutHeight - translate(TestElements.Foo, y = { absoluteDistance }) - } - }, - firstScroll = 1f, // 100% scroll - animatedFloatRange = 0f..100f, - onAnimatedFloat = { animatedFloat = it }, - ) - - val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag) - fooElement.assertTopPositionInRootIsEqualTo(0.dp) - assertThat(animatedFloat).isEqualTo(100f) - - rule.onRoot().performTouchInput { - // Scroll another 100% - moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000) - } - - val transition = assertThat(state.transitionState).isSceneTransition() - assertThat(animatedFloat).isEqualTo(100f) - - // Scroll 200% (100% scroll + 100% overscroll) - assertThat(transition).hasProgress(2f) - assertThat(transition).hasOverscrollSpec() - - // Overscroll progress is halved, we are at 50% of the overscroll progress. - fooElement.assertTopPositionInRootIsEqualTo(layoutHeight * 0.5f) - assertThat(animatedFloat).isEqualTo(100f) - - rule.onRoot().performTouchInput { - // Scroll another 100% - moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000) - } - - // Scroll 300% (100% scroll + 200% overscroll) - assertThat(transition).hasProgress(3f) - assertThat(transition).hasOverscrollSpec() - - // Overscroll progress is halved, we are at 100% of the overscroll progress. - fooElement.assertTopPositionInRootIsEqualTo(layoutHeight) - assertThat(animatedFloat).isEqualTo(100f) - } - - @Test - fun elementTransitionWithDistanceDuringOverscrollBouncing() { - val layoutWidth = 200.dp - val layoutHeight = 400.dp - var animatedFloat = 0f - val state = - setupOverscrollScenario( - layoutWidth = layoutWidth, - layoutHeight = layoutHeight, - sceneTransitions = { - defaultSwipeSpec = - spring( - dampingRatio = Spring.DampingRatioMediumBouncy, - stiffness = Spring.StiffnessLow, - ) - - overscroll(SceneB, Orientation.Vertical) { - progressConverter = ProgressConverter.linear() - // On overscroll 100% -> Foo should translate by layoutHeight - translate(TestElements.Foo, y = { absoluteDistance }) - } - }, - firstScroll = 1f, // 100% scroll - animatedFloatRange = 0f..100f, - onAnimatedFloat = { animatedFloat = it }, - ) - - val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag) - fooElement.assertTopPositionInRootIsEqualTo(0.dp) - assertThat(animatedFloat).isEqualTo(100f) - - rule.onRoot().performTouchInput { - // Scroll another 50% - moveBy(Offset(0f, layoutHeight.toPx() * 0.5f), delayMillis = 1_000) - } - - val transition = assertThat(state.transitionState).isSceneTransition() - - // Scroll 150% (100% scroll + 50% overscroll) - assertThat(transition).hasProgress(1.5f) - assertThat(transition).hasOverscrollSpec() - fooElement.assertTopPositionInRootIsEqualTo(layoutHeight * (transition.progress - 1f)) - assertThat(animatedFloat).isEqualTo(100f) - - // finger raised - rule.onRoot().performTouchInput { up() } - - // The target value is 1f, but the spring (defaultSwipeSpec) allows you to go to a lower - // value. - rule.waitUntil(timeoutMillis = 10_000) { transition.progress < 1f } - - assertThat(transition.progress).isLessThan(1f) - assertThat(transition).hasOverscrollSpec() - assertThat(transition).hasBouncingContent(transition.toContent) - assertThat(animatedFloat).isEqualTo(100f) - } - - @Test fun elementIsUsingLastTransition() { // 4 frames of animation. val duration = 4 * 16 @@ -1848,13 +1439,7 @@ class ElementTest { @Test fun targetStateIsSetEvenWhenNotPlaced() { // Start directly at A => B but with progress < 0f to overscroll on A. - val state = - rule.runOnUiThread { - MutableSceneTransitionLayoutStateImpl( - SceneA, - transitions { overscrollDisabled(SceneA, Orientation.Horizontal) }, - ) - } + val state = rule.runOnUiThread { MutableSceneTransitionLayoutStateImpl(SceneA) } lateinit var layoutImpl: SceneTransitionLayoutImpl val scope = @@ -1870,14 +1455,7 @@ class ElementTest { } scope.launch { - state.startTransition( - transition( - from = SceneA, - to = SceneB, - progress = { -1f }, - orientation = Orientation.Horizontal, - ) - ) + state.startTransition(transition(from = SceneA, to = SceneB, progress = { -1f })) } rule.waitForIdle() @@ -2004,204 +1582,6 @@ class ElementTest { } @Test - fun sharedElementIsOnlyPlacedInOverscrollingScene() { - val state = - rule.runOnUiThread { - MutableSceneTransitionLayoutStateImpl( - SceneA, - transitions { - overscrollDisabled(SceneA, Orientation.Horizontal) - overscrollDisabled(SceneB, Orientation.Horizontal) - }, - ) - } - - @Composable - fun ContentScope.Foo() { - Box(Modifier.element(TestElements.Foo).size(10.dp)) - } - - val scope = - rule.setContentAndCreateMainScope { - SceneTransitionLayout(state) { - scene(SceneA) { Foo() } - scene(SceneB) { Foo() } - } - } - - rule.onNode(isElement(TestElements.Foo, SceneA)).assertIsDisplayed() - rule.onNode(isElement(TestElements.Foo, SceneB)).assertDoesNotExist() - - // A => B while overscrolling at scene B. - var progress by mutableStateOf(2f) - scope.launch { - state.startTransition(transition(from = SceneA, to = SceneB, progress = { progress })) - } - rule.waitForIdle() - - // Foo should only be placed in scene B. - rule.onNode(isElement(TestElements.Foo, SceneA)).assertExists().assertIsNotDisplayed() - rule.onNode(isElement(TestElements.Foo, SceneB)).assertIsDisplayed() - - // Overscroll at scene A. - progress = -1f - rule.waitForIdle() - - // Foo should only be placed in scene A. - rule.onNode(isElement(TestElements.Foo, SceneA)).assertIsDisplayed() - rule.onNode(isElement(TestElements.Foo, SceneB)).assertExists().assertIsNotDisplayed() - } - - @Test - fun sharedMovableElementIsOnlyComposedInOverscrollingScene() { - val state = - rule.runOnUiThread { - MutableSceneTransitionLayoutStateImpl( - SceneA, - transitions { - overscrollDisabled(SceneA, Orientation.Horizontal) - overscrollDisabled(SceneB, Orientation.Horizontal) - }, - ) - } - - val fooInA = "fooInA" - val fooInB = "fooInB" - - val key = MovableElementKey("Foo", contents = setOf(SceneA, SceneB)) - - @Composable - fun ContentScope.MovableFoo(text: String, modifier: Modifier = Modifier) { - MovableElement(key, modifier) { content { Text(text) } } - } - - val scope = - rule.setContentAndCreateMainScope { - SceneTransitionLayout(state) { - scene(SceneA) { MovableFoo(text = fooInA) } - scene(SceneB) { MovableFoo(text = fooInB) } - } - } - - rule.onNode(hasText(fooInA)).assertIsDisplayed() - rule.onNode(hasText(fooInB)).assertDoesNotExist() - - // A => B while overscrolling at scene B. - var progress by mutableStateOf(2f) - scope.launch { - state.startTransition(transition(from = SceneA, to = SceneB, progress = { progress })) - } - rule.waitForIdle() - - // Foo content should only be composed in scene B. - rule.onNode(hasText(fooInA)).assertDoesNotExist() - rule.onNode(hasText(fooInB)).assertIsDisplayed() - - // Overscroll at scene A. - progress = -1f - rule.waitForIdle() - - // Foo content should only be composed in scene A. - rule.onNode(hasText(fooInA)).assertIsDisplayed() - rule.onNode(hasText(fooInB)).assertDoesNotExist() - } - - @Test - fun interruptionThenOverscroll() { - val state = - rule.runOnUiThread { - MutableSceneTransitionLayoutStateImpl( - SceneA, - transitions { - overscroll(SceneB, Orientation.Vertical) { - progressConverter = ProgressConverter.linear() - translate(TestElements.Foo, y = 15.dp) - } - }, - ) - } - - @Composable - fun ContentScope.SceneWithFoo(offset: DpOffset, modifier: Modifier = Modifier) { - Box(modifier.fillMaxSize()) { - Box(Modifier.offset(offset.x, offset.y).element(TestElements.Foo).size(100.dp)) - } - } - - val scope = - rule.setContentAndCreateMainScope { - SceneTransitionLayout(state, Modifier.size(200.dp)) { - scene(SceneA) { SceneWithFoo(offset = DpOffset.Zero) } - scene(SceneB) { SceneWithFoo(offset = DpOffset(x = 40.dp, y = 0.dp)) } - scene(SceneC) { SceneWithFoo(offset = DpOffset(x = 40.dp, y = 40.dp)) } - } - } - - // Start A => B at 75%. - scope.launch { - state.startTransition( - transition( - from = SceneA, - to = SceneB, - progress = { 0.75f }, - onFreezeAndAnimate = { /* never finish */ }, - ) - ) - } - - // Foo should be at offset (30dp, 0dp) and placed in scene B. - rule.onNode(isElement(TestElements.Foo, SceneA)).assertIsNotDisplayed() - rule.onNode(isElement(TestElements.Foo, SceneB)).assertPositionInRootIsEqualTo(30.dp, 0.dp) - rule.onNode(isElement(TestElements.Foo, SceneC)).assertIsNotDisplayed() - - // Interrupt A => B with B => C at 0%. - var progress by mutableStateOf(0f) - var interruptionProgress by mutableStateOf(1f) - scope.launch { - state.startTransition( - transition( - from = SceneB, - to = SceneC, - progress = { progress }, - interruptionProgress = { interruptionProgress }, - orientation = Orientation.Vertical, - onFreezeAndAnimate = { /* never finish */ }, - ) - ) - } - - // Because interruption progress is at 100M, Foo should still be at offset (30dp, 0dp) but - // placed in scene C. - rule.onNode(isElement(TestElements.Foo, SceneA)).assertIsNotDisplayed() - rule.onNode(isElement(TestElements.Foo, SceneB)).assertIsNotDisplayed() - rule.onNode(isElement(TestElements.Foo, SceneC)).assertPositionInRootIsEqualTo(30.dp, 0.dp) - - // Overscroll B => C on scene B at -100%. Because overscrolling on B => C translates Foo - // vertically by -15dp and that interruptionProgress is still 100%, we should now be at - // (30dp, -15dp) - progress = -1f - rule.onNode(isElement(TestElements.Foo, SceneA)).assertIsNotDisplayed() - rule - .onNode(isElement(TestElements.Foo, SceneB)) - .assertPositionInRootIsEqualTo(30.dp, -15.dp) - rule.onNode(isElement(TestElements.Foo, SceneC)).assertIsNotDisplayed() - - // Finish the interruption, we should now be at (40dp, -15dp), still on scene B. - interruptionProgress = 0f - rule.onNode(isElement(TestElements.Foo, SceneA)).assertIsNotDisplayed() - rule - .onNode(isElement(TestElements.Foo, SceneB)) - .assertPositionInRootIsEqualTo(40.dp, -15.dp) - rule.onNode(isElement(TestElements.Foo, SceneC)).assertIsNotDisplayed() - - // Finish the transition, we should be at the final position (40dp, 40dp) on scene C. - progress = 1f - rule.onNode(isElement(TestElements.Foo, SceneA)).assertIsNotDisplayed() - rule.onNode(isElement(TestElements.Foo, SceneB)).assertIsNotDisplayed() - rule.onNode(isElement(TestElements.Foo, SceneC)).assertPositionInRootIsEqualTo(40.dp, 40.dp) - } - - @Test fun lastPlacementValuesAreClearedOnNestedElements() { val state = rule.runOnIdle { MutableSceneTransitionLayoutStateImpl(SceneA) } @@ -2397,53 +1777,6 @@ class ElementTest { } @Test - fun lastSizeIsUnspecifiedWhenOverscrollingOtherScene() { - val state = - rule.runOnIdle { - MutableSceneTransitionLayoutStateImpl( - SceneA, - transitions { overscrollDisabled(SceneA, Orientation.Horizontal) }, - ) - } - - @Composable - fun ContentScope.Foo() { - Box(Modifier.element(TestElements.Foo).size(10.dp)) - } - - lateinit var layoutImpl: SceneTransitionLayoutImpl - val scope = - rule.setContentAndCreateMainScope { - SceneTransitionLayoutForTesting(state, onLayoutImpl = { layoutImpl = it }) { - scene(SceneA) { Foo() } - scene(SceneB) { Foo() } - } - } - - // Overscroll A => B on A. - scope.launch { - state.startTransition( - transition( - from = SceneA, - to = SceneB, - progress = { -1f }, - onFreezeAndAnimate = { /* never finish */ }, - ) - ) - } - rule.waitForIdle() - - assertThat( - layoutImpl.elements - .getValue(TestElements.Foo) - .stateByContent - .getValue(SceneB) - .lastSize - ) - .isEqualTo(Element.SizeUnspecified) - } - - @Test fun transparentElementIsNotImpactingInterruption() { val state = rule.runOnIdle { @@ -2853,7 +2186,6 @@ class ElementTest { // Start an overscrollable transition driven by progress. var progress by mutableFloatStateOf(0f) val transition = transition(from = SceneA, to = SceneB, progress = { progress }) - assertThat(transition).isInstanceOf(TransitionState.DirectionProperties::class.java) scope.launch { state.startTransition(transition) } // Reset the counters after the first animation frame. diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/NestedScrollToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/NestedScrollToSceneTest.kt deleted file mode 100644 index 37dae39f935d..000000000000 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/NestedScrollToSceneTest.kt +++ /dev/null @@ -1,318 +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.compose.animation.scene - -import androidx.compose.foundation.gestures.Orientation.Vertical -import androidx.compose.foundation.gestures.rememberScrollableState -import androidx.compose.foundation.gestures.scrollable -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.size -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.platform.LocalViewConfiguration -import androidx.compose.ui.test.junit4.createComposeRule -import androidx.compose.ui.test.onRoot -import androidx.compose.ui.test.performTouchInput -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp -import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.android.compose.animation.scene.TestScenes.SceneA -import com.android.compose.animation.scene.TestScenes.SceneB -import com.android.compose.animation.scene.subjects.assertThat -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith - -@RunWith(AndroidJUnit4::class) -class NestedScrollToSceneTest { - @get:Rule val rule = createComposeRule() - - private var touchSlop = 0f - private val layoutWidth: Dp = 200.dp - private val layoutHeight = 400.dp - - private fun setup2ScenesAndScrollTouchSlop( - modifierSceneA: @Composable ContentScope.() -> Modifier = { Modifier } - ): MutableSceneTransitionLayoutState { - val state = - rule.runOnUiThread { - MutableSceneTransitionLayoutState(SceneA, transitions = EmptyTestTransitions) - } - - rule.setContent { - touchSlop = LocalViewConfiguration.current.touchSlop - SceneTransitionLayout( - state = state, - modifier = Modifier.size(layoutWidth, layoutHeight), - ) { - scene(SceneA, userActions = mapOf(Swipe.Up to SceneB)) { - Spacer(modifierSceneA().fillMaxSize()) - } - scene(SceneB, userActions = mapOf(Swipe.Down to SceneA)) { - Spacer(Modifier.fillMaxSize()) - } - } - } - - pointerDownAndScrollTouchSlop() - - assertThat(state.transitionState).isIdle() - - return state - } - - private fun pointerDownAndScrollTouchSlop() { - rule.onRoot().performTouchInput { - val middleTop = Offset((layoutWidth / 2).toPx(), 0f) - down(middleTop) - // Scroll touchSlop - moveBy(Offset(0f, touchSlop), delayMillis = 1_000) - } - } - - private fun scrollDown(percent: Float = 1f) { - rule.onRoot().performTouchInput { - moveBy(Offset(0f, layoutHeight.toPx() * percent), delayMillis = 1_000) - } - } - - private fun scrollUp(percent: Float = 1f) = scrollDown(-percent) - - private fun pointerUp() { - rule.onRoot().performTouchInput { up() } - } - - @Test - fun scrollableElementsInSTL_shouldHavePriority() { - val state = setup2ScenesAndScrollTouchSlop { - Modifier - // A scrollable that consumes the scroll gesture - .scrollable(rememberScrollableState { it }, Vertical) - } - - scrollUp(percent = 0.5f) - - // Consumed by the scrollable element - assertThat(state.transitionState).isIdle() - } - - @Test - fun unconsumedScrollEvents_canBeConsumedBySTLByDefault() { - val state = setup2ScenesAndScrollTouchSlop { - Modifier - // A scrollable that does not consume the scroll gesture - .scrollable(rememberScrollableState { 0f }, Vertical) - } - - scrollUp(percent = 0.5f) - // STL will start a transition with the remaining scroll - val transition = assertThat(state.transitionState).isSceneTransition() - assertThat(transition).hasProgress(0.5f) - - scrollUp(percent = 1f) - assertThat(transition).hasProgress(1.5f) - } - - @Test - fun customizeStlNestedScrollBehavior_EdgeNoPreview() { - var canScroll = true - val state = setup2ScenesAndScrollTouchSlop { - Modifier.verticalNestedScrollToScene( - bottomBehavior = NestedScrollBehavior.EdgeNoPreview - ) - .scrollable(rememberScrollableState { if (canScroll) it else 0f }, Vertical) - } - - scrollUp(percent = 0.5f) - assertThat(state.transitionState).isIdle() - - // Reach the end of the scrollable element - canScroll = false - scrollUp(percent = 0.5f) - assertThat(state.transitionState).isIdle() - - pointerUp() - assertThat(state.transitionState).isIdle() - - // Start a new gesture - pointerDownAndScrollTouchSlop() - scrollUp(percent = 0.5f) - val transition = assertThat(state.transitionState).isSceneTransition() - assertThat(transition).hasProgress(0.5f) - - pointerUp() - rule.waitForIdle() - assertThat(state.transitionState).isIdle() - assertThat(state.transitionState).hasCurrentScene(SceneB) - } - - @Test - fun customizeStlNestedScrollBehavior_EdgeWithPreview() { - var canScroll = true - val state = setup2ScenesAndScrollTouchSlop { - Modifier.verticalNestedScrollToScene( - bottomBehavior = NestedScrollBehavior.EdgeWithPreview - ) - .scrollable(rememberScrollableState { if (canScroll) it else 0f }, Vertical) - } - - scrollUp(percent = 0.5f) - assertThat(state.transitionState).isIdle() - - // Reach the end of the scrollable element - canScroll = false - scrollUp(percent = 0.5f) - val transition1 = assertThat(state.transitionState).isSceneTransition() - assertThat(transition1).hasProgress(0.5f) - - pointerUp() - rule.waitForIdle() - assertThat(state.transitionState).isIdle() - assertThat(state.transitionState).hasCurrentScene(SceneA) - - // Start a new gesture - pointerDownAndScrollTouchSlop() - scrollUp(percent = 0.5f) - val transition2 = assertThat(state.transitionState).isSceneTransition() - assertThat(transition2).hasProgress(0.5f) - - pointerUp() - rule.waitForIdle() - assertThat(state.transitionState).isIdle() - assertThat(state.transitionState).hasCurrentScene(SceneB) - } - - @Test - fun customizeStlNestedScrollBehavior_EdgeAlways() { - var canScroll = true - val state = setup2ScenesAndScrollTouchSlop { - Modifier.verticalNestedScrollToScene(bottomBehavior = NestedScrollBehavior.EdgeAlways) - .scrollable(rememberScrollableState { if (canScroll) it else 0f }, Vertical) - } - - scrollUp(percent = 0.5f) - assertThat(state.transitionState).isIdle() - - // Reach the end of the scrollable element - canScroll = false - scrollUp(percent = 0.5f) - val transition = assertThat(state.transitionState).isSceneTransition() - assertThat(transition).hasProgress(0.5f) - - pointerUp() - rule.waitForIdle() - assertThat(state.transitionState).isIdle() - assertThat(state.transitionState).hasCurrentScene(SceneB) - } - - @Test - fun stlNotConsumeUnobservedGesture() { - val state = - rule.runOnUiThread { - MutableSceneTransitionLayoutState(SceneA, transitions = EmptyTestTransitions) - } - - rule.setContent { - touchSlop = LocalViewConfiguration.current.touchSlop - SceneTransitionLayout( - state = state, - modifier = Modifier.size(layoutWidth, layoutHeight), - ) { - scene(SceneA) { - Spacer( - Modifier.verticalNestedScrollToScene() - // This scrollable will not consume the gesture. - .scrollable(rememberScrollableState { 0f }, Vertical) - .fillMaxSize() - ) - } - } - } - - rule.onRoot().performTouchInput { - down(Offset.Zero) - // There is no vertical scene. - moveBy(Offset(0f, layoutWidth.toPx()), delayMillis = 1_000) - } - - rule.waitForIdle() - assertThat(state.transitionState).isIdle() - } - - @Test - fun customizeStlNestedScrollBehavior_multipleRequests() { - var canScroll = true - val state = setup2ScenesAndScrollTouchSlop { - Modifier - // This verticalNestedScrollToScene is closer the STL (an ancestor node) - .verticalNestedScrollToScene(bottomBehavior = NestedScrollBehavior.EdgeAlways) - // Another verticalNestedScrollToScene modifier - .verticalNestedScrollToScene(bottomBehavior = NestedScrollBehavior.EdgeNoPreview) - .scrollable(rememberScrollableState { if (canScroll) it else 0f }, Vertical) - } - - scrollUp(percent = 0.5f) - assertThat(state.transitionState).isIdle() - - // Reach the end of the scrollable element - canScroll = false - - scrollUp(percent = 0.5f) - // EdgeAlways always consume the remaining scroll, EdgeNoPreview does not. - val transition = assertThat(state.transitionState).isSceneTransition() - assertThat(transition).hasProgress(0.5f) - } - - @Test - fun resetScrollTracking_afterMissingPointerUpEvent() { - var canScroll = true - var hasScrollable by mutableStateOf(true) - val state = setup2ScenesAndScrollTouchSlop { - if (hasScrollable) { - Modifier.scrollable(rememberScrollableState { if (canScroll) it else 0f }, Vertical) - } else { - Modifier - } - } - - // The gesture is consumed by the component in the scene. - scrollUp(percent = 0.2f) - - // STL keeps track of the scroll consumed. The scene remains in Idle. - assertThat(state.transitionState).isIdle() - - // The scrollable component disappears, and does not send the signal (pointer up) to reset - // the consumed amount. - hasScrollable = false - pointerUp() - - // A new scrollable component appears and allows the scene to consume the scroll. - hasScrollable = true - canScroll = false - pointerDownAndScrollTouchSlop() - scrollUp(percent = 0.2f) - - // STL can only start the transition if it has reset the amount of scroll consumed. - val transition = assertThat(state.transitionState).isSceneTransition() - assertThat(transition).hasProgress(0.2f) - } -} diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt index 7ea414d6b8cd..bad4c6298e6b 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt @@ -19,7 +19,6 @@ package com.android.compose.animation.scene import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.tween import androidx.compose.foundation.ScrollState -import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size @@ -46,7 +45,6 @@ import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onRoot import androidx.compose.ui.test.performTouchInput import androidx.compose.ui.test.swipe -import androidx.compose.ui.test.swipeUp import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -56,7 +54,6 @@ import com.android.compose.animation.scene.TestScenes.SceneA import com.android.compose.animation.scene.subjects.assertThat import com.android.compose.test.assertSizeIsEqualTo import com.android.compose.test.setContentAndCreateMainScope -import com.android.compose.test.subjects.assertThat import com.android.compose.test.transition import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope @@ -745,18 +742,7 @@ class OverlayTest { @Test fun overscrollingOverlay_movableElementNotInOverlay() { - val state = - rule.runOnUiThread { - MutableSceneTransitionLayoutStateImpl( - SceneA, - transitions { - // Make OverlayA overscrollable. - overscroll(OverlayA, orientation = Orientation.Horizontal) { - translate(ElementKey("elementThatDoesNotExist"), x = 10.dp) - } - }, - ) - } + val state = rule.runOnUiThread { MutableSceneTransitionLayoutStateImpl(SceneA) } val key = MovableElementKey("Foo", contents = setOf(SceneA)) val movableElementChildTag = "movableElementChildTag" diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt index 3b7d661ba91a..d1bd52b56ddd 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt @@ -17,8 +17,6 @@ package com.android.compose.animation.scene import android.util.Log -import androidx.compose.foundation.gestures.Orientation -import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.test.junit4.createComposeRule import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.compose.animation.scene.TestScenes.SceneA @@ -27,7 +25,6 @@ import com.android.compose.animation.scene.TestScenes.SceneC import com.android.compose.animation.scene.content.state.TransitionState import com.android.compose.animation.scene.subjects.assertThat import com.android.compose.animation.scene.transition.seekToScene -import com.android.compose.test.MonotonicClockTestScope import com.android.compose.test.TestSceneTransition import com.android.compose.test.runMonotonicClockTest import com.android.compose.test.transition @@ -166,115 +163,6 @@ class SceneTransitionLayoutStateTest { assertThat(state.currentTransition?.transformationSpec?.transformationMatchers).hasSize(2) } - private fun MonotonicClockTestScope.startOverscrollableTransistionFromAtoB( - progress: () -> Float, - sceneTransitions: SceneTransitions, - ): MutableSceneTransitionLayoutStateImpl { - val state = MutableSceneTransitionLayoutStateImpl(SceneA, sceneTransitions) - state.startTransitionImmediately( - animationScope = backgroundScope, - transition( - from = SceneA, - to = SceneB, - progress = progress, - orientation = Orientation.Vertical, - ), - ) - assertThat(state.isTransitioning()).isTrue() - return state - } - - @Test - fun overscrollDsl_definedForToScene() = runMonotonicClockTest { - val progress = mutableStateOf(0f) - val state = - startOverscrollableTransistionFromAtoB( - progress = { progress.value }, - sceneTransitions = - transitions { - overscroll(SceneB, Orientation.Vertical) { fade(TestElements.Foo) } - }, - ) - val transition = assertThat(state.transitionState).isSceneTransition() - assertThat(transition).hasNoOverscrollSpec() - - // overscroll for SceneA is NOT defined - progress.value = -0.1f - assertThat(transition).hasNoOverscrollSpec() - - // scroll from SceneA to SceneB - progress.value = 0.5f - assertThat(transition).hasNoOverscrollSpec() - - progress.value = 1f - assertThat(transition).hasNoOverscrollSpec() - - // overscroll for SceneB is defined - progress.value = 1.1f - val overscrollSpec = assertThat(transition).hasOverscrollSpec() - assertThat(overscrollSpec.content).isEqualTo(SceneB) - } - - @Test - fun overscrollDsl_definedForFromScene() = runMonotonicClockTest { - val progress = mutableStateOf(0f) - val state = - startOverscrollableTransistionFromAtoB( - progress = { progress.value }, - sceneTransitions = - transitions { - overscroll(SceneA, Orientation.Vertical) { fade(TestElements.Foo) } - }, - ) - - val transition = assertThat(state.transitionState).isSceneTransition() - assertThat(transition).hasNoOverscrollSpec() - - // overscroll for SceneA is defined - progress.value = -0.1f - val overscrollSpec = assertThat(transition).hasOverscrollSpec() - assertThat(overscrollSpec.content).isEqualTo(SceneA) - - // scroll from SceneA to SceneB - progress.value = 0.5f - assertThat(transition).hasNoOverscrollSpec() - - progress.value = 1f - assertThat(transition).hasNoOverscrollSpec() - - // overscroll for SceneB is NOT defined - progress.value = 1.1f - assertThat(transition).hasNoOverscrollSpec() - } - - @Test - fun overscrollDsl_notDefinedScenes() = runMonotonicClockTest { - val progress = mutableStateOf(0f) - val state = - startOverscrollableTransistionFromAtoB( - progress = { progress.value }, - sceneTransitions = transitions {}, - ) - - val transition = assertThat(state.transitionState).isSceneTransition() - assertThat(transition).hasNoOverscrollSpec() - - // overscroll for SceneA is NOT defined - progress.value = -0.1f - assertThat(transition).hasNoOverscrollSpec() - - // scroll from SceneA to SceneB - progress.value = 0.5f - assertThat(transition).hasNoOverscrollSpec() - - progress.value = 1f - assertThat(transition).hasNoOverscrollSpec() - - // overscroll for SceneB is NOT defined - progress.value = 1.1f - assertThat(transition).hasNoOverscrollSpec() - } - @Test fun multipleTransitions() = runTest { val frozenTransitions = mutableSetOf<TestSceneTransition>() diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt index b00b894b5dea..fdbd0f63292a 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt @@ -20,7 +20,6 @@ import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.tween import androidx.compose.foundation.background -import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.offset @@ -28,7 +27,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue @@ -55,13 +53,11 @@ import com.android.compose.animation.scene.TestScenes.SceneB import com.android.compose.animation.scene.TestScenes.SceneC import com.android.compose.animation.scene.subjects.assertThat import com.android.compose.test.assertSizeIsEqualTo -import com.android.compose.test.setContentAndCreateMainScope import com.android.compose.test.subjects.DpOffsetSubject import com.android.compose.test.subjects.assertThat import com.android.compose.test.transition import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.launch import org.junit.Assert.assertThrows import org.junit.Rule import org.junit.Test @@ -311,43 +307,6 @@ class SceneTransitionLayoutTest { } @Test - fun layoutSizeDoesNotOverscrollWhenOverscrollIsSpecified() { - val state = - rule.runOnUiThread { - MutableSceneTransitionLayoutStateImpl( - SceneA, - transitions { overscrollDisabled(SceneB, Orientation.Horizontal) }, - ) - } - - val layoutTag = "layout" - val scope = - rule.setContentAndCreateMainScope { - SceneTransitionLayout(state, Modifier.testTag(layoutTag)) { - scene(SceneA) { Box(Modifier.size(50.dp)) } - scene(SceneB) { Box(Modifier.size(70.dp)) } - } - } - - // Overscroll on A at -100%: size should be interpolated given that there is no overscroll - // defined for scene A. - var progress by mutableStateOf(-1f) - scope.launch { - state.startTransition(transition(from = SceneA, to = SceneB, progress = { progress })) - } - rule.onNodeWithTag(layoutTag).assertSizeIsEqualTo(30.dp) - - // Middle of the transition. - progress = 0.5f - rule.onNodeWithTag(layoutTag).assertSizeIsEqualTo(60.dp) - - // Overscroll on B at 200%: size should not be interpolated given that there is an - // overscroll defined for scene B. - progress = 2f - rule.onNodeWithTag(layoutTag).assertSizeIsEqualTo(70.dp) - } - - @Test fun multipleTransitionsWillComposeMultipleScenes() { val duration = 10 * 16L diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt index fe7b5b6bf4da..9135fdd15b3a 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt @@ -35,9 +35,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.input.nestedscroll.NestedScrollConnection -import androidx.compose.ui.input.nestedscroll.NestedScrollSource -import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.pointer.PointerType import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.platform.LocalViewConfiguration @@ -735,46 +732,6 @@ class SwipeToSceneTest { } @Test - fun overscrollScopeExtendsDensity() { - val swipeDistance = 100.dp - val state = - rule.runOnUiThread { - MutableSceneTransitionLayoutState( - SceneA, - transitions { - from(SceneA, to = SceneB) { distance = FixedDistance(swipeDistance) } - - overscroll(SceneB, Orientation.Vertical) { - progressConverter = ProgressConverter.linear() - translate(TestElements.Foo, x = { 20.dp.toPx() }, y = { 30.dp.toPx() }) - } - }, - ) - } - val layoutSize = 200.dp - var touchSlop = 0f - rule.setContent { - touchSlop = LocalViewConfiguration.current.touchSlop - SceneTransitionLayout(state, Modifier.size(layoutSize)) { - scene(SceneA, userActions = mapOf(Swipe.Down to SceneB)) { - Box(Modifier.fillMaxSize()) - } - scene(SceneB) { Box(Modifier.element(TestElements.Foo).fillMaxSize()) } - } - } - - // Swipe down by twice the swipe distance so that we are at 100% overscrolling on scene B. - rule.onRoot().performTouchInput { - val middle = (layoutSize / 2).toPx() - down(Offset(middle, middle)) - moveBy(Offset(0f, touchSlop + (swipeDistance * 2).toPx()), delayMillis = 1_000) - } - - // Foo should be translated by (20dp, 30dp). - rule.onNode(isElement(TestElements.Foo)).assertPositionInRootIsEqualTo(20.dp, 30.dp) - } - - @Test fun startEnd_ltrLayout() { val state = rule.runOnUiThread { @@ -923,128 +880,6 @@ class SwipeToSceneTest { } @Test - fun whenOverscrollIsDisabled_dragGestureShouldNotBeConsumed() { - val swipeDistance = 100.dp - - var availableOnPostScroll = Float.MIN_VALUE - val connection = - object : NestedScrollConnection { - override fun onPostScroll( - consumed: Offset, - available: Offset, - source: NestedScrollSource, - ): Offset { - availableOnPostScroll = available.y - return super.onPostScroll(consumed, available, source) - } - } - val state = - rule.runOnUiThread { - MutableSceneTransitionLayoutState( - SceneA, - transitions { - from(SceneA, to = SceneB) { distance = FixedDistance(swipeDistance) } - overscrollDisabled(SceneB, Orientation.Vertical) - }, - ) - } - val layoutSize = 200.dp - var touchSlop = 0f - rule.setContent { - touchSlop = LocalViewConfiguration.current.touchSlop - SceneTransitionLayout(state, Modifier.size(layoutSize).nestedScroll(connection)) { - scene(SceneA, userActions = mapOf(Swipe.Down to SceneB)) { - Box(Modifier.fillMaxSize()) - } - scene(SceneB) { Box(Modifier.element(TestElements.Foo).fillMaxSize()) } - } - } - - // Swipe down by the swipe distance so that we are on scene B. - rule.onRoot().performTouchInput { - val middle = (layoutSize / 2).toPx() - down(Offset(middle, middle)) - moveBy(Offset(0f, touchSlop + (swipeDistance).toPx()), delayMillis = 1_000) - } - val transition = state.currentTransition - assertThat(transition).isNotNull() - assertThat(transition!!.progress).isEqualTo(1f) - assertThat(availableOnPostScroll).isEqualTo(0f) - - // Overscrolling on Scene B - val ovescrollPx = 100f - rule.onRoot().performTouchInput { moveBy(Offset(0f, ovescrollPx), delayMillis = 1_000) } - // Overscroll is disabled on Scene B - assertThat(transition.progress).isEqualTo(1f) - assertThat(availableOnPostScroll).isEqualTo(ovescrollPx) - } - - @Test - fun scrollKeepPriorityEvenIfWeCanNoLongerScrollOnThatDirection() { - val swipeDistance = 100.dp - val state = - rule.runOnUiThread { - MutableSceneTransitionLayoutState( - SceneA, - transitions { - from(SceneA, to = SceneB) { distance = FixedDistance(swipeDistance) } - from(SceneB, to = SceneC) { distance = FixedDistance(swipeDistance) } - overscrollDisabled(SceneB, Orientation.Vertical) - }, - ) - } - val layoutSize = 200.dp - var touchSlop = 0f - rule.setContent { - touchSlop = LocalViewConfiguration.current.touchSlop - SceneTransitionLayout(state, Modifier.size(layoutSize)) { - scene(SceneA, userActions = mapOf(Swipe.Down to SceneB, Swipe.Right to SceneC)) { - Box( - Modifier.fillMaxSize() - // A scrollable that does not consume the scroll gesture - .scrollable(rememberScrollableState { 0f }, Orientation.Vertical) - ) - } - scene(SceneB, userActions = mapOf(Swipe.Right to SceneC)) { - Box(Modifier.element(TestElements.Foo).fillMaxSize()) - } - scene(SceneC) { Box(Modifier.fillMaxSize()) } - } - } - - fun assertTransition(from: SceneKey, to: SceneKey, progress: Float) { - val transition = assertThat(state.transitionState).isSceneTransition() - assertThat(transition).hasFromScene(from) - assertThat(transition).hasToScene(to) - assertThat(transition.progress).isEqualTo(progress) - } - - // Vertical scroll 100% - rule.onRoot().performTouchInput { - val middle = (layoutSize / 2).toPx() - down(Offset(middle, middle)) - moveBy(Offset(0f, y = touchSlop + swipeDistance.toPx()), delayMillis = 1_000) - } - assertTransition(from = SceneA, to = SceneB, progress = 1f) - - // Continue vertical scroll, should be ignored (overscrollDisabled) - rule.onRoot().performTouchInput { moveBy(Offset(0f, y = touchSlop), delayMillis = 1_000) } - assertTransition(from = SceneA, to = SceneB, progress = 1f) - - // Horizontal scroll, should be ignored - rule.onRoot().performTouchInput { - moveBy(Offset(x = touchSlop + swipeDistance.toPx(), 0f), delayMillis = 1_000) - } - assertTransition(from = SceneA, to = SceneB, progress = 1f) - - // Vertical scroll, in the opposite direction - rule.onRoot().performTouchInput { - moveBy(Offset(0f, -swipeDistance.toPx()), delayMillis = 1_000) - } - assertTransition(from = SceneA, to = SceneB, progress = 0f) - } - - @Test fun sceneWithoutSwipesDoesNotConsumeGestures() { val buttonTag = "button" diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt index 70f2ff80f9d7..cb87fe849a81 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt @@ -21,7 +21,6 @@ import androidx.compose.animation.core.SpringSpec import androidx.compose.animation.core.TweenSpec import androidx.compose.animation.core.spring import androidx.compose.animation.core.tween -import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.unit.IntSize import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.compose.animation.scene.TestScenes.SceneA @@ -29,7 +28,6 @@ import com.android.compose.animation.scene.TestScenes.SceneB import com.android.compose.animation.scene.TestScenes.SceneC import com.android.compose.animation.scene.content.state.TransitionState import com.android.compose.animation.scene.transformation.CustomPropertyTransformation -import com.android.compose.animation.scene.transformation.OverscrollTranslate import com.android.compose.animation.scene.transformation.PropertyTransformation import com.android.compose.animation.scene.transformation.PropertyTransformationScope import com.android.compose.animation.scene.transformation.TransformationMatcher @@ -308,34 +306,6 @@ class TransitionDslTest { } @Test - fun overscrollSpec() { - val transitions = transitions { - overscroll(SceneA, Orientation.Vertical) { - translate(TestElements.Bar, x = { 1f }, y = { 2f }) - } - } - - val overscrollSpec = transitions.overscrollSpecs.single() - val transformation = - overscrollSpec.transformationSpec.transformationMatchers.single().factory.create() - assertThat(transformation).isInstanceOf(OverscrollTranslate::class.java) - } - - @Test - fun overscrollSpec_for_overscrollDisabled() { - val transitions = transitions { overscrollDisabled(SceneA, Orientation.Vertical) } - val overscrollSpec = transitions.overscrollSpecs.single() - assertThat(overscrollSpec.transformationSpec.transformationMatchers).isEmpty() - } - - @Test - fun overscrollSpec_throwIfTransformationsIsEmpty() { - assertThrows(IllegalStateException::class.java) { - transitions { overscroll(SceneA, Orientation.Vertical) {} } - } - } - - @Test fun transitionIsPassedToBuilder() = runTest { var transitionPassedToBuilder: TransitionState.Transition? = null val state = diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt index 9a2af640c46f..6db98a874787 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt @@ -16,9 +16,7 @@ package com.android.compose.animation.scene.subjects -import com.android.compose.animation.scene.ContentKey import com.android.compose.animation.scene.OverlayKey -import com.android.compose.animation.scene.OverscrollSpec import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.content.state.TransitionState import com.google.common.truth.Fact.simpleFact @@ -156,26 +154,6 @@ abstract class BaseTransitionSubject<T : TransitionState.Transition>( fun hasIsUserInputOngoing(isUserInputOngoing: Boolean) { check("isUserInputOngoing").that(actual.isUserInputOngoing).isEqualTo(isUserInputOngoing) } - - internal fun hasOverscrollSpec(): OverscrollSpec { - check("currentOverscrollSpec").that(actual.currentOverscrollSpec).isNotNull() - return actual.currentOverscrollSpec!! - } - - fun hasNoOverscrollSpec() { - check("currentOverscrollSpec").that(actual.currentOverscrollSpec).isNull() - } - - fun hasBouncingContent(content: ContentKey) { - val actual = actual - if (actual !is TransitionState.DirectionProperties) { - failWithActual(simpleFact("expected to be ContentState.HasOverscrollProperties")) - } - - check("bouncingContent") - .that((actual as TransitionState.DirectionProperties).bouncingContent) - .isEqualTo(content) - } } class SceneTransitionSubject diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt index c8fb2cb8474f..53bb14fec22f 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt @@ -19,7 +19,6 @@ package com.android.compose.nestedscroll import androidx.compose.foundation.gestures.FlingBehavior import androidx.compose.foundation.gestures.ScrollScope import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollSource import com.google.common.truth.Truth.assertThat import org.junit.Test @@ -48,15 +47,6 @@ class LargeTopAppBarNestedScrollConnectionTest(testCase: TestCase) { flingBehavior = customFlingBehavior, ) - private fun NestedScrollConnection.scroll( - available: Offset, - consumedByScroll: Offset = Offset.Zero, - ) { - val consumedByPreScroll = onPreScroll(available = available, source = scrollSource) - val consumed = consumedByPreScroll + consumedByScroll - onPostScroll(consumed = consumed, available = available - consumed, source = scrollSource) - } - @Test fun onScrollUp_consumeHeightFirst() { val scrollConnection = buildScrollConnection(heightRange = 0f..2f) diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestOverlayTransition.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestOverlayTransition.kt index 6015479d8e21..b9d01c2eaa3b 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestOverlayTransition.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestOverlayTransition.kt @@ -16,12 +16,9 @@ package com.android.compose.test -import androidx.compose.foundation.gestures.Orientation -import com.android.compose.animation.scene.ContentKey import com.android.compose.animation.scene.OverlayKey import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.SceneTransitionLayoutImpl -import com.android.compose.animation.scene.content.state.TransitionState import com.android.compose.animation.scene.content.state.TransitionState.Transition import kotlinx.coroutines.CompletableDeferred @@ -63,15 +60,10 @@ fun transition( interruptionProgress: () -> Float = { 0f }, isInitiatedByUserInput: Boolean = false, isUserInputOngoing: Boolean = false, - isUpOrLeft: Boolean = false, - bouncingContent: ContentKey? = null, - orientation: Orientation = Orientation.Horizontal, onFreezeAndAnimate: ((TestOverlayTransition) -> Unit)? = null, replacedTransition: Transition? = null, ): TestOverlayTransition { - return object : - TestOverlayTransition(fromScene, overlay, replacedTransition), - TransitionState.DirectionProperties { + return object : TestOverlayTransition(fromScene, overlay, replacedTransition) { override val isEffectivelyShown: Boolean get() = isEffectivelyShown() @@ -92,10 +84,6 @@ fun transition( override val isInitiatedByUserInput: Boolean = isInitiatedByUserInput override val isUserInputOngoing: Boolean = isUserInputOngoing - override val isUpOrLeft: Boolean = isUpOrLeft - override val bouncingContent: ContentKey? = bouncingContent - override val orientation: Orientation = orientation - override val absoluteDistance = 0f override fun freezeAndAnimateToCurrentState() { if (onFreezeAndAnimate != null) { diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestReplaceOverlayTransition.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestReplaceOverlayTransition.kt index bd2118dd8395..983c429aa58e 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestReplaceOverlayTransition.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestReplaceOverlayTransition.kt @@ -16,11 +16,8 @@ package com.android.compose.test -import androidx.compose.foundation.gestures.Orientation -import com.android.compose.animation.scene.ContentKey import com.android.compose.animation.scene.OverlayKey import com.android.compose.animation.scene.SceneTransitionLayoutImpl -import com.android.compose.animation.scene.content.state.TransitionState import com.android.compose.animation.scene.content.state.TransitionState.Transition import kotlinx.coroutines.CompletableDeferred @@ -60,15 +57,10 @@ fun transition( interruptionProgress: () -> Float = { 0f }, isInitiatedByUserInput: Boolean = false, isUserInputOngoing: Boolean = false, - isUpOrLeft: Boolean = false, - bouncingContent: ContentKey? = null, - orientation: Orientation = Orientation.Horizontal, onFreezeAndAnimate: ((TestReplaceOverlayTransition) -> Unit)? = null, replacedTransition: Transition? = null, ): TestReplaceOverlayTransition { - return object : - TestReplaceOverlayTransition(from, to, replacedTransition), - TransitionState.DirectionProperties { + return object : TestReplaceOverlayTransition(from, to, replacedTransition) { override val effectivelyShownOverlay: OverlayKey get() = effectivelyShownOverlay() @@ -89,10 +81,6 @@ fun transition( override val isInitiatedByUserInput: Boolean = isInitiatedByUserInput override val isUserInputOngoing: Boolean = isUserInputOngoing - override val isUpOrLeft: Boolean = isUpOrLeft - override val bouncingContent: ContentKey? = bouncingContent - override val orientation: Orientation = orientation - override val absoluteDistance = 0f override fun freezeAndAnimateToCurrentState() { if (onFreezeAndAnimate != null) { diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestSceneTransition.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestSceneTransition.kt index 1d27e3a3f191..d11951ee4b24 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestSceneTransition.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestSceneTransition.kt @@ -16,11 +16,8 @@ package com.android.compose.test -import androidx.compose.foundation.gestures.Orientation -import com.android.compose.animation.scene.ContentKey import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.SceneTransitionLayoutImpl -import com.android.compose.animation.scene.content.state.TransitionState import com.android.compose.animation.scene.content.state.TransitionState.Transition import kotlinx.coroutines.CompletableDeferred @@ -55,14 +52,10 @@ fun transition( interruptionProgress: () -> Float = { 0f }, isInitiatedByUserInput: Boolean = false, isUserInputOngoing: Boolean = false, - isUpOrLeft: Boolean = false, - bouncingContent: ContentKey? = null, - orientation: Orientation = Orientation.Horizontal, onFreezeAndAnimate: ((TestSceneTransition) -> Unit)? = null, replacedTransition: Transition? = null, ): TestSceneTransition { - return object : - TestSceneTransition(from, to, replacedTransition), TransitionState.DirectionProperties { + return object : TestSceneTransition(from, to, replacedTransition) { override val currentScene: SceneKey get() = current() @@ -83,10 +76,6 @@ fun transition( override val isInitiatedByUserInput: Boolean = isInitiatedByUserInput override val isUserInputOngoing: Boolean = isUserInputOngoing - override val isUpOrLeft: Boolean = isUpOrLeft - override val bouncingContent: ContentKey? = bouncingContent - override val orientation: Orientation = orientation - override val absoluteDistance = 0f override fun freezeAndAnimateToCurrentState() { if (onFreezeAndAnimate != null) { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/external/TileServiceRequestControllerTestComposeOn.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/external/TileServiceRequestControllerTestComposeOn.kt index f02856c2f5ae..f48027beef12 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/external/TileServiceRequestControllerTestComposeOn.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/external/TileServiceRequestControllerTestComposeOn.kt @@ -148,7 +148,7 @@ class TileServiceRequestControllerTestComposeOn : SysuiTestCase() { @Test fun showAllUsers_set() = kosmos.runTest { - val dialog = runOnMainThreadAndWaitForIdleSync { + val dialog = createDialog { underTest.requestTileAdd( TEST_UID, TEST_COMPONENT, @@ -158,7 +158,6 @@ class TileServiceRequestControllerTestComposeOn : SysuiTestCase() { Callback(), )!! } - onTeardown { dialog.cancel() } assertThat(dialog.isShowForAllUsers).isTrue() } @@ -166,7 +165,7 @@ class TileServiceRequestControllerTestComposeOn : SysuiTestCase() { @Test fun cancelOnTouchOutside_set() = kosmos.runTest { - val dialog = runOnMainThreadAndWaitForIdleSync { + val dialog = createDialog { underTest.requestTileAdd( TEST_UID, TEST_COMPONENT, @@ -176,11 +175,16 @@ class TileServiceRequestControllerTestComposeOn : SysuiTestCase() { Callback(), )!! } - onTeardown { dialog.cancel() } assertThat(dialog.isCancelOnTouchOutside).isTrue() } + fun <T : DialogInterface> createDialog(constructor: () -> T): T { + val dialog = runOnMainThreadAndWaitForIdleSync { constructor() } + onTeardown { runOnMainThreadAndWaitForIdleSync { dialog.cancel() } } + return dialog + } + @Test fun positiveAction_tileAdded() = kosmos.runTest { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTrackerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTrackerTest.kt new file mode 100644 index 000000000000..56356b4489f8 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTrackerTest.kt @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.shade + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.internal.logging.latencyTracker +import com.android.systemui.SysuiTestCase +import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository +import com.android.systemui.common.ui.view.fakeChoreographerUtils +import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.testKosmos +import kotlin.test.Test +import kotlin.time.Duration.Companion.seconds +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.advanceTimeBy +import kotlinx.coroutines.test.runTest +import org.junit.runner.RunWith +import org.mockito.Mockito.never +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.mockito.kotlin.any + +@SmallTest +@RunWith(AndroidJUnit4::class) +class ShadeDisplayChangeLatencyTrackerTest : SysuiTestCase() { + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + private val configurationRepository = kosmos.fakeConfigurationRepository + private val latencyTracker = kosmos.latencyTracker + private val testScope = kosmos.testScope + private val choreographerUtils = kosmos.fakeChoreographerUtils + + private val underTest = kosmos.shadeDisplayChangeLatencyTracker + + @Test + fun onShadeDisplayChanging_afterMovedToDisplayAndDoFrameCompleted_atomReported() = + testScope.runTest { + underTest.onShadeDisplayChanging(1) + + verify(latencyTracker).onActionStart(any()) + verify(latencyTracker, never()).onActionEnd(any()) + + sendOnMovedToDisplay(1) + choreographerUtils.completeDoFrame() + + verify(latencyTracker).onActionEnd(any()) + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun onChange_doFrameTimesOut_previousCancelled() = + testScope.runTest { + underTest.onShadeDisplayChanging(1) + + verify(latencyTracker).onActionStart(any()) + verify(latencyTracker, never()).onActionEnd(any()) + + sendOnMovedToDisplay(1) + advanceTimeBy(100.seconds) + + verify(latencyTracker, never()).onActionEnd(any()) + verify(latencyTracker).onActionCancel(any()) + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun onChange_onMovedToDisplayTimesOut_cancelled() = + testScope.runTest { + underTest.onShadeDisplayChanging(1) + + verify(latencyTracker).onActionStart(any()) + + choreographerUtils.completeDoFrame() + advanceTimeBy(100.seconds) + + verify(latencyTracker).onActionCancel(any()) + } + + @Test + fun onChange_whilePreviousWasInProgress_previousCancelledAndNewStarted() = + testScope.runTest { + underTest.onShadeDisplayChanging(1) + + verify(latencyTracker).onActionStart(any()) + + underTest.onShadeDisplayChanging(2) + + verify(latencyTracker).onActionCancel(any()) + verify(latencyTracker, times(2)).onActionStart(any()) + } + + @Test + fun onChange_multiple_multipleReported() = + testScope.runTest { + underTest.onShadeDisplayChanging(1) + verify(latencyTracker).onActionStart(any()) + + sendOnMovedToDisplay(1) + choreographerUtils.completeDoFrame() + + verify(latencyTracker).onActionEnd(any()) + + underTest.onShadeDisplayChanging(0) + + sendOnMovedToDisplay(0) + choreographerUtils.completeDoFrame() + + verify(latencyTracker, times(2)).onActionStart(any()) + verify(latencyTracker, times(2)).onActionEnd(any()) + } + + private fun sendOnMovedToDisplay(displayId: Int) { + configurationRepository.onMovedToDisplay(displayId) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt index e93d0effe742..a98d1a2ea4a5 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt @@ -45,6 +45,7 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() { private val positionRepository = kosmos.fakeShadeDisplaysRepository private val shadeContext = kosmos.mockedWindowContext private val resources = kosmos.mockResources + private val latencyTracker = kosmos.mockedShadeDisplayChangeLatencyTracker private val configuration = mock<Configuration>() private val display = mock<Display>() @@ -81,4 +82,14 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() { verify(shadeContext).reparentToDisplay(eq(1)) } + + @Test + fun start_shadeInWrongPosition_logsStartToLatencyTracker() { + whenever(display.displayId).thenReturn(0) + positionRepository.setDisplayId(1) + + underTest.start() + + verify(latencyTracker).onShadeDisplayChanging(eq(1)) + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/QuickStepContractTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/QuickStepContractTest.kt index ef03fab95778..d92781a5f3ce 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/QuickStepContractTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/QuickStepContractTest.kt @@ -16,8 +16,10 @@ package com.android.systemui.shared.system +import android.platform.test.annotations.DisableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_BACK_ACTION import com.android.systemui.SysuiTestCase import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_COMMUNAL_HUB_SHOWING @@ -30,6 +32,7 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class QuickStepContractTest : SysuiTestCase() { @Test + @DisableFlags(FLAG_GLANCEABLE_HUB_BACK_ACTION) fun isBackGestureDisabled_hubShowing() { val sysuiStateFlags = SYSUI_STATE_COMMUNAL_HUB_SHOWING diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/domain/interactor/MediaControlChipInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/domain/interactor/MediaControlChipInteractorTest.kt new file mode 100644 index 000000000000..dd81b75e180e --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/domain/interactor/MediaControlChipInteractorTest.kt @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.featurepods.media.domain.interactor + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.media.controls.data.repository.mediaFilterRepository +import com.android.systemui.media.controls.shared.model.MediaData +import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class MediaControlChipInteractorTest : SysuiTestCase() { + + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + private val underTest = kosmos.mediaControlChipInteractor + + @Test + fun mediaControlModel_noActiveMedia_null() = + kosmos.runTest { + val model by collectLastValue(underTest.mediaControlModel) + + assertThat(model).isNull() + } + + @Test + fun mediaControlModel_activeMedia_notNull() = + kosmos.runTest { + val model by collectLastValue(underTest.mediaControlModel) + + val userMedia = MediaData(active = true) + val instanceId = userMedia.instanceId + + mediaFilterRepository.addSelectedUserMediaEntry(userMedia) + mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId)) + + assertThat(model).isNotNull() + } + + @Test + fun mediaControlModel_mediaRemoved_null() = + kosmos.runTest { + val model by collectLastValue(underTest.mediaControlModel) + + val userMedia = MediaData(active = true) + val instanceId = userMedia.instanceId + + mediaFilterRepository.addSelectedUserMediaEntry(userMedia) + mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId)) + + assertThat(model).isNotNull() + + assertThat(mediaFilterRepository.removeSelectedUserMediaEntry(instanceId, userMedia)) + .isTrue() + mediaFilterRepository.addMediaDataLoadingState( + MediaDataLoadingModel.Removed(instanceId) + ) + + assertThat(model).isNull() + } + + @Test + fun mediaControlModel_songNameChanged_emitsUpdatedModel() = + kosmos.runTest { + val model by collectLastValue(underTest.mediaControlModel) + + val initialSongName = "Initial Song" + val newSongName = "New Song" + val userMedia = MediaData(active = true, song = initialSongName) + val instanceId = userMedia.instanceId + + mediaFilterRepository.addSelectedUserMediaEntry(userMedia) + mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId)) + + assertThat(model).isNotNull() + assertThat(model?.songName).isEqualTo(initialSongName) + + val updatedUserMedia = userMedia.copy(song = newSongName) + mediaFilterRepository.addSelectedUserMediaEntry(updatedUserMedia) + + assertThat(model?.songName).isEqualTo(newSongName) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt index 3359db0a22e6..26c6eb5dc47a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt @@ -20,6 +20,7 @@ import android.app.Notification import android.app.Notification.BigPictureStyle import android.app.Notification.BigTextStyle import android.app.Notification.CallStyle +import android.app.Notification.FLAG_PROMOTED_ONGOING import android.app.Notification.MessagingStyle import android.app.Notification.ProgressStyle import android.app.Notification.ProgressStyle.Segment @@ -46,9 +47,6 @@ import org.junit.runner.RunWith class PromotedNotificationContentExtractorImplTest : SysuiTestCase() { private val kosmos = testKosmos() - private val provider = - FakePromotedNotificationsProvider().also { kosmos.promotedNotificationsProvider = it } - private val underTest = kosmos.promotedNotificationContentExtractor @Test @@ -87,7 +85,7 @@ class PromotedNotificationContentExtractorImplTest : SysuiTestCase() { @Test @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) - fun shouldNotExtract_providerDidNotPromote() { + fun shouldNotExtract_becauseNotPromoted() { val entry = createEntry(promoted = false) val content = extractContent(entry) assertThat(content).isNull() @@ -231,9 +229,10 @@ class PromotedNotificationContentExtractorImplTest : SysuiTestCase() { builderBlock: Notification.Builder.() -> Unit = {}, ): NotificationEntry { val notif = Notification.Builder(context, "channel").also(builderBlock).build() - return NotificationEntryBuilder().setNotification(notif).build().also { - provider.shouldPromoteForEntry[it] = promoted + if (promoted) { + notif.flags = FLAG_PROMOTED_ONGOING } + return NotificationEntryBuilder().setNotification(notif).build() } companion object { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationsProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationsProviderTest.kt deleted file mode 100644 index a9dbe63e8f07..000000000000 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationsProviderTest.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.notification.promoted - -import android.app.Notification -import android.app.Notification.FLAG_PROMOTED_ONGOING -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags -import androidx.test.filters.SmallTest -import com.android.systemui.SysuiTestCase -import com.android.systemui.statusbar.notification.collection.NotificationEntry -import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder -import com.android.systemui.testKosmos -import com.google.common.truth.Truth.assertThat -import kotlin.test.Test - -@SmallTest -class PromotedNotificationsProviderTest : SysuiTestCase() { - private val kosmos = testKosmos() - - private val underTest = kosmos.promotedNotificationsProvider - - @Test - @DisableFlags(PromotedNotificationUi.FLAG_NAME) - fun shouldPromote_uiFlagOff_false() { - val entry = createNotification(FLAG_PROMOTED_ONGOING) - - assertThat(underTest.shouldPromote(entry)).isFalse() - } - - @Test - @EnableFlags(PromotedNotificationUi.FLAG_NAME) - fun shouldPromote_uiFlagOn_notifDoesNotHaveFlag_false() { - val entry = createNotification(flag = null) - - assertThat(underTest.shouldPromote(entry)).isFalse() - } - - @Test - @EnableFlags(PromotedNotificationUi.FLAG_NAME) - fun shouldPromote_uiFlagOn_notifHasFlag_true() { - val entry = createNotification(FLAG_PROMOTED_ONGOING) - - assertThat(underTest.shouldPromote(entry)).isTrue() - } - - private fun createNotification(flag: Int? = null): NotificationEntry { - val n = Notification.Builder(context, "a") - if (flag != null) { - n.setFlag(flag, true) - } - - return NotificationEntryBuilder().setNotification(n.build()).build() - } -} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt index 83600422bda4..e1589b6ad4bd 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt @@ -219,6 +219,7 @@ class PhoneStatusBarPolicyTest : SysuiTestCase() { @Test fun testAppTransitionFinished_doesNotShowManagedProfileIcon() { + whenever(userManager.isProfile(anyInt())).thenReturn(true) whenever(userManager.getUserStatusBarIconResId(anyInt())).thenReturn(0 /* ID_NULL */) whenever(keyguardStateController.isShowing).thenReturn(false) statusBarPolicy.appTransitionFinished(0) @@ -232,6 +233,7 @@ class PhoneStatusBarPolicyTest : SysuiTestCase() { @Test fun testAppTransitionFinished_showsManagedProfileIcon() { + whenever(userManager.isProfile(anyInt())).thenReturn(true) whenever(userManager.getUserStatusBarIconResId(anyInt())).thenReturn(100) whenever(keyguardStateController.isShowing).thenReturn(false) statusBarPolicy.appTransitionFinished(0) diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/ChoreographerUtils.kt b/packages/SystemUI/src/com/android/systemui/common/ui/view/ChoreographerUtils.kt new file mode 100644 index 000000000000..cc7a7bfda58e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/ChoreographerUtils.kt @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.common.ui.view + +import android.view.Choreographer +import android.view.View +import com.android.app.tracing.coroutines.TrackTracer +import kotlin.coroutines.resume +import kotlinx.coroutines.suspendCancellableCoroutine + +/** utilities related to [Choreographer]. */ +interface ChoreographerUtils { + /** + * Waits until the next [view] doFrame is completed. + * + * Note that this is expected to work properly when called from any thread. If called during a + * doFrame, it waits for the next one to be completed. + * + * This differs from [kotlinx.coroutines.android.awaitFrame] as it uses + * [Handler.postAtFrontOfQueue] instead of [Handler.post] when called from a thread different + * than the UI thread for that view. Using [Handler.post] might lead to posting the runnable + * after a few frame, effectively missing the "next do frame". + */ + suspend fun waitUntilNextDoFrameDone(view: View) +} + +object ChoreographerUtilsImpl : ChoreographerUtils { + private val t = TrackTracer("ChoreographerUtils") + + override suspend fun waitUntilNextDoFrameDone(view: View) { + t.traceAsync("waitUntilNextDoFrameDone") { waitUntilNextDoFrameDoneTraced(view) } + } + + suspend fun waitUntilNextDoFrameDoneTraced(view: View) { + suspendCancellableCoroutine { cont -> + val frameCallback = + Choreographer.FrameCallback { + t.instant { "We're in doFrame, waiting for it to end." } + view.handler.postAtFrontOfQueue { + t.instant { "DoFrame ended." } + cont.resume(Unit) + } + } + view.runOnUiThreadUrgently { + t.instant { "Waiting for next doFrame" } + val choreographer = Choreographer.getInstance() + cont.invokeOnCancellation { choreographer.removeFrameCallback(frameCallback) } + choreographer.postFrameCallback(frameCallback) + } + } + } + + /** + * Execute [r] on the view UI thread, taking priority over everything else scheduled there. Runs + * directly if we're already in the correct thread. + */ + private fun View.runOnUiThreadUrgently(r: () -> Unit) { + if (handler.looper.isCurrentThread) { + r() + } else { + handler.postAtFrontOfQueue(r) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/FakeChoreographerUtils.kt b/packages/SystemUI/src/com/android/systemui/common/ui/view/FakeChoreographerUtils.kt new file mode 100644 index 000000000000..2f097b1a9279 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/FakeChoreographerUtils.kt @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.common.ui.view + +import android.view.View +import kotlinx.coroutines.CompletableDeferred + +class FakeChoreographerUtils : ChoreographerUtils { + + private var pendingDeferred: CompletableDeferred<Unit>? = null + + override suspend fun waitUntilNextDoFrameDone(view: View) { + getDeferred().await() + clearDeferred() + } + + /** + * Called from tests when it's time to complete the doFrame. It works also if it's called before + * [waitUntilNextDoFrameDone]. + */ + fun completeDoFrame() { + getDeferred().complete(Unit) + } + + @Synchronized + private fun getDeferred(): CompletableDeferred<Unit> { + if (pendingDeferred == null) { + pendingDeferred = CompletableDeferred() + } + return pendingDeferred!! + } + + @Synchronized + private fun clearDeferred() { + pendingDeferred = null + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt index 0d9474e07ce7..85306e67994c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt @@ -37,6 +37,7 @@ import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDoz import com.android.systemui.keyguard.shared.model.DozeTransitionModel import com.android.systemui.keyguard.shared.model.Edge import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER import com.android.systemui.keyguard.shared.model.KeyguardState.AOD import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB @@ -93,6 +94,8 @@ constructor( private val fromGoneTransitionInteractor: Provider<FromGoneTransitionInteractor>, private val fromLockscreenTransitionInteractor: Provider<FromLockscreenTransitionInteractor>, private val fromOccludedTransitionInteractor: Provider<FromOccludedTransitionInteractor>, + private val fromAlternateBouncerTransitionInteractor: + Provider<FromAlternateBouncerTransitionInteractor>, @Application applicationScope: CoroutineScope, ) { // TODO(b/296118689): move to a repository @@ -526,6 +529,8 @@ constructor( when (keyguardTransitionInteractor.transitionState.value.to) { LOCKSCREEN -> fromLockscreenTransitionInteractor.get().dismissKeyguard() OCCLUDED -> fromOccludedTransitionInteractor.get().dismissFromOccluded() + ALTERNATE_BOUNCER -> + fromAlternateBouncerTransitionInteractor.get().dismissAlternateBouncer() else -> Log.v(TAG, "Keyguard was dismissed, no direct transition call needed") } } diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt index bbb13d5c1dfe..e1631ccdcb06 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt +++ b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt @@ -61,17 +61,8 @@ interface UserTracker : UserContentResolverProvider, UserContextProvider { /** Callback for notifying of changes. */ @WeaklyReferencedCallback interface Callback { - /** - * Same as {@link onBeforeUserSwitching(Int, Runnable)} but the callback will be called - * automatically after the completion of this method. - */ - fun onBeforeUserSwitching(newUser: Int) {} - /** Notifies that the current user will be changed. */ - fun onBeforeUserSwitching(newUser: Int, resultCallback: Runnable) { - onBeforeUserSwitching(newUser) - resultCallback.run() - } + fun onBeforeUserSwitching(newUser: Int) {} /** * Same as {@link onUserChanging(Int, Context, Runnable)} but the callback will be called diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt index 42d83637ec1a..b7a3aedc565e 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt @@ -196,9 +196,8 @@ internal constructor( private fun registerUserSwitchObserver() { iActivityManager.registerUserSwitchObserver( object : UserSwitchObserver() { - override fun onBeforeUserSwitching(newUserId: Int, reply: IRemoteCallback?) { + override fun onBeforeUserSwitching(newUserId: Int) { handleBeforeUserSwitching(newUserId) - reply?.sendResult(null) } override fun onUserSwitching(newUserId: Int, reply: IRemoteCallback?) { @@ -237,7 +236,8 @@ internal constructor( setUserIdInternal(newUserId) notifySubscribers { callback, resultCallback -> - callback.onBeforeUserSwitching(newUserId, resultCallback) + callback.onBeforeUserSwitching(newUserId) + resultCallback.run() } .await() } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java index 69b3cc8cf4f4..e4cd7ea098af 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java @@ -27,6 +27,7 @@ import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Rect; import android.graphics.Region; +import android.os.IBinder; import android.os.RemoteException; import android.os.Trace; import android.os.UserHandle; @@ -252,6 +253,19 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW if (mCurrentState.shadeOrQsExpanded != isExpanded) { mCurrentState.shadeOrQsExpanded = isExpanded; apply(mCurrentState); + + final IBinder token; + if (com.android.window.flags.Flags.schedulingForNotificationShade() + && (token = mWindowRootView.getWindowToken()) != null) { + mBackgroundExecutor.execute(() -> { + try { + WindowManagerGlobal.getWindowManagerService() + .onNotificationShadeExpanded(token, isExpanded); + } catch (RemoteException e) { + Log.e(TAG, "Failed to call onNotificationShadeExpanded", e); + } + }); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt index 61b9f0819f56..63e8ba8f65cd 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt @@ -30,6 +30,8 @@ import com.android.systemui.common.ui.data.repository.ConfigurationRepository import com.android.systemui.common.ui.data.repository.ConfigurationRepositoryImpl import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractorImpl +import com.android.systemui.common.ui.view.ChoreographerUtils +import com.android.systemui.common.ui.view.ChoreographerUtilsImpl import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.res.R @@ -260,6 +262,12 @@ object ShadeDisplayAwareModule { } } + /** + * Provided for making classes easier to test. In tests, a custom method to wait for the next + * frame can be easily provided. + */ + @Provides fun provideChoreographerUtils(): ChoreographerUtils = ChoreographerUtilsImpl + @Provides @ShadeOnDefaultDisplayWhenLocked fun provideShadeOnDefaultDisplayWhenLocked(): Boolean = true diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTracker.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTracker.kt new file mode 100644 index 000000000000..4d35d0eba178 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTracker.kt @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.shade + +import android.util.Log +import android.view.Display +import com.android.app.tracing.coroutines.TrackTracer +import com.android.internal.util.LatencyTracker +import com.android.systemui.common.ui.data.repository.ConfigurationRepository +import com.android.systemui.common.ui.view.ChoreographerUtils +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.scene.ui.view.WindowRootView +import com.android.systemui.shade.ShadeDisplayChangeLatencyTracker.Companion.TIMEOUT +import com.android.systemui.shade.data.repository.ShadeDisplaysRepository +import com.android.systemui.util.kotlin.getOrNull +import java.util.Optional +import java.util.concurrent.CancellationException +import javax.inject.Inject +import kotlin.time.Duration.Companion.seconds +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch +import kotlinx.coroutines.withTimeout + +/** + * Tracks the time it takes to move the shade from one display to another. + * - The start event is when [ShadeDisplaysRepository] propagates the new display ID. + * - The end event is one frame after the shade configuration controller receives a new + * configuration change. + * + * Note that even in the unlikely case the configuration of the new display is the same, + * onConfigurationChange is called anyway as is is triggered by + * [NotificationShadeWindowView.onMovedToDisplay]. + */ +@SysUISingleton +class ShadeDisplayChangeLatencyTracker +@Inject +constructor( + optionalShadeRootView: Optional<WindowRootView>, + @ShadeDisplayAware private val configurationRepository: ConfigurationRepository, + private val latencyTracker: LatencyTracker, + @Background private val bgScope: CoroutineScope, + private val choreographerUtils: ChoreographerUtils, +) { + + private val shadeRootView = + optionalShadeRootView.getOrNull() + ?: error( + """ + ShadeRootView must be provided for ShadeDisplayChangeLatencyTracker to work. + If it is not, it means this is being instantiated in a SystemUI variant that shouldn't. + """ + .trimIndent() + ) + /** + * We need to keep this always up to date eagerly to avoid delays receiving the new display ID. + */ + private val onMovedToDisplayFlow: StateFlow<Int> = + configurationRepository.onMovedToDisplay.stateIn( + bgScope, + SharingStarted.Eagerly, + Display.DEFAULT_DISPLAY, + ) + + private var previousJob: Job? = null + + /** + * Called before the display change begins. + * + * It is guaranteed that context and resources are still associated to the "old" display id, and + * that onMovedToDisplay has not been received yet on the notification shade window root view. + * + * IMPORTANT: this shouldn't be refactored to use [ShadePositionRepository], otherwise there is + * no guarantees of event order (as the shade could be reparented before the event is propagated + * to this class, breaking the assumption that [onMovedToDisplayFlow] didn't emit with the new + * display id yet. + */ + @Synchronized + fun onShadeDisplayChanging(displayId: Int) { + previousJob?.cancel(CancellationException("New shade move in progress")) + previousJob = bgScope.launch { onShadeDisplayChangingAsync(displayId) } + } + + private suspend fun onShadeDisplayChangingAsync(displayId: Int) { + try { + latencyTracker.onActionStart(SHADE_MOVE_ACTION) + waitForOnMovedToDisplayDispatchedToView(displayId) + waitUntilNextDoFrameDone() + latencyTracker.onActionEnd(SHADE_MOVE_ACTION) + } catch (e: Exception) { + val reason = + when (e) { + is CancellationException -> + "Shade move cancelled as a new move is being done " + + "before the previous one finished." + + else -> "Shade move cancelled." + } + Log.e(TAG, reason, e) + latencyTracker.onActionCancel(SHADE_MOVE_ACTION) + } + } + + private suspend fun waitForOnMovedToDisplayDispatchedToView(newDisplayId: Int) { + t.traceAsync({ "waitForOnMovedToDisplayDispatchedToView(newDisplayId=$newDisplayId)" }) { + withTimeout(TIMEOUT) { onMovedToDisplayFlow.filter { it == newDisplayId }.first() } + t.instant { "onMovedToDisplay received with $newDisplayId" } + } + } + + private suspend fun waitUntilNextDoFrameDone(): Unit = + t.traceAsync("waitUntilNextDoFrameDone") { + withTimeout(TIMEOUT) { choreographerUtils.waitUntilNextDoFrameDone(shadeRootView) } + } + + private companion object { + const val TAG = "ShadeDisplayLatency" + val t = TrackTracer(trackName = TAG) + val TIMEOUT = 3.seconds + const val SHADE_MOVE_ACTION = LatencyTracker.ACTION_SHADE_WINDOW_DISPLAY_CHANGE + } +} diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeTraceLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeTraceLogger.kt index 45161331c0d9..a36c56eafbfc 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeTraceLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeTraceLogger.kt @@ -17,45 +17,35 @@ package com.android.systemui.shade import android.content.res.Configuration -import android.os.Trace -import com.android.app.tracing.TraceUtils.traceAsync +import com.android.app.tracing.coroutines.TrackTracer /** * Centralized logging for shade-related events to a dedicated Perfetto track. * - * Used by shade components to log events to a track named [TAG]. This consolidates shade-specific - * events into a single track for easier analysis in Perfetto, rather than scattering them across - * various threads' logs. + * Used by shade components to log events to a track named [TRACK_NAME]. This consolidates + * shade-specific events into a single track for easier analysis in Perfetto, rather than scattering + * them across various threads' logs. */ object ShadeTraceLogger { - private const val TAG = "ShadeTraceLogger" + private val t = TrackTracer(trackName = "ShadeTraceLogger") @JvmStatic fun logOnMovedToDisplay(displayId: Int, config: Configuration) { - if (!Trace.isEnabled()) return - Trace.instantForTrack( - Trace.TRACE_TAG_APP, - TAG, - "onMovedToDisplay(displayId=$displayId, dpi=" + config.densityDpi + ")", - ) + t.instant { "onMovedToDisplay(displayId=$displayId, dpi=${config.densityDpi})" } } @JvmStatic fun logOnConfigChanged(config: Configuration) { - if (!Trace.isEnabled()) return - Trace.instantForTrack( - Trace.TRACE_TAG_APP, - TAG, - "onConfigurationChanged(dpi=" + config.densityDpi + ")", - ) + t.instant { "onConfigurationChanged(dpi=${config.densityDpi})" } } + @JvmStatic fun logMoveShadeWindowTo(displayId: Int) { - if (!Trace.isEnabled()) return - Trace.instantForTrack(Trace.TRACE_TAG_APP, TAG, "moveShadeWindowTo(displayId=$displayId)") + t.instant { "moveShadeWindowTo(displayId=$displayId)" } } + @JvmStatic fun traceReparenting(r: () -> Unit) { - traceAsync(TAG, { "reparenting" }) { r() } + t.traceAsync({ "reparenting" }) { r() } } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt index 8d536accaf76..be561b178136 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt @@ -25,14 +25,13 @@ import com.android.systemui.CoreStartable import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.scene.ui.view.WindowRootView import com.android.systemui.shade.ShadeDisplayAware +import com.android.systemui.shade.ShadeDisplayChangeLatencyTracker import com.android.systemui.shade.ShadeTraceLogger.logMoveShadeWindowTo import com.android.systemui.shade.ShadeTraceLogger.traceReparenting import com.android.systemui.shade.data.repository.ShadeDisplaysRepository import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround -import com.android.systemui.util.kotlin.getOrNull -import java.util.Optional +import com.android.window.flags.Flags import javax.inject.Inject import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CoroutineScope @@ -43,23 +42,13 @@ import kotlinx.coroutines.withContext class ShadeDisplaysInteractor @Inject constructor( - optionalShadeRootView: Optional<WindowRootView>, private val shadePositionRepository: ShadeDisplaysRepository, @ShadeDisplayAware private val shadeContext: WindowContext, @Background private val bgScope: CoroutineScope, @Main private val mainThreadContext: CoroutineContext, + private val shadeDisplayChangeLatencyTracker: ShadeDisplayChangeLatencyTracker, ) : CoreStartable { - private val shadeRootView = - optionalShadeRootView.getOrNull() - ?: error( - """ - ShadeRootView must be provided for this ShadeDisplayInteractor to work. - If it is not, it means this is being instantiated in a SystemUI variant that shouldn't. - """ - .trimIndent() - ) - override fun start() { ShadeWindowGoesAround.isUnexpectedlyInLegacyMode() bgScope.launchTraced(TAG) { @@ -87,7 +76,11 @@ constructor( } try { withContext(mainThreadContext) { - traceReparenting { reparentToDisplayId(id = destinationId) } + traceReparenting { + shadeDisplayChangeLatencyTracker.onShadeDisplayChanging(destinationId) + reparentToDisplayId(id = destinationId) + } + checkContextDisplayMatchesExpected(destinationId) } } catch (e: IllegalStateException) { Log.e( @@ -98,6 +91,18 @@ constructor( } } + private fun checkContextDisplayMatchesExpected(destinationId: Int) { + if (shadeContext.displayId != destinationId) { + Log.wtf( + TAG, + "Shade context display id doesn't match the expected one after the move. " + + "actual=${shadeContext.displayId} expected=$destinationId. " + + "This means something wrong happened while trying to move the shade. " + + "Flag reparentWindowTokenApi=${Flags.reparentWindowTokenApi()}", + ) + } + } + @UiThread private fun reparentToDisplayId(id: Int) { traceSection({ "reparentToDisplayId(id=$id)" }) { shadeContext.reparentToDisplay(id) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/domain/interactor/MediaControlChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/domain/interactor/MediaControlChipInteractor.kt new file mode 100644 index 000000000000..85c67f5b55a2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/domain/interactor/MediaControlChipInteractor.kt @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.featurepods.media.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.media.controls.data.repository.MediaFilterRepository +import com.android.systemui.media.controls.shared.model.MediaCommonModel +import com.android.systemui.media.controls.shared.model.MediaData +import com.android.systemui.statusbar.featurepods.media.shared.model.MediaControlChipModel +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn + +/** + * Interactor for managing the state of the media control chip in the status bar. + * + * Provides a [StateFlow] of [MediaControlChipModel] representing the current state of the media + * control chip. Emits a new [MediaControlChipModel] when there is an active media session and the + * corresponding user preference is found, otherwise emits null. + */ +@SysUISingleton +class MediaControlChipInteractor +@Inject +constructor( + @Background private val applicationScope: CoroutineScope, + mediaFilterRepository: MediaFilterRepository, +) { + private val currentMediaControls: StateFlow<List<MediaCommonModel.MediaControl>> = + mediaFilterRepository.currentMedia + .map { mediaList -> mediaList.filterIsInstance<MediaCommonModel.MediaControl>() } + .stateIn( + scope = applicationScope, + started = SharingStarted.WhileSubscribed(), + initialValue = emptyList(), + ) + + /** The currently active [MediaControlChipModel] */ + val mediaControlModel: StateFlow<MediaControlChipModel?> = + combine(currentMediaControls, mediaFilterRepository.selectedUserEntries) { + mediaControls, + userEntries -> + mediaControls + .mapNotNull { userEntries[it.mediaLoadedModel.instanceId] } + .firstOrNull { it.active } + ?.toMediaControlChipModel() + } + .stateIn( + scope = applicationScope, + started = SharingStarted.WhileSubscribed(), + initialValue = null, + ) +} + +private fun MediaData.toMediaControlChipModel(): MediaControlChipModel { + return MediaControlChipModel(appIcon = this.appIcon, appName = this.app, songName = this.song) +} diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/Selectors.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/shared/model/MediaControlChipModel.kt index d6f64bfe4974..403566749e03 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/Selectors.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/shared/model/MediaControlChipModel.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,14 +14,13 @@ * limitations under the License. */ -package com.android.compose.test +package com.android.systemui.statusbar.featurepods.media.shared.model -import androidx.compose.ui.test.SemanticsNodeInteraction -import androidx.compose.ui.test.SemanticsNodeInteractionCollection +import android.graphics.drawable.Icon -/** Assert [assert] on each element of [this] [SemanticsNodeInteractionCollection]. */ -fun SemanticsNodeInteractionCollection.onEach(assert: SemanticsNodeInteraction.() -> Unit) { - for (i in 0 until this.fetchSemanticsNodes().size) { - get(i).assert() - } -} +/** Model used to display a media control chip in the status bar. */ +data class MediaControlChipModel( + val appIcon: Icon?, + val appName: String?, + val songName: CharSequence?, +) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt index 46d4560ff102..df0cde51e8ba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt @@ -23,6 +23,7 @@ import com.android.systemui.statusbar.notification.collection.SortBySectionTimeF import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider +import com.android.systemui.statusbar.notification.promoted.AutomaticPromotionCoordinator import com.android.systemui.statusbar.notification.shared.NotificationMinimalism import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection @@ -69,6 +70,7 @@ constructor( dismissibilityCoordinator: DismissibilityCoordinator, statsLoggerCoordinator: NotificationStatsLoggerCoordinator, bundleCoordinator: BundleCoordinator, + automaticPromotionCoordinator: AutomaticPromotionCoordinator, ) : NotifCoordinators { private val mCoreCoordinators: MutableList<CoreCoordinator> = ArrayList() @@ -110,6 +112,7 @@ constructor( mCoordinators.add(preparationCoordinator) mCoordinators.add(remoteInputCoordinator) mCoordinators.add(dismissibilityCoordinator) + mCoordinators.add(automaticPromotionCoordinator) if (NotificationsLiveDataStoreRefactor.isEnabled) { mCoordinators.add(statsLoggerCoordinator) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/ReferenceCoordinatorsModule.kt index c00bb93ff66e..1829c2c5d548 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/ReferenceCoordinatorsModule.kt @@ -20,6 +20,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinatorsImpl import com.android.systemui.statusbar.notification.collection.coordinator.SensitiveContentCoordinatorModule +import com.android.systemui.statusbar.notification.promoted.ReferenceAutomaticPromotionModule import dagger.Binds import dagger.Module import dagger.Provides @@ -28,12 +29,12 @@ import javax.inject.Qualifier import javax.inject.Scope @Module(subcomponents = [CoordinatorsSubcomponent::class]) -object CoordinatorsModule { +object ReferenceCoordinatorsModule { @SysUISingleton @JvmStatic @Provides fun notifCoordinators(factory: CoordinatorsSubcomponent.Factory): NotifCoordinators = - factory.create().notifCoordinators + factory.create().notifCoordinators } @CoordinatorScope @@ -47,9 +48,9 @@ interface CoordinatorsSubcomponent { } } -@Module(includes = [ - SensitiveContentCoordinatorModule::class, -]) +@Module( + includes = [SensitiveContentCoordinatorModule::class, ReferenceAutomaticPromotionModule::class] +) abstract class InternalCoordinatorsModule { @Binds @Internal @@ -61,7 +62,4 @@ abstract class InternalCoordinatorsModule { @Retention(AnnotationRetention.RUNTIME) private annotation class Internal -@Scope -@MustBeDocumented -@Retention(AnnotationRetention.RUNTIME) -annotation class CoordinatorScope +@Scope @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class CoordinatorScope diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index aa010cf63d5b..ea48fb4ffd92 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -41,7 +41,6 @@ import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotifPipelineChoreographerModule; import com.android.systemui.statusbar.notification.collection.coordinator.ShadeEventCoordinator; -import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorsModule; import com.android.systemui.statusbar.notification.collection.inflation.BindEventManager; import com.android.systemui.statusbar.notification.collection.inflation.BindEventManagerImpl; import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater; @@ -110,7 +109,6 @@ import javax.inject.Provider; * Dagger Module for classes found within the com.android.systemui.statusbar.notification package. */ @Module(includes = { - CoordinatorsModule.class, FooterViewModelModule.class, KeyguardNotificationVisibilityProviderModule.class, NotificationDataLayerModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/ReferenceNotificationsModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/ReferenceNotificationsModule.kt index 4c2512988f4d..6c2c5937f669 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/ReferenceNotificationsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/ReferenceNotificationsModule.kt @@ -16,7 +16,7 @@ package com.android.systemui.statusbar.notification.dagger -import com.android.systemui.statusbar.notification.promoted.PromotedNotificationsModule +import com.android.systemui.statusbar.notification.collection.coordinator.dagger.ReferenceCoordinatorsModule import com.android.systemui.statusbar.notification.row.NotificationRowModule import dagger.Module @@ -29,7 +29,7 @@ import dagger.Module [ NotificationsModule::class, NotificationRowModule::class, - PromotedNotificationsModule::class, + ReferenceCoordinatorsModule::class, ] ) object ReferenceNotificationsModule diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/FakePromotedNotificationsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AutomaticPromotionCoordinator.kt index ea7b41d43871..bb164848320e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/FakePromotedNotificationsProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AutomaticPromotionCoordinator.kt @@ -16,21 +16,16 @@ package com.android.systemui.statusbar.notification.promoted -import com.android.systemui.statusbar.notification.collection.NotificationEntry -import org.junit.Assert +import com.android.systemui.statusbar.notification.collection.NotifPipeline +import com.android.systemui.statusbar.notification.collection.coordinator.Coordinator +import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope +import javax.inject.Inject -class FakePromotedNotificationsProvider : PromotedNotificationsProvider { - val promotedEntries = mutableSetOf<NotificationEntry>() - val shouldPromoteForEntry = mutableMapOf<NotificationEntry, Boolean>() +/** A coordinator that may automatically promote certain notifications. */ +interface AutomaticPromotionCoordinator : Coordinator - override fun shouldPromote(entry: NotificationEntry): Boolean { - if (shouldPromoteForEntry.isEmpty()) { - // If *no* entries are set, just return false for everything. - return false - } else { - // If entries *are* set, fail on unexpected ones. - Assert.assertTrue(shouldPromoteForEntry.containsKey(entry)) - return shouldPromoteForEntry[entry] ?: false - } - } +/** A default implementation of [AutomaticPromotionCoordinator] that doesn't promote anything. */ +@CoordinatorScope +class EmptyAutomaticPromotionCoordinator @Inject constructor() : AutomaticPromotionCoordinator { + override fun attach(pipeline: NotifPipeline) {} } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt index 4e9e3336b86f..7d2827666227 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt @@ -24,10 +24,12 @@ import android.app.Notification.EXTRA_CHRONOMETER_COUNT_DOWN import android.app.Notification.EXTRA_SUB_TEXT import android.app.Notification.EXTRA_TEXT import android.app.Notification.EXTRA_TITLE +import android.app.Notification.FLAG_PROMOTED_ONGOING import android.app.Notification.ProgressStyle import android.content.Context import com.android.systemui.dagger.SysUISingleton import com.android.systemui.shade.ShadeDisplayAware +import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Style @@ -45,7 +47,6 @@ interface PromotedNotificationContentExtractor { class PromotedNotificationContentExtractorImpl @Inject constructor( - private val promotedNotificationsProvider: PromotedNotificationsProvider, @ShadeDisplayAware private val context: Context, private val logger: PromotedNotificationLogger, ) : PromotedNotificationContentExtractor { @@ -58,17 +59,22 @@ constructor( return null } - if (!promotedNotificationsProvider.shouldPromote(entry)) { - logger.logExtractionSkipped(entry, "shouldPromote returned false") - return null - } - val notification = entry.sbn.notification if (notification == null) { logger.logExtractionFailed(entry, "entry.sbn.notification is null") return null } + // Notification.isPromotedOngoing checks the ui_rich_ongoing flag, but we want the status + // bar chip to be ready before all the features behind the ui_rich_ongoing flag are ready. + val isPromotedForStatusBarChip = + StatusBarNotifChips.isEnabled && (notification.flags and FLAG_PROMOTED_ONGOING) != 0 + val isPromoted = notification.isPromotedOngoing() || isPromotedForStatusBarChip + if (!isPromoted) { + logger.logExtractionSkipped(entry, "isPromotedOngoing returned false") + return null + } + val contentBuilder = PromotedNotificationContentModel.Builder(entry.key) // TODO: Pitch a fit if style is unsupported or mandatory fields are missing once diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationsProvider.kt deleted file mode 100644 index 947d9e3e9547..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationsProvider.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.notification.promoted - -import android.app.Notification.FLAG_PROMOTED_ONGOING -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.statusbar.notification.collection.NotificationEntry -import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel -import javax.inject.Inject - -/** A provider for making decisions on which notifications should be promoted. */ -interface PromotedNotificationsProvider { - /** Returns true if the given notification should be promoted and false otherwise. */ - fun shouldPromote(entry: NotificationEntry): Boolean -} - -@SysUISingleton -open class PromotedNotificationsProviderImpl @Inject constructor() : PromotedNotificationsProvider { - override fun shouldPromote(entry: NotificationEntry): Boolean { - if (!PromotedNotificationContentModel.featureFlagEnabled()) { - return false - } - return (entry.sbn.notification.flags and FLAG_PROMOTED_ONGOING) != 0 - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationsModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/ReferenceAutomaticPromotionModule.kt index 4be12bd44a29..6a9bd3f748df 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/ReferenceAutomaticPromotionModule.kt @@ -16,15 +16,15 @@ package com.android.systemui.statusbar.notification.promoted -import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope import dagger.Binds import dagger.Module @Module -abstract class PromotedNotificationsModule { +abstract class ReferenceAutomaticPromotionModule { @Binds - @SysUISingleton - abstract fun bindPromotedNotificationsProvider( - impl: PromotedNotificationsProviderImpl - ): PromotedNotificationsProvider + @CoordinatorScope + abstract fun bindAutomaticPromotionCoordinator( + impl: EmptyAutomaticPromotionCoordinator + ): AutomaticPromotionCoordinator } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index f8eae3607f6a..a2b4e7b474a0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -617,7 +617,8 @@ public class PhoneStatusBarPolicy mUiBgExecutor.execute(() -> { try { final int userId = ActivityTaskManager.getService().getLastResumedActivityUserId(); - final int iconResId = mUserManager.getUserStatusBarIconResId(userId); + final int iconResId = mUserManager.isProfile(userId) ? + mUserManager.getUserStatusBarIconResId(userId) : Resources.ID_NULL; mMainExecutor.execute(() -> { final boolean showIcon; if (iconResId != Resources.ID_NULL && (!mKeyguardStateController.isShowing() diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/FullscreenMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/FullscreenMagnificationControllerTest.java index 5e9f2a2fbe97..9d9fb9c23a73 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/FullscreenMagnificationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/FullscreenMagnificationControllerTest.java @@ -56,6 +56,7 @@ import android.view.animation.Interpolator; import android.window.InputTransferToken; import androidx.annotation.NonNull; +import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.systemui.Flags; @@ -77,6 +78,7 @@ import java.util.function.Supplier; @SmallTest @TestableLooper.RunWithLooper @RunWith(AndroidTestingRunner.class) +@FlakyTest(bugId = 385115361) public class FullscreenMagnificationControllerTest extends SysuiTestCase { private static final long ANIMATION_DURATION_MS = 100L; private static final long WAIT_TIMEOUT_S = 5L * HW_TIMEOUT_MULTIPLIER; diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt index f695c13a9e62..a0ecb802dd61 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt @@ -76,8 +76,6 @@ class UserTrackerImplTest : SysuiTestCase() { @Mock private lateinit var iActivityManager: IActivityManager - @Mock private lateinit var beforeUserSwitchingReply: IRemoteCallback - @Mock private lateinit var userSwitchingReply: IRemoteCallback @Mock(stubOnly = true) private lateinit var dumpManager: DumpManager @@ -201,10 +199,9 @@ class UserTrackerImplTest : SysuiTestCase() { val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java) verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString()) - captor.value.onBeforeUserSwitching(newID, beforeUserSwitchingReply) + captor.value.onBeforeUserSwitching(newID) captor.value.onUserSwitching(newID, userSwitchingReply) runCurrent() - verify(beforeUserSwitchingReply).sendResult(any()) verify(userSwitchingReply).sendResult(any()) verify(userManager).getProfiles(newID) @@ -344,11 +341,10 @@ class UserTrackerImplTest : SysuiTestCase() { val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java) verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString()) - captor.value.onBeforeUserSwitching(newID, beforeUserSwitchingReply) + captor.value.onBeforeUserSwitching(newID) captor.value.onUserSwitching(newID, userSwitchingReply) runCurrent() - verify(beforeUserSwitchingReply).sendResult(any()) verify(userSwitchingReply).sendResult(any()) assertThat(callback.calledOnUserChanging).isEqualTo(1) assertThat(callback.lastUser).isEqualTo(newID) @@ -399,7 +395,7 @@ class UserTrackerImplTest : SysuiTestCase() { val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java) verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString()) - captor.value.onBeforeUserSwitching(newID, any()) + captor.value.onBeforeUserSwitching(newID) captor.value.onUserSwitchComplete(newID) runCurrent() @@ -457,10 +453,8 @@ class UserTrackerImplTest : SysuiTestCase() { val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java) verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString()) - captor.value.onBeforeUserSwitching(newID, beforeUserSwitchingReply) captor.value.onUserSwitching(newID, userSwitchingReply) runCurrent() - verify(beforeUserSwitchingReply).sendResult(any()) verify(userSwitchingReply).sendResult(any()) captor.value.onUserSwitchComplete(newID) @@ -494,7 +488,6 @@ class UserTrackerImplTest : SysuiTestCase() { } private class TestCallback : UserTracker.Callback { - var calledOnBeforeUserChanging = 0 var calledOnUserChanging = 0 var calledOnUserChanged = 0 var calledOnProfilesChanged = 0 @@ -502,11 +495,6 @@ class UserTrackerImplTest : SysuiTestCase() { var lastUserContext: Context? = null var lastUserProfiles = emptyList<UserInfo>() - override fun onBeforeUserSwitching(newUser: Int) { - calledOnBeforeUserChanging++ - lastUser = newUser - } - override fun onUserChanging(newUser: Int, userContext: Context) { calledOnUserChanging++ lastUser = newUser diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationsProviderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/view/ChoreographerUtilsKosmos.kt index 580f617a3cdf..266cb31d4756 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationsProviderKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/view/ChoreographerUtilsKosmos.kt @@ -14,9 +14,9 @@ * limitations under the License. */ -package com.android.systemui.statusbar.notification.promoted +package com.android.systemui.common.ui.view import com.android.systemui.kosmos.Kosmos -var Kosmos.promotedNotificationsProvider: PromotedNotificationsProvider by - Kosmos.Fixture { PromotedNotificationsProviderImpl() } +val Kosmos.fakeChoreographerUtils: FakeChoreographerUtils by + Kosmos.Fixture { FakeChoreographerUtils() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt index 4a6e27331efc..3de809308702 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt @@ -54,6 +54,7 @@ object KeyguardInteractorFactory { fromGoneTransitionInteractor: FromGoneTransitionInteractor = mock(), fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor = mock(), fromOccludedTransitionInteractor: FromOccludedTransitionInteractor = mock(), + fromAlternateBouncerTransitionInteractor: FromAlternateBouncerTransitionInteractor = mock(), powerInteractor: PowerInteractor = PowerInteractorFactory.create().powerInteractor, testScope: CoroutineScope = TestScope(), ): WithDependencies { @@ -84,6 +85,9 @@ object KeyguardInteractorFactory { fromGoneTransitionInteractor = { fromGoneTransitionInteractor }, fromLockscreenTransitionInteractor = { fromLockscreenTransitionInteractor }, fromOccludedTransitionInteractor = { fromOccludedTransitionInteractor }, + fromAlternateBouncerTransitionInteractor = { + fromAlternateBouncerTransitionInteractor + }, applicationScope = testScope, ), ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt index da261bfb9805..f5f8ef75065f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt @@ -38,6 +38,7 @@ val Kosmos.keyguardInteractor: KeyguardInteractor by fromGoneTransitionInteractor = { fromGoneTransitionInteractor }, fromLockscreenTransitionInteractor = { fromLockscreenTransitionInteractor }, fromOccludedTransitionInteractor = { fromOccludedTransitionInteractor }, + fromAlternateBouncerTransitionInteractor = { fromAlternateBouncerTransitionInteractor }, applicationScope = testScope.backgroundScope, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTrackerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTrackerKosmos.kt new file mode 100644 index 000000000000..67dd0ad896d5 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTrackerKosmos.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.shade + +import com.android.internal.logging.latencyTracker +import com.android.systemui.common.ui.data.repository.configurationRepository +import com.android.systemui.common.ui.view.fakeChoreographerUtils +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.kosmos.testScope +import com.android.systemui.scene.ui.view.mockShadeRootView +import java.util.Optional + +val Kosmos.shadeDisplayChangeLatencyTracker by Fixture { + ShadeDisplayChangeLatencyTracker( + Optional.of(mockShadeRootView), + configurationRepository, + latencyTracker, + testScope.backgroundScope, + fakeChoreographerUtils, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt index f2af619a4ad7..4af5e7d9d725 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt @@ -20,22 +20,23 @@ import android.content.mockedContext import android.window.WindowContext import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope -import com.android.systemui.scene.ui.view.mockShadeRootView +import com.android.systemui.shade.ShadeDisplayChangeLatencyTracker import com.android.systemui.shade.ShadeWindowLayoutParams import com.android.systemui.shade.data.repository.fakeShadeDisplaysRepository -import java.util.Optional import org.mockito.kotlin.mock val Kosmos.shadeLayoutParams by Kosmos.Fixture { ShadeWindowLayoutParams.create(mockedContext) } val Kosmos.mockedWindowContext by Kosmos.Fixture { mock<WindowContext>() } +val Kosmos.mockedShadeDisplayChangeLatencyTracker by + Kosmos.Fixture { mock<ShadeDisplayChangeLatencyTracker>() } val Kosmos.shadeDisplaysInteractor by Kosmos.Fixture { ShadeDisplaysInteractor( - Optional.of(mockShadeRootView), fakeShadeDisplaysRepository, mockedWindowContext, testScope.backgroundScope, testScope.backgroundScope.coroutineContext, + mockedShadeDisplayChangeLatencyTracker, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/media/domain/interactor/MediaControlChipInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/media/domain/interactor/MediaControlChipInteractorKosmos.kt new file mode 100644 index 000000000000..0025ad42ba53 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/media/domain/interactor/MediaControlChipInteractorKosmos.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.featurepods.media.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.media.controls.data.repository.mediaFilterRepository + +val Kosmos.mediaControlChipInteractor: MediaControlChipInteractor by + Kosmos.Fixture { + MediaControlChipInteractor( + applicationScope = applicationCoroutineScope, + mediaFilterRepository = mediaFilterRepository, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt index 52c17c82fb12..912d5027c494 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt @@ -21,9 +21,5 @@ import com.android.systemui.kosmos.Kosmos var Kosmos.promotedNotificationContentExtractor by Kosmos.Fixture { - PromotedNotificationContentExtractorImpl( - promotedNotificationsProvider, - applicationContext, - promotedNotificationLogger, - ) + PromotedNotificationContentExtractorImpl(applicationContext, promotedNotificationLogger) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt index e739e82aa8a8..3fddd47c25f0 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt @@ -67,7 +67,6 @@ import com.android.systemui.statusbar.notification.icon.IconManager import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractorImpl import com.android.systemui.statusbar.notification.promoted.PromotedNotificationLogger -import com.android.systemui.statusbar.notification.promoted.PromotedNotificationsProviderImpl import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.CoordinateOnClickListener import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.ExpandableNotificationRowLogger import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.OnExpandClickListener @@ -224,7 +223,6 @@ class ExpandableNotificationRowBuilder( ) val promotedNotificationContentExtractor = PromotedNotificationContentExtractorImpl( - PromotedNotificationsProviderImpl(), context, PromotedNotificationLogger(logcatLogBuffer("PromotedNotifLog")), ) diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 70f2a8e1dd1b..c31b9ef60bd2 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -160,7 +160,6 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.BiConsumer; import java.util.function.Consumer; /** @@ -177,9 +176,6 @@ import java.util.function.Consumer; class UserController implements Handler.Callback { private static final String TAG = TAG_WITH_CLASS_NAME ? "UserController" : TAG_AM; - // Amount of time we wait for observers to handle onBeforeUserSwitching, before crashing system. - static final int DEFAULT_BEFORE_USER_SWITCH_TIMEOUT_MS = 20 * 1000; - // Amount of time we wait for observers to handle a user switch before // giving up on them and dismissing the user switching dialog. static final int DEFAULT_USER_SWITCH_TIMEOUT_MS = 3 * 1000; @@ -1924,14 +1920,8 @@ class UserController implements Handler.Callback { return false; } - final Runnable continueStartUserInternal = () -> continueStartUserInternal(userInfo, - oldUserId, userStartMode, unlockListener, callingUid, callingPid); - if (foreground) { - mHandler.post(() -> dispatchOnBeforeUserSwitching(userId, () -> - mHandler.post(continueStartUserInternal))); - } else { - continueStartUserInternal.run(); - } + mHandler.post(() -> startUserInternalOnHandler(userId, oldUserId, userStartMode, + unlockListener, callingUid, callingPid)); } finally { Binder.restoreCallingIdentity(ident); } @@ -1939,11 +1929,11 @@ class UserController implements Handler.Callback { return true; } - private void continueStartUserInternal(UserInfo userInfo, int oldUserId, int userStartMode, + private void startUserInternalOnHandler(int userId, int oldUserId, int userStartMode, IProgressListener unlockListener, int callingUid, int callingPid) { final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); final boolean foreground = userStartMode == USER_START_MODE_FOREGROUND; - final int userId = userInfo.id; + final UserInfo userInfo = getUserInfo(userId); boolean needStart = false; boolean updateUmState = false; @@ -2005,6 +1995,7 @@ class UserController implements Handler.Callback { // it should be moved outside, but for now it's not as there are many calls to // external components here afterwards updateProfileRelatedCaches(); + dispatchOnBeforeUserSwitching(userId); mInjector.getWindowManager().setCurrentUser(userId); mInjector.reportCurWakefulnessUsageEvent(); // Once the internal notion of the active user has switched, we lock the device @@ -2305,40 +2296,25 @@ class UserController implements Handler.Callback { mUserSwitchObservers.finishBroadcast(); } - private void dispatchOnBeforeUserSwitching(@UserIdInt int newUserId, Runnable onComplete) { + private void dispatchOnBeforeUserSwitching(@UserIdInt int newUserId) { final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); t.traceBegin("dispatchOnBeforeUserSwitching-" + newUserId); - final AtomicBoolean isSuccessful = new AtomicBoolean(false); - startTimeoutForOnBeforeUserSwitching(isSuccessful); - informUserSwitchObservers((observer, callback) -> { + final int observerCount = mUserSwitchObservers.beginBroadcast(); + for (int i = 0; i < observerCount; i++) { + final String name = "#" + i + " " + mUserSwitchObservers.getBroadcastCookie(i); + t.traceBegin("onBeforeUserSwitching-" + name); try { - observer.onBeforeUserSwitching(newUserId, callback); + mUserSwitchObservers.getBroadcastItem(i).onBeforeUserSwitching(newUserId); } catch (RemoteException e) { - // ignore + // Ignore + } finally { + t.traceEnd(); } - }, () -> { - isSuccessful.set(true); - onComplete.run(); - }, "onBeforeUserSwitching"); + } + mUserSwitchObservers.finishBroadcast(); t.traceEnd(); } - private void startTimeoutForOnBeforeUserSwitching(AtomicBoolean isSuccessful) { - mHandler.postDelayed(() -> { - if (isSuccessful.get()) { - return; - } - String unresponsiveObservers; - synchronized (mLock) { - unresponsiveObservers = String.join(", ", mCurWaitingUserSwitchCallbacks); - } - throw new RuntimeException("Timeout on dispatchOnBeforeUserSwitching. " - + "These UserSwitchObservers did not respond in " - + DEFAULT_BEFORE_USER_SWITCH_TIMEOUT_MS + "ms: " + unresponsiveObservers + "."); - }, DEFAULT_BEFORE_USER_SWITCH_TIMEOUT_MS); - } - - /** Called on handler thread */ @VisibleForTesting void dispatchUserSwitchComplete(@UserIdInt int oldUserId, @UserIdInt int newUserId) { @@ -2551,76 +2527,70 @@ class UserController implements Handler.Callback { t.traceBegin("dispatchUserSwitch-" + oldUserId + "-to-" + newUserId); EventLog.writeEvent(EventLogTags.UC_DISPATCH_USER_SWITCH, oldUserId, newUserId); - uss.switching = true; - informUserSwitchObservers((observer, callback) -> { - try { - observer.onUserSwitching(newUserId, callback); - } catch (RemoteException e) { - // ignore - } - }, () -> { - synchronized (mLock) { - sendContinueUserSwitchLU(uss, oldUserId, newUserId); - } - }, "onUserSwitching"); - t.traceEnd(); - } - void informUserSwitchObservers(BiConsumer<IUserSwitchObserver, IRemoteCallback> consumer, - final Runnable onComplete, String trace) { final int observerCount = mUserSwitchObservers.beginBroadcast(); - if (observerCount == 0) { - onComplete.run(); - mUserSwitchObservers.finishBroadcast(); - return; - } - final ArraySet<String> curWaitingUserSwitchCallbacks = new ArraySet<>(); - synchronized (mLock) { - mCurWaitingUserSwitchCallbacks = curWaitingUserSwitchCallbacks; - } - final AtomicInteger waitingCallbacksCount = new AtomicInteger(observerCount); - final long userSwitchTimeoutMs = getUserSwitchTimeoutMs(); - final long dispatchStartedTime = SystemClock.elapsedRealtime(); - for (int i = 0; i < observerCount; i++) { - final long dispatchStartedTimeForObserver = SystemClock.elapsedRealtime(); - // Prepend with unique prefix to guarantee that keys are unique - final String name = "#" + i + " " + mUserSwitchObservers.getBroadcastCookie(i); + if (observerCount > 0) { + final ArraySet<String> curWaitingUserSwitchCallbacks = new ArraySet<>(); synchronized (mLock) { - curWaitingUserSwitchCallbacks.add(name); - } - final IRemoteCallback callback = new IRemoteCallback.Stub() { - @Override - public void sendResult(Bundle data) throws RemoteException { - asyncTraceEnd(trace + "-" + name, 0); + uss.switching = true; + mCurWaitingUserSwitchCallbacks = curWaitingUserSwitchCallbacks; + } + final AtomicInteger waitingCallbacksCount = new AtomicInteger(observerCount); + final long userSwitchTimeoutMs = getUserSwitchTimeoutMs(); + final long dispatchStartedTime = SystemClock.elapsedRealtime(); + for (int i = 0; i < observerCount; i++) { + final long dispatchStartedTimeForObserver = SystemClock.elapsedRealtime(); + try { + // Prepend with unique prefix to guarantee that keys are unique + final String name = "#" + i + " " + mUserSwitchObservers.getBroadcastCookie(i); synchronized (mLock) { - long delayForObserver = SystemClock.elapsedRealtime() - - dispatchStartedTimeForObserver; - if (delayForObserver > LONG_USER_SWITCH_OBSERVER_WARNING_TIME_MS) { - Slogf.w(TAG, "User switch slowed down by observer " + name - + ": result took " + delayForObserver - + " ms to process. " + trace); - } - long totalDelay = SystemClock.elapsedRealtime() - dispatchStartedTime; - if (totalDelay > userSwitchTimeoutMs) { - Slogf.e(TAG, "User switch timeout: observer " + name - + "'s result was received " + totalDelay - + " ms after dispatchUserSwitch. " + trace); - } - curWaitingUserSwitchCallbacks.remove(name); - // Continue switching if all callbacks have been notified and - // user switching session is still valid - if (waitingCallbacksCount.decrementAndGet() == 0 - && (curWaitingUserSwitchCallbacks - == mCurWaitingUserSwitchCallbacks)) { - onComplete.run(); - } + curWaitingUserSwitchCallbacks.add(name); } + final IRemoteCallback callback = new IRemoteCallback.Stub() { + @Override + public void sendResult(Bundle data) throws RemoteException { + asyncTraceEnd("onUserSwitching-" + name, newUserId); + synchronized (mLock) { + long delayForObserver = SystemClock.elapsedRealtime() + - dispatchStartedTimeForObserver; + if (delayForObserver > LONG_USER_SWITCH_OBSERVER_WARNING_TIME_MS) { + Slogf.w(TAG, "User switch slowed down by observer " + name + + ": result took " + delayForObserver + + " ms to process."); + } + + long totalDelay = SystemClock.elapsedRealtime() + - dispatchStartedTime; + if (totalDelay > userSwitchTimeoutMs) { + Slogf.e(TAG, "User switch timeout: observer " + name + + "'s result was received " + totalDelay + + " ms after dispatchUserSwitch."); + } + + curWaitingUserSwitchCallbacks.remove(name); + // Continue switching if all callbacks have been notified and + // user switching session is still valid + if (waitingCallbacksCount.decrementAndGet() == 0 + && (curWaitingUserSwitchCallbacks + == mCurWaitingUserSwitchCallbacks)) { + sendContinueUserSwitchLU(uss, oldUserId, newUserId); + } + } + } + }; + asyncTraceBegin("onUserSwitching-" + name, newUserId); + mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(newUserId, callback); + } catch (RemoteException e) { + // Ignore } - }; - asyncTraceBegin(trace + "-" + name, 0); - consumer.accept(mUserSwitchObservers.getBroadcastItem(i), callback); + } + } else { + synchronized (mLock) { + sendContinueUserSwitchLU(uss, oldUserId, newUserId); + } } mUserSwitchObservers.finishBroadcast(); + t.traceEnd(); // end dispatchUserSwitch- } @GuardedBy("mLock") diff --git a/services/core/java/com/android/server/display/BrightnessRangeController.java b/services/core/java/com/android/server/display/BrightnessRangeController.java index 50d650855b05..4fd92751d498 100644 --- a/services/core/java/com/android/server/display/BrightnessRangeController.java +++ b/services/core/java/com/android/server/display/BrightnessRangeController.java @@ -17,7 +17,6 @@ package com.android.server.display; import android.annotation.Nullable; -import android.hardware.display.BrightnessInfo; import android.os.Handler; import android.os.IBinder; @@ -121,8 +120,11 @@ class BrightnessRangeController { } void onBrightnessChanged(float brightness, float unthrottledBrightness, - @BrightnessInfo.BrightnessMaxReason int throttlingReason) { - mHbmController.onBrightnessChanged(brightness, unthrottledBrightness, throttlingReason); + DisplayBrightnessState state) { + mHbmController.onHdrBoostApplied( + state.getHdrBrightness() != DisplayBrightnessState.BRIGHTNESS_NOT_SET); + mHbmController.onBrightnessChanged(brightness, unthrottledBrightness, + state.getBrightnessMaxReason()); } float getCurrentBrightnessMin() { diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 2f82b2ac464a..92f5cab10c2a 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -1638,7 +1638,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // brightness sources (such as an app override) are not saved to the setting, but should be // reflected in HBM calculations. mBrightnessRangeController.onBrightnessChanged(brightnessState, unthrottledBrightnessState, - clampedState.getBrightnessMaxReason()); + clampedState); // Animate the screen brightness when the screen is on or dozing. // Skip the animation when the screen is off or suspended. diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java index 6be0c123d262..0334aa5bca8f 100644 --- a/services/core/java/com/android/server/display/HighBrightnessModeController.java +++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java @@ -102,7 +102,8 @@ class HighBrightnessModeController { BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE; private int mHbmMode = BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF; - private boolean mIsHdrLayerPresent = false; + @VisibleForTesting + boolean mIsHdrLayerPresent = false; // mMaxDesiredHdrSdrRatio should only be applied when there is a valid backlight->nits mapping private float mMaxDesiredHdrSdrRatio = DEFAULT_MAX_DESIRED_HDR_SDR_RATIO; private boolean mForceHbmChangeCallback = false; @@ -387,6 +388,18 @@ class HighBrightnessModeController { mHdrBoostDisabled = true; unregisterHdrListener(); } + /** + * Hdr boost can be applied by + * {@link com.android.server.display.brightness.clamper.HdrBrightnessModifier}, in this case + * HBMController should not consume HBM time budget + */ + void onHdrBoostApplied(boolean applied) { + // We need to update mIsHdrLayerPresent flag only if HDR boost is controlled by other + // component and disabled here + if (mHdrBoostDisabled) { + mIsHdrLayerPresent = applied; + } + } private long calculateRemainingTime(long currentTime) { if (!deviceSupportsHbm()) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index ec0f25169d75..17b712de3be6 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -191,7 +191,6 @@ import android.service.dreams.IDreamManager; import android.service.vr.IPersistentVrStateCallbacks; import android.speech.RecognizerIntent; import android.telecom.TelecomManager; -import android.util.ArraySet; import android.util.Log; import android.util.MathUtils; import android.util.MutableBoolean; @@ -725,23 +724,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { private final boolean mVisibleBackgroundUsersEnabled = isVisibleBackgroundUsersEnabled(); - // Key codes that should be ignored for visible background users in MUMD environment. - private static final Set<Integer> KEY_CODES_IGNORED_FOR_VISIBLE_BACKGROUND_USERS = - new ArraySet<>(Arrays.asList( - KeyEvent.KEYCODE_POWER, - KeyEvent.KEYCODE_SLEEP, - KeyEvent.KEYCODE_WAKEUP, - KeyEvent.KEYCODE_CALL, - KeyEvent.KEYCODE_ENDCALL, - KeyEvent.KEYCODE_ASSIST, - KeyEvent.KEYCODE_VOICE_ASSIST, - KeyEvent.KEYCODE_MUTE, - KeyEvent.KEYCODE_VOLUME_MUTE, - KeyEvent.KEYCODE_RECENT_APPS, - KeyEvent.KEYCODE_APP_SWITCH, - KeyEvent.KEYCODE_NOTIFICATION - )); - private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3; private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4; private static final int MSG_KEYGUARD_DRAWN_COMPLETE = 5; @@ -5127,7 +5109,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // There are key events that perform the operation as the current user, // and these should be ignored for visible background users. if (mVisibleBackgroundUsersEnabled - && KEY_CODES_IGNORED_FOR_VISIBLE_BACKGROUND_USERS.contains(keyCode) + && !KeyEvent.isVisibleBackgroundUserAllowedKey(keyCode) && !isKeyEventForCurrentUser(event.getDisplayId(), keyCode, null)) { return 0; } diff --git a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java index e80a86d73f90..4fd026a6dc52 100644 --- a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java +++ b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java @@ -285,14 +285,20 @@ public final class PowerStatsLogger extends Handler { } private void updateCacheFile(String cacheFilename, byte[] data) { + AtomicFile atomicCachedFile = null; + FileOutputStream fos = null; try { - final AtomicFile atomicCachedFile = + atomicCachedFile = new AtomicFile(new File(mDataStoragePath, cacheFilename)); - final FileOutputStream fos = atomicCachedFile.startWrite(); + fos = atomicCachedFile.startWrite(); fos.write(data); atomicCachedFile.finishWrite(fos); } catch (IOException e) { Slog.e(TAG, "Failed to write current data to cached file", e); + if (fos != null) { + atomicCachedFile.failWrite(fos); + } + return; } } diff --git a/services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java b/services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java index 083b1fd61c46..f303a588d30c 100644 --- a/services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java +++ b/services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java @@ -129,7 +129,8 @@ public class NetworkLogSource implements DataSource { timestamp); dnsEvent.setId(mId); incrementEventID(); - mDataAggregator.addSingleData(new IntrusionDetectionEvent(dnsEvent)); + mDataAggregator.addSingleData( + IntrusionDetectionEvent.createForDnsEvent(dnsEvent)); } @Override @@ -141,7 +142,8 @@ public class NetworkLogSource implements DataSource { new ConnectEvent(ipAddr, port, mPm.getNameForUid(uid), timestamp); connectEvent.setId(mId); incrementEventID(); - mDataAggregator.addSingleData(new IntrusionDetectionEvent(connectEvent)); + mDataAggregator.addSingleData( + IntrusionDetectionEvent.createForConnectEvent(connectEvent)); } }; } diff --git a/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java b/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java index 5611905bf270..142094c9d9f4 100644 --- a/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java +++ b/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java @@ -89,7 +89,7 @@ public class SecurityLogSource implements DataSource { List<IntrusionDetectionEvent> intrusionDetectionEvents = events.stream() .filter(event -> event != null) - .map(event -> new IntrusionDetectionEvent(event)) + .map(event -> IntrusionDetectionEvent.createForSecurityEvent(event)) .collect(Collectors.toList()); mDataAggregator.addBatchData(intrusionDetectionEvents); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 290f155bb4cd..2971e8edef43 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -438,10 +438,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /** It is set from keyguard-going-away to set-keyguard-shown. */ static final int DEMOTE_TOP_REASON_DURING_UNLOCKING = 1; + /** It is set when notification shade occludes the foreground app. */ + static final int DEMOTE_TOP_REASON_EXPANDED_NOTIFICATION_SHADE = 1 << 1; @Retention(RetentionPolicy.SOURCE) @IntDef({ DEMOTE_TOP_REASON_DURING_UNLOCKING, + DEMOTE_TOP_REASON_EXPANDED_NOTIFICATION_SHADE, }) @interface DemoteTopReason {} @@ -5247,6 +5250,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { : mRootWindowContainer.getTopResumedActivity(); mTopApp = top != null ? top.app : null; if (mTopApp == mPreviousProcess) mPreviousProcess = null; + + final int demoteReasons = mDemoteTopAppReasons; + if ((demoteReasons & DEMOTE_TOP_REASON_EXPANDED_NOTIFICATION_SHADE) != 0) { + Trace.instant(TRACE_TAG_WINDOW_MANAGER, "cancel-demote-top-for-ns-switch"); + mDemoteTopAppReasons = demoteReasons & ~DEMOTE_TOP_REASON_EXPANDED_NOTIFICATION_SHADE; + } } /** diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java index 852a0ac054f4..89d756ca5aaf 100644 --- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java +++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java @@ -1091,11 +1091,6 @@ public class BackgroundActivityStartController { // don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission if (mService.hasSystemAlertWindowPermission(state.mCallingUid, state.mCallingPid, state.mCallingPackage)) { - Slog.w( - TAG, - "Background activity start for " - + state.mCallingPackage - + " allowed because SYSTEM_ALERT_WINDOW permission is granted."); return new BalVerdict(BAL_ALLOW_SAW_PERMISSION, /*background*/ true, "SYSTEM_ALERT_WINDOW permission is granted"); } @@ -1167,18 +1162,9 @@ public class BackgroundActivityStartController { } // don't abort if the realCallingUid has SYSTEM_ALERT_WINDOW permission - Slog.i(TAG, "hasSystemAlertWindowPermission(" + state.mRealCallingUid + ", " - + state.mRealCallingPid + ", " + state.mRealCallingPackage + ") " - + balStartModeToString( - state.mCheckedOptions.getPendingIntentBackgroundActivityStartMode())); if (allowAlways && mService.hasSystemAlertWindowPermission(state.mRealCallingUid, state.mRealCallingPid, state.mRealCallingPackage)) { - Slog.w( - TAG, - "Background activity start for " - + state.mRealCallingPackage - + " allowed because SYSTEM_ALERT_WINDOW permission is granted."); return new BalVerdict(BAL_ALLOW_SAW_PERMISSION, /*background*/ true, "SYSTEM_ALERT_WINDOW permission is granted"); } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 4dd950ba6ee9..5c3fbdfcff0e 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -440,7 +440,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp private boolean mSandboxDisplayApis = true; /** Whether {@link #setIgnoreOrientationRequest} is called to override the default policy. */ - @VisibleForTesting boolean mHasSetIgnoreOrientationRequest; /** diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java index f0ba822c37c5..4ae100857f55 100644 --- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java +++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java @@ -376,6 +376,9 @@ class DisplayWindowSettings { if (settings.mIgnoreOrientationRequest != null) { dc.setIgnoreOrientationRequest(settings.mIgnoreOrientationRequest); + } else if (dc.mHasSetIgnoreOrientationRequest) { + // Null entry is default behavior, i.e. do not ignore. + dc.setIgnoreOrientationRequest(false); } dc.getDisplayRotation().resetAllowAllRotations(); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 04650b9e0150..793f18992109 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -121,6 +121,7 @@ import static com.android.server.LockGuard.INDEX_WINDOW; import static com.android.server.LockGuard.installLock; import static com.android.server.policy.PhoneWindowManager.TRACE_WAIT_FOR_ALL_WINDOWS_DRAWN_METHOD; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; +import static com.android.server.wm.ActivityTaskManagerService.DEMOTE_TOP_REASON_EXPANDED_NOTIFICATION_SHADE; import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY; import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND; import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING; @@ -7845,6 +7846,37 @@ public class WindowManagerService extends IWindowManager.Stub } @Override + public void onNotificationShadeExpanded(IBinder token, boolean expanded) { + synchronized (mGlobalLock) { + final WindowState w = mWindowMap.get(token); + if (w == null || w != w.mDisplayContent.getDisplayPolicy().getNotificationShade()) { + return; + } + final WindowProcessController topApp = mAtmService.mTopApp; + // Demotes the priority of top app if notification shade is expanded to occlude the app. + // So the notification shade may have more capacity to draw and animate. + final int demoteTopAppReasons = mAtmService.mDemoteTopAppReasons; + if (expanded && mAtmService.mTopProcessState == ActivityManager.PROCESS_STATE_TOP + && (demoteTopAppReasons & DEMOTE_TOP_REASON_EXPANDED_NOTIFICATION_SHADE) == 0) { + mAtmService.mDemoteTopAppReasons = + demoteTopAppReasons | DEMOTE_TOP_REASON_EXPANDED_NOTIFICATION_SHADE; + Trace.instant(TRACE_TAG_WINDOW_MANAGER, "demote-top-for-ns"); + if (topApp != null) { + topApp.scheduleUpdateOomAdj(); + } + } else if (!expanded + && (demoteTopAppReasons & DEMOTE_TOP_REASON_EXPANDED_NOTIFICATION_SHADE) != 0) { + mAtmService.mDemoteTopAppReasons = + demoteTopAppReasons & ~DEMOTE_TOP_REASON_EXPANDED_NOTIFICATION_SHADE; + Trace.instant(TRACE_TAG_WINDOW_MANAGER, "cancel-demote-top-for-ns"); + if (topApp != null) { + topApp.scheduleUpdateOomAdj(); + } + } + } + } + + @Override public void registerShortcutKey(long shortcutCode, IShortcutService shortcutKeyReceiver) throws RemoteException { if (!checkCallingPermission(REGISTER_WINDOW_MANAGER_LISTENERS, "registerShortcutKey")) { diff --git a/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt b/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt index 161a8168d993..b356b830a5c4 100644 --- a/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt +++ b/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt @@ -119,6 +119,10 @@ class AppOpService(private val service: AccessCheckingService) : AppOpsCheckingS val permissions = service.getState { with(permissionPolicy) { getPermissions() } } for (appOpCode in 0 until AppOpsManager._NUM_OP) { + // Ops that default to MODE_FOREGROUND are foregroundable. + if (AppOpsManager.opToDefaultMode(appOpCode) == AppOpsManager.MODE_FOREGROUND) { + foregroundableOps[appOpCode] = true + } AppOpsManager.opToPermission(appOpCode)?.let { permissionName -> // Multiple ops might map to a single permission but only one is considered the // runtime appop calculations. diff --git a/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java index cde87b9b89b2..255d236186b6 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java @@ -720,6 +720,25 @@ public class HighBrightnessModeControllerTest { .DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_LOW_REQUESTED_BRIGHTNESS)); } + @Test + public void testDoesNotAcceptExternalHdrLayerUpdates_hdrBoostEnabled() { + final HighBrightnessModeController hbmc = createDefaultHbm(); + assertFalse(hbmc.mIsHdrLayerPresent); + + hbmc.onHdrBoostApplied(true); + assertFalse(hbmc.mIsHdrLayerPresent); + } + + @Test + public void testAcceptsExternalHdrLayerUpdates_hdrBoostDisabled() { + final HighBrightnessModeController hbmc = createDefaultHbm(); + hbmc.disableHdrBoost(); + assertFalse(hbmc.mIsHdrLayerPresent); + + hbmc.onHdrBoostApplied(true); + assertTrue(hbmc.mIsHdrLayerPresent); + } + private void assertState(HighBrightnessModeController hbmc, float brightnessMin, float brightnessMax, int hbmMode) { assertEquals(brightnessMin, hbmc.getCurrentBrightnessMin(), EPSILON); diff --git a/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java index 5cba6b2c3e67..298d27e2e8c4 100644 --- a/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java +++ b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java @@ -350,15 +350,17 @@ public class IntrusionDetectionServiceTest { mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread); SecurityEvent securityEvent = new SecurityEvent(0, new byte[0]); - IntrusionDetectionEvent eventOne = new IntrusionDetectionEvent(securityEvent); + IntrusionDetectionEvent eventOne = + IntrusionDetectionEvent.createForSecurityEvent(securityEvent); ConnectEvent connectEvent = new ConnectEvent( "127.0.0.1", 80, null, 0); - IntrusionDetectionEvent eventTwo = new IntrusionDetectionEvent(connectEvent); + IntrusionDetectionEvent eventTwo = + IntrusionDetectionEvent.createForConnectEvent(connectEvent); DnsEvent dnsEvent = new DnsEvent( null, new String[] {"127.0.0.1"}, 1, null, 0); - IntrusionDetectionEvent eventThree = new IntrusionDetectionEvent(dnsEvent); + IntrusionDetectionEvent eventThree = IntrusionDetectionEvent.createForDnsEvent(dnsEvent); List<IntrusionDetectionEvent> events = new ArrayList<>(); events.add(eventOne); @@ -581,7 +583,8 @@ public class IntrusionDetectionServiceTest { // call the methods on the transport object IntrusionDetectionEvent event = - new IntrusionDetectionEvent(new SecurityEvent(123, new byte[15])); + IntrusionDetectionEvent.createForSecurityEvent( + new SecurityEvent(123, new byte[15])); List<IntrusionDetectionEvent> events = new ArrayList<>(); events.add(event); assertTrue(transport.initialize()); diff --git a/services/tests/servicestests/assets/shortcut/dumpsys_expected.txt b/services/tests/servicestests/assets/shortcut/dumpsys_expected.txt index eed2087f80ef..029ada3f5118 100644 --- a/services/tests/servicestests/assets/shortcut/dumpsys_expected.txt +++ b/services/tests/servicestests/assets/shortcut/dumpsys_expected.txt @@ -1,7 +1,7 @@ { "shortcut": [ { - "userId": 0, + "userId": 10, "launchers": [ { "name": "com.android.launcher.1" @@ -55,7 +55,7 @@ ] }, { - "userId": 10, + "userId": 11, "launchers": [ { "name": "com.android.launcher.1" diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java index 7dbbff22a537..2fe6918630f6 100644 --- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java @@ -33,7 +33,6 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat import static com.android.server.am.UserController.CLEAR_USER_JOURNEY_SESSION_MSG; import static com.android.server.am.UserController.COMPLETE_USER_SWITCH_MSG; import static com.android.server.am.UserController.CONTINUE_USER_SWITCH_MSG; -import static com.android.server.am.UserController.DEFAULT_BEFORE_USER_SWITCH_TIMEOUT_MS; import static com.android.server.am.UserController.REPORT_LOCKED_BOOT_COMPLETE_MSG; import static com.android.server.am.UserController.REPORT_USER_SWITCH_COMPLETE_MSG; import static com.android.server.am.UserController.REPORT_USER_SWITCH_MSG; @@ -95,7 +94,6 @@ import android.os.Looper; import android.os.Message; import android.os.PowerManagerInternal; import android.os.RemoteException; -import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.IStorageManager; @@ -183,12 +181,14 @@ public class UserControllerTest { Intent.ACTION_USER_STARTING); private static final Set<Integer> START_FOREGROUND_USER_MESSAGE_CODES = newHashSet( + 0, // for startUserInternalOnHandler REPORT_USER_SWITCH_MSG, USER_SWITCH_TIMEOUT_MSG, USER_START_MSG, USER_CURRENT_MSG); private static final Set<Integer> START_BACKGROUND_USER_MESSAGE_CODES = newHashSet( + 0, // for startUserInternalOnHandler USER_START_MSG, REPORT_LOCKED_BOOT_COMPLETE_MSG); @@ -376,7 +376,7 @@ public class UserControllerTest { // and the cascade effect goes on...). In fact, a better approach would to not assert the // binder calls, but their side effects (in this case, that the user is stopped right away) assertWithMessage("wrong binder message calls").that(mInjector.mHandler.getMessageCodes()) - .containsExactly(USER_START_MSG); + .containsExactly(/* for startUserInternalOnHandler */ 0, USER_START_MSG); } private void startUserAssertions( @@ -419,12 +419,17 @@ public class UserControllerTest { @Test public void testDispatchUserSwitch() throws RemoteException { // Prepare mock observer and register it - IUserSwitchObserver observer = registerUserSwitchObserver( - /* replyToOnBeforeUserSwitchingCallback= */ true, - /* replyToOnUserSwitchingCallback= */ true); + IUserSwitchObserver observer = mock(IUserSwitchObserver.class); + when(observer.asBinder()).thenReturn(new Binder()); + doAnswer(invocation -> { + IRemoteCallback callback = (IRemoteCallback) invocation.getArguments()[1]; + callback.sendResult(null); + return null; + }).when(observer).onUserSwitching(anyInt(), any()); + mUserController.registerUserSwitchObserver(observer, "mock"); // Start user -- this will update state of mUserController mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND); - verify(observer, times(1)).onBeforeUserSwitching(eq(TEST_USER_ID), any()); + verify(observer, times(1)).onBeforeUserSwitching(eq(TEST_USER_ID)); Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG); assertNotNull(reportMsg); UserState userState = (UserState) reportMsg.obj; @@ -448,26 +453,14 @@ public class UserControllerTest { } @Test - public void testShouldCrashWhenOnBeforeUserSwitchingTimeouts() throws RemoteException { - IUserSwitchObserver observer = registerUserSwitchObserver( - /* replyToOnBeforeUserSwitchingCallback= */ false, - /* replyToOnUserSwitchingCallback= */ true); - mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND); - verify(observer, times(1)).onBeforeUserSwitching(eq(TEST_USER_ID), any()); - assertThrows("Should have crashed when observers don't reply to onBeforeUserSwitching in " - + DEFAULT_BEFORE_USER_SWITCH_TIMEOUT_MS + " ms", RuntimeException.class, - mInjector.mHandler::runPendingCallbacks); - } - - @Test public void testDispatchUserSwitchBadReceiver() throws RemoteException { - // Prepare mock observer which doesn't notify the onUserSwitching callback and register it - IUserSwitchObserver observer = registerUserSwitchObserver( - /* replyToOnBeforeUserSwitchingCallback= */ true, - /* replyToOnUserSwitchingCallback= */ false); + // Prepare mock observer which doesn't notify the callback and register it + IUserSwitchObserver observer = mock(IUserSwitchObserver.class); + when(observer.asBinder()).thenReturn(new Binder()); + mUserController.registerUserSwitchObserver(observer, "mock"); // Start user -- this will update state of mUserController mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND); - verify(observer, times(1)).onBeforeUserSwitching(eq(TEST_USER_ID), any()); + verify(observer, times(1)).onBeforeUserSwitching(eq(TEST_USER_ID)); Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG); assertNotNull(reportMsg); UserState userState = (UserState) reportMsg.obj; @@ -558,6 +551,7 @@ public class UserControllerTest { expectedCodes.add(REPORT_USER_SWITCH_COMPLETE_MSG); if (backgroundUserStopping) { expectedCodes.add(CLEAR_USER_JOURNEY_SESSION_MSG); + expectedCodes.add(0); // this is for directly posting in stopping. } if (expectScheduleBackgroundUserStopping) { expectedCodes.add(SCHEDULED_STOP_BACKGROUND_USER_MSG); @@ -573,9 +567,9 @@ public class UserControllerTest { @Test public void testDispatchUserSwitchComplete() throws RemoteException { // Prepare mock observer and register it - IUserSwitchObserver observer = registerUserSwitchObserver( - /* replyToOnBeforeUserSwitchingCallback= */ true, - /* replyToOnUserSwitchingCallback= */ true); + IUserSwitchObserver observer = mock(IUserSwitchObserver.class); + when(observer.asBinder()).thenReturn(new Binder()); + mUserController.registerUserSwitchObserver(observer, "mock"); // Start user -- this will update state of mUserController mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND); Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG); @@ -1758,29 +1752,6 @@ public class UserControllerTest { verify(mInjector, never()).onSystemUserVisibilityChanged(anyBoolean()); } - private IUserSwitchObserver registerUserSwitchObserver( - boolean replyToOnBeforeUserSwitchingCallback, boolean replyToOnUserSwitchingCallback) - throws RemoteException { - IUserSwitchObserver observer = mock(IUserSwitchObserver.class); - when(observer.asBinder()).thenReturn(new Binder()); - if (replyToOnBeforeUserSwitchingCallback) { - doAnswer(invocation -> { - IRemoteCallback callback = (IRemoteCallback) invocation.getArguments()[1]; - callback.sendResult(null); - return null; - }).when(observer).onBeforeUserSwitching(anyInt(), any()); - } - if (replyToOnUserSwitchingCallback) { - doAnswer(invocation -> { - IRemoteCallback callback = (IRemoteCallback) invocation.getArguments()[1]; - callback.sendResult(null); - return null; - }).when(observer).onUserSwitching(anyInt(), any()); - } - mUserController.registerUserSwitchObserver(observer, "mock"); - return observer; - } - // Should be public to allow mocking private static class TestInjector extends UserController.Injector { public final TestHandler mHandler; @@ -1986,7 +1957,6 @@ public class UserControllerTest { * fix this, but in the meantime, this is your warning. */ private final List<Message> mMessages = new ArrayList<>(); - private final List<Runnable> mPendingCallbacks = new ArrayList<>(); TestHandler(Looper looper) { super(looper); @@ -2019,24 +1989,14 @@ public class UserControllerTest { @Override public boolean sendMessageAtTime(Message msg, long uptimeMillis) { - if (msg.getCallback() == null) { - Message copy = new Message(); - copy.copyFrom(msg); - mMessages.add(copy); - } else { - if (SystemClock.uptimeMillis() >= uptimeMillis) { - msg.getCallback().run(); - } else { - mPendingCallbacks.add(msg.getCallback()); - } + Message copy = new Message(); + copy.copyFrom(msg); + mMessages.add(copy); + if (msg.getCallback() != null) { + msg.getCallback().run(); msg.setCallback(null); } return super.sendMessageAtTime(msg, uptimeMillis); } - - private void runPendingCallbacks() { - mPendingCallbacks.forEach(Runnable::run); - mPendingCallbacks.clear(); - } } } diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java index 2c1e37beda26..0b2a2cdd26b9 100644 --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java @@ -721,54 +721,56 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { protected static final String SYSTEM_PACKAGE_NAME = "android"; protected static final String CALLING_PACKAGE_1 = "com.android.test.1"; - protected static final int CALLING_UID_1 = 10001; + protected static final int CALLING_UID_1 = 1000001; protected static final String CALLING_PACKAGE_2 = "com.android.test.2"; - protected static final int CALLING_UID_2 = 10002; + protected static final int CALLING_UID_2 = 1000002; protected static final String CALLING_PACKAGE_3 = "com.android.test.3"; - protected static final int CALLING_UID_3 = 10003; + protected static final int CALLING_UID_3 = 1000003; protected static final String CALLING_PACKAGE_4 = "com.android.test.4"; - protected static final int CALLING_UID_4 = 10004; + protected static final int CALLING_UID_4 = 1000004; protected static final String LAUNCHER_1 = "com.android.launcher.1"; - protected static final int LAUNCHER_UID_1 = 10011; + protected static final int LAUNCHER_UID_1 = 1000011; protected static final String LAUNCHER_2 = "com.android.launcher.2"; - protected static final int LAUNCHER_UID_2 = 10012; + protected static final int LAUNCHER_UID_2 = 1000012; protected static final String LAUNCHER_3 = "com.android.launcher.3"; - protected static final int LAUNCHER_UID_3 = 10013; + protected static final int LAUNCHER_UID_3 = 1000013; protected static final String LAUNCHER_4 = "com.android.launcher.4"; - protected static final int LAUNCHER_UID_4 = 10014; + protected static final int LAUNCHER_UID_4 = 1000014; protected static final String CHOOSER_ACTIVITY_PACKAGE = "com.android.intentresolver"; - protected static final int CHOOSER_ACTIVITY_UID = 10015; + protected static final int CHOOSER_ACTIVITY_UID = 1000015; - protected static final int USER_0 = UserHandle.USER_SYSTEM; + // Shifting primary user to 10 to support HSUM protected static final int USER_10 = 10; protected static final int USER_11 = 11; + protected static final int USER_12 = 12; protected static final int USER_P0 = 20; // profile of user 0 (MANAGED_PROFILE *not* set) protected static final int USER_P1 = 21; // another profile of user 0 (MANAGED_PROFILE set) - protected static final UserHandle HANDLE_USER_0 = UserHandle.of(USER_0); protected static final UserHandle HANDLE_USER_10 = UserHandle.of(USER_10); protected static final UserHandle HANDLE_USER_11 = UserHandle.of(USER_11); + protected static final UserHandle HANDLE_USER_12 = UserHandle.of(USER_12); protected static final UserHandle HANDLE_USER_P0 = UserHandle.of(USER_P0); protected static final UserHandle HANDLE_USER_P1 = UserHandle.of(USER_P1); - protected static final UserInfo USER_INFO_0 = withProfileGroupId( - new UserInfo(USER_0, "user0", - UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED), 0); - - protected static final UserInfo USER_INFO_10 = - new UserInfo(USER_10, "user10", UserInfo.FLAG_INITIALIZED); + protected static final UserInfo USER_INFO_10 = withProfileGroupId( + new UserInfo(USER_10, "user10", + UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED), + USER_10); protected static final UserInfo USER_INFO_11 = new UserInfo(USER_11, "user11", UserInfo.FLAG_INITIALIZED); + protected static final UserInfo USER_INFO_12 = + new UserInfo(USER_12, "user12", UserInfo.FLAG_INITIALIZED); + /* * Cheat: USER_P0 is a sub profile of USER_0, but it doesn't have the MANAGED_PROFILE flag set. * Due to a change made to LauncherApps (b/34340531), work profile apps a no longer able @@ -778,11 +780,11 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { * can't access main profile's shortcuts.) */ protected static final UserInfo USER_INFO_P0 = withProfileGroupId( - new UserInfo(USER_P0, "userP0", UserInfo.FLAG_INITIALIZED), 0); + new UserInfo(USER_P0, "userP0", UserInfo.FLAG_INITIALIZED), USER_10); protected static final UserInfo USER_INFO_P1 = withProfileGroupId( new UserInfo(USER_P1, "userP1", - UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_MANAGED_PROFILE), 0); + UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_MANAGED_PROFILE), USER_10); protected static final UserProperties USER_PROPERTIES_0 = new UserProperties.Builder().setItemsRestrictedOnHomeScreen(false).build(); @@ -925,14 +927,14 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { deleteAllSavedFiles(); // Set up users. - mUserInfos.put(USER_0, USER_INFO_0); mUserInfos.put(USER_10, USER_INFO_10); mUserInfos.put(USER_11, USER_INFO_11); + mUserInfos.put(USER_12, USER_INFO_12); mUserInfos.put(USER_P0, USER_INFO_P0); mUserInfos.put(USER_P1, USER_INFO_P1); - mUserProperties.put(USER_0, USER_PROPERTIES_0); - mUserProperties.put(USER_10, USER_PROPERTIES_10); - mUserProperties.put(USER_11, USER_PROPERTIES_11); + mUserProperties.put(USER_10, USER_PROPERTIES_0); + mUserProperties.put(USER_11, USER_PROPERTIES_10); + mUserProperties.put(USER_12, USER_PROPERTIES_11); when(mMockUserManagerInternal.isUserUnlockingOrUnlocked(anyInt())) .thenAnswer(inv -> { @@ -994,16 +996,16 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { mUserInfos.values().toArray(new UserInfo[0])); // User 0 and P0 are always running - mRunningUsers.put(USER_0, true); - mRunningUsers.put(USER_10, false); + mRunningUsers.put(USER_10, true); mRunningUsers.put(USER_11, false); + mRunningUsers.put(USER_12, false); mRunningUsers.put(USER_P0, true); mRunningUsers.put(USER_P1, true); // Unlock all users by default. - mUnlockedUsers.put(USER_0, true); mUnlockedUsers.put(USER_10, true); mUnlockedUsers.put(USER_11, true); + mUnlockedUsers.put(USER_12, true); mUnlockedUsers.put(USER_P0, true); mUnlockedUsers.put(USER_P1, true); @@ -1391,7 +1393,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { } protected void setCaller(String packageName) { - setCaller(packageName, UserHandle.USER_SYSTEM); + setCaller(packageName, USER_10); } protected String getCallingPackage() { @@ -2223,7 +2225,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { dumpsysOnLogcat("Before backup"); - final byte[] payload = mService.getBackupPayload(USER_0); + final byte[] payload = mService.getBackupPayload(USER_10); if (ENABLE_DUMP) { final String xml = new String(payload); Log.v(TAG, "Backup payload:"); @@ -2233,7 +2235,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { } // Before doing anything else, uninstall all packages. - for (int userId : list(USER_0, USER_P0)) { + for (int userId : list(USER_10, USER_P0)) { for (String pkg : list(CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3, LAUNCHER_1, LAUNCHER_2, LAUNCHER_3)) { uninstallPackage(userId, pkg); @@ -2245,11 +2247,11 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { deleteAllSavedFiles(); initService(); - mService.applyRestore(payload, USER_0); + mService.applyRestore(payload, USER_10); // handleUnlockUser will perform the gone package check, but it shouldn't remove // shadow information. - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); dumpsysOnLogcat("After restore"); @@ -2257,24 +2259,24 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { } protected void prepareCrossProfileDataSet() { - mRunningUsers.put(USER_10, true); // this test needs user 10. + mRunningUsers.put(USER_11, true); // this test needs user 10. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"), makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6")))); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"), makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6")))); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"), makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6")))); }); - runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_4, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list())); }); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { @@ -2282,79 +2284,79 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"), makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6")))); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"), makeShortcut("x4"), makeShortcut("x5"), makeShortcut("x6")))); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s1", "s2"), HANDLE_USER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s1", "s2", "s3"), HANDLE_USER_0); + runWithCaller(LAUNCHER_1, USER_10, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_10); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s1", "s2"), HANDLE_USER_10); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s1", "s2", "s3"), HANDLE_USER_10); mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s4"), HANDLE_USER_P0); }); - runWithCaller(LAUNCHER_2, USER_0, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s2", "s3"), HANDLE_USER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s2", "s3", "s4"), HANDLE_USER_0); + runWithCaller(LAUNCHER_2, USER_10, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_10); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s2", "s3"), HANDLE_USER_10); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s2", "s3", "s4"), HANDLE_USER_10); mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s5"), HANDLE_USER_P0); }); // Note LAUNCHER_3 has allowBackup=false. - runWithCaller(LAUNCHER_3, USER_0, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4"), HANDLE_USER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5"), HANDLE_USER_0); + runWithCaller(LAUNCHER_3, USER_10, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_10); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4"), HANDLE_USER_10); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5"), HANDLE_USER_10); mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s6"), HANDLE_USER_P0); }); - runWithCaller(LAUNCHER_4, USER_0, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), HANDLE_USER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), HANDLE_USER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list(), HANDLE_USER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_4, list(), HANDLE_USER_0); + runWithCaller(LAUNCHER_4, USER_10, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), HANDLE_USER_10); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), HANDLE_USER_10); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list(), HANDLE_USER_10); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_4, list(), HANDLE_USER_10); }); // Launcher on a managed profile is referring ot user 0! runWithCaller(LAUNCHER_1, USER_P0, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s4"), HANDLE_USER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4", "s5"), HANDLE_USER_0); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s4"), HANDLE_USER_10); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4", "s5"), HANDLE_USER_10); mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5", "s6"), - HANDLE_USER_0); + HANDLE_USER_10); mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s4", "s1"), HANDLE_USER_P0); }); - runWithCaller(LAUNCHER_1, USER_10, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("x4", "x5"), HANDLE_USER_10); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("x4", "x5", "x6"), HANDLE_USER_10); + runWithCaller(LAUNCHER_1, USER_11, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("x4", "x5"), HANDLE_USER_11); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("x4", "x5", "x6"), HANDLE_USER_11); mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("x4", "x5", "x6", "x1"), - HANDLE_USER_10); + HANDLE_USER_11); }); // Then remove some dynamic shortcuts. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); - runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_4, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list())); }); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3")))); }); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java index d70ffd2ec050..c01283a236c4 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -285,7 +285,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } public void SetDynamicShortcuts() { - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.icon1); final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource( @@ -338,7 +338,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { dumpsysOnLogcat(); mInjectedCurrentTimeMillis++; // Need to advance the clock for reset to work. - mService.resetThrottlingInner(UserHandle.USER_SYSTEM); + mService.resetThrottlingInner(USER_10); dumpsysOnLogcat(); @@ -347,15 +347,15 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // TODO Check max number - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_11, () -> { assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1")))); }); } public void AddDynamicShortcuts() { - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); final ShortcutInfo si1 = makeShortcut("shortcut1"); final ShortcutInfo si2 = makeShortcut("shortcut2"); @@ -395,9 +395,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // TODO Check fields. - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_11, () -> { assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1")))); }); } @@ -406,7 +406,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Change the max number of shortcuts. mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=5," + ShortcutService.ConfigConstants.KEY_SAVE_DELAY_MILLIS + "=1"); - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); final ShortcutInfo s1 = makeShortcut("s1"); final ShortcutInfo s2 = makeShortcut("s2"); @@ -420,10 +420,11 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Test push as first shortcut mManager.pushDynamicShortcut(s1); + setCaller(CALLING_PACKAGE_1, USER_10); assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()), "s1"); assertEquals(0, getCallerShortcut("s1").getRank()); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( - eq(CALLING_PACKAGE_1), eq("s1"), eq(USER_0)); + eq(CALLING_PACKAGE_1), eq("s1"), eq(USER_10)); // Test push when other shortcuts exist Mockito.reset(mMockUsageStatsManagerInternal); @@ -436,11 +437,11 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(1, getCallerShortcut("s1").getRank()); assertEquals(2, getCallerShortcut("s2").getRank()); verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage( - eq(CALLING_PACKAGE_1), eq("s1"), eq(USER_0)); + eq(CALLING_PACKAGE_1), eq("s1"), eq(USER_10)); verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage( - eq(CALLING_PACKAGE_1), eq("s2"), eq(USER_0)); + eq(CALLING_PACKAGE_1), eq("s2"), eq(USER_10)); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( - eq(CALLING_PACKAGE_1), eq("s3"), eq(USER_0)); + eq(CALLING_PACKAGE_1), eq("s3"), eq(USER_10)); mInjectedCurrentTimeMillis += INTERVAL; // reset @@ -451,7 +452,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(2, getCallerShortcut("s4").getRank()); assertEquals(3, getCallerShortcut("s2").getRank()); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( - eq(CALLING_PACKAGE_1), eq("s4"), eq(USER_0)); + eq(CALLING_PACKAGE_1), eq("s4"), eq(USER_10)); // Push existing shortcut with set rank Mockito.reset(mMockUsageStatsManagerInternal); @@ -461,7 +462,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(2, getCallerShortcut("s2").getRank()); assertEquals(3, getCallerShortcut("s4").getRank()); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( - eq(CALLING_PACKAGE_1), eq("s4"), eq(USER_0)); + eq(CALLING_PACKAGE_1), eq("s4"), eq(USER_10)); mInjectedCurrentTimeMillis += INTERVAL; // reset @@ -476,7 +477,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(3, getCallerShortcut("s2").getRank()); assertEquals(4, getCallerShortcut("s4").getRank()); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( - eq(CALLING_PACKAGE_1), eq("s5"), eq(USER_0)); + eq(CALLING_PACKAGE_1), eq("s5"), eq(USER_10)); // Push when max has already reached Mockito.reset(mMockUsageStatsManagerInternal); @@ -487,7 +488,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(1, getCallerShortcut("s5").getRank()); assertEquals(4, getCallerShortcut("s2").getRank()); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( - eq(CALLING_PACKAGE_1), eq("s6"), eq(USER_0)); + eq(CALLING_PACKAGE_1), eq("s6"), eq(USER_10)); mInjectedCurrentTimeMillis += INTERVAL; // reset @@ -499,7 +500,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { getCallerShortcut("s7").getActivity()); assertEquals(0, getCallerShortcut("s7").getRank()); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( - eq(CALLING_PACKAGE_1), eq("s7"), eq(USER_0)); + eq(CALLING_PACKAGE_1), eq("s7"), eq(USER_10)); // Push to update shortcut with different activity Mockito.reset(mMockUsageStatsManagerInternal); @@ -514,7 +515,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(2, getCallerShortcut("s3").getRank()); assertEquals(3, getCallerShortcut("s2").getRank()); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( - eq(CALLING_PACKAGE_1), eq("s1"), eq(USER_0)); + eq(CALLING_PACKAGE_1), eq("s1"), eq(USER_10)); mInjectedCurrentTimeMillis += INTERVAL; // reset @@ -524,12 +525,12 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { s8.setRank(100); mManager.pushDynamicShortcut(s8); assertEquals(4, getCallerShortcut("s8").getRank()); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mInjectCheckAccessShortcutsPermission = true; - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s8"), HANDLE_USER_0, + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s8"), HANDLE_USER_10, CACHE_OWNER_0); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( - eq(CALLING_PACKAGE_1), eq("s8"), eq(USER_0)); + eq(CALLING_PACKAGE_1), eq("s8"), eq(USER_10)); }); Mockito.reset(mMockUsageStatsManagerInternal); @@ -540,7 +541,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED), "s8"); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( - eq(CALLING_PACKAGE_1), eq("s9"), eq(USER_0)); + eq(CALLING_PACKAGE_1), eq("s9"), eq(USER_10)); } public void PushDynamicShortcut_CallsToUsageStatsManagerAreThrottled() @@ -549,13 +550,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { ShortcutService.ConfigConstants.KEY_SAVE_DELAY_MILLIS + "=500"); // Verify calls to UsageStatsManagerInternal#reportShortcutUsage are throttled. - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); { final ShortcutInfo si = makeShortcut("s0"); mManager.pushDynamicShortcut(si); } verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( - eq(CALLING_PACKAGE_1), eq("s0"), eq(USER_0)); + eq(CALLING_PACKAGE_1), eq("s0"), eq(USER_10)); Mockito.reset(mMockUsageStatsManagerInternal); for (int i = 2; i <= 10; i++) { final ShortcutInfo si = makeShortcut("s" + i); @@ -565,13 +566,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { any(), any(), anyInt()); // Verify pkg2 isn't blocked by pkg1, but consecutive calls from pkg2 are throttled as well. - setCaller(CALLING_PACKAGE_2, USER_0); + setCaller(CALLING_PACKAGE_2, USER_10); { final ShortcutInfo si = makeShortcut("s1"); mManager.pushDynamicShortcut(si); } verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( - eq(CALLING_PACKAGE_2), eq("s1"), eq(USER_0)); + eq(CALLING_PACKAGE_2), eq("s1"), eq(USER_10)); Mockito.reset(mMockUsageStatsManagerInternal); for (int i = 2; i <= 10; i++) { final ShortcutInfo si = makeShortcut("s" + i); @@ -584,18 +585,18 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Let time passes which resets the throttle Thread.sleep(505); // Verify UsageStatsManagerInternal#reportShortcutUsed can be called again - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); mManager.pushDynamicShortcut(makeShortcut("s10")); - setCaller(CALLING_PACKAGE_2, USER_0); + setCaller(CALLING_PACKAGE_2, USER_10); mManager.pushDynamicShortcut(makeShortcut("s10")); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( - eq(CALLING_PACKAGE_1), any(), eq(USER_0)); + eq(CALLING_PACKAGE_1), any(), eq(USER_10)); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( - eq(CALLING_PACKAGE_2), any(), eq(USER_0)); + eq(CALLING_PACKAGE_2), any(), eq(USER_10)); } public void UnlimitedCalls() { - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); final ShortcutInfo si1 = makeShortcut("shortcut1"); @@ -628,9 +629,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { public void PublishWithNoActivity() { // If activity is not explicitly set, use the default one. - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_11, () -> { // s1 and s3 has no activities. final ShortcutInfo si1 = new ShortcutInfo.Builder(mClientContext, "si1") .setShortLabel("label1") @@ -732,9 +733,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } public void PublishWithNoActivity_noMainActivityInPackage() { - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_11, () -> { final ShortcutInfo si1 = new ShortcutInfo.Builder(mClientContext, "si1") .setShortLabel("label1") .setIntent(new Intent("action1")) @@ -905,35 +906,35 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { setCaller(LAUNCHER_1); // Check hasIconResource()/hasIconFile(). assertShortcutIds(assertAllHaveIconResId( - list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res32x32", USER_0))), + list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res32x32", USER_10))), "res32x32"); assertShortcutIds(assertAllHaveIconResId( - list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res64x64", USER_0))), + list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res64x64", USER_10))), "res64x64"); assertShortcutIds(assertAllHaveIconFile( - list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_0))), + list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_10))), "bmp32x32"); assertShortcutIds(assertAllHaveIconFile( - list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp64x64", USER_0))), + list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp64x64", USER_10))), "bmp64x64"); assertShortcutIds(assertAllHaveIconFile( - list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp512x512", USER_0))), + list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp512x512", USER_10))), "bmp512x512"); assertShortcutIds(assertAllHaveIconUri( - list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "uri32x32", USER_0))), + list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "uri32x32", USER_10))), "uri32x32"); assertShortcutIds(assertAllHaveIconUri( - list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "uri64x64", USER_0))), + list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "uri64x64", USER_10))), "uri64x64"); assertShortcutIds(assertAllHaveIconUri( - list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "uri512x512", USER_0))), + list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "uri512x512", USER_10))), "uri512x512"); assertShortcutIds(assertAllHaveIconResId( @@ -947,36 +948,36 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals( R.drawable.black_32x32, mLauncherApps.getShortcutIconResId( - getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res32x32", USER_0))); + getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res32x32", USER_10))); assertEquals( R.drawable.black_64x64, mLauncherApps.getShortcutIconResId( - getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res64x64", USER_0))); + getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res64x64", USER_10))); assertEquals( 0, // because it's not a resource mLauncherApps.getShortcutIconResId( - getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_0))); + getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_10))); assertEquals( 0, // because it's not a resource mLauncherApps.getShortcutIconResId( - getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp64x64", USER_0))); + getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp64x64", USER_10))); assertEquals( 0, // because it's not a resource mLauncherApps.getShortcutIconResId( - getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp512x512", USER_0))); + getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp512x512", USER_10))); bmp = pfdToBitmap(mLauncherApps.getShortcutIconFd( - getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_0))); + getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_10))); assertBitmapSize(32, 32, bmp); bmp = pfdToBitmap(mLauncherApps.getShortcutIconFd( - getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp64x64", USER_0))); + getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp64x64", USER_10))); assertBitmapSize(64, 64, bmp); bmp = pfdToBitmap(mLauncherApps.getShortcutIconFd( - getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp512x512", USER_0))); + getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp512x512", USER_10))); assertBitmapSize(128, 128, bmp); assertEquals( @@ -991,10 +992,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Also check the overload APIs too. assertEquals( R.drawable.black_32x32, - mLauncherApps.getShortcutIconResId(CALLING_PACKAGE_1, "res32x32", HANDLE_USER_0)); + mLauncherApps.getShortcutIconResId(CALLING_PACKAGE_1, "res32x32", HANDLE_USER_10)); assertEquals( R.drawable.black_64x64, - mLauncherApps.getShortcutIconResId(CALLING_PACKAGE_1, "res64x64", HANDLE_USER_0)); + mLauncherApps.getShortcutIconResId(CALLING_PACKAGE_1, "res64x64", HANDLE_USER_10)); assertEquals( R.drawable.black_512x512, mLauncherApps.getShortcutIconResId(CALLING_PACKAGE_1, "res32x32", HANDLE_USER_P0)); @@ -1035,14 +1036,14 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } public void CleanupDanglingBitmaps() throws Exception { - assertBitmapDirectories(USER_0, EMPTY_STRINGS); assertBitmapDirectories(USER_10, EMPTY_STRINGS); + assertBitmapDirectories(USER_11, EMPTY_STRINGS); // Make some shortcuts with bitmap icons. final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.black_32x32)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.setDynamicShortcuts(list( makeShortcutWithIcon("s1", bmp32x32), makeShortcutWithIcon("s2", bmp32x32), @@ -1053,7 +1054,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Increment the time (which actually we don't have to), which is used for filenames. mInjectedCurrentTimeMillis++; - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { mManager.setDynamicShortcuts(list( makeShortcutWithIcon("s4", bmp32x32), makeShortcutWithIcon("s5", bmp32x32), @@ -1064,29 +1065,29 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Increment the time, which is used for filenames. mInjectedCurrentTimeMillis++; - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { mManager.setDynamicShortcuts(list( )); }); // For USER-10, let's try without updating the times. - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { mManager.setDynamicShortcuts(list( makeShortcutWithIcon("10s1", bmp32x32), makeShortcutWithIcon("10s2", bmp32x32), makeShortcutWithIcon("10s3", bmp32x32) )); }); - runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_11, () -> { mManager.setDynamicShortcuts(list( makeShortcutWithIcon("10s4", bmp32x32), makeShortcutWithIcon("10s5", bmp32x32), makeShortcutWithIcon("10s6", bmp32x32) )); }); - runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_11, () -> { mManager.setDynamicShortcuts(list( )); }); @@ -1096,102 +1097,102 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mService.waitForBitmapSavesForTest(); // Check files and directories. // Package 3 has no bitmaps, so we don't create a directory. - assertBitmapDirectories(USER_0, CALLING_PACKAGE_1, CALLING_PACKAGE_2); assertBitmapDirectories(USER_10, CALLING_PACKAGE_1, CALLING_PACKAGE_2); + assertBitmapDirectories(USER_11, CALLING_PACKAGE_1, CALLING_PACKAGE_2); - assertBitmapFiles(USER_0, CALLING_PACKAGE_1, - getBitmapFilename(USER_0, CALLING_PACKAGE_1, "s1"), - getBitmapFilename(USER_0, CALLING_PACKAGE_1, "s2"), - getBitmapFilename(USER_0, CALLING_PACKAGE_1, "s3") + assertBitmapFiles(USER_10, CALLING_PACKAGE_1, + getBitmapFilename(USER_10, CALLING_PACKAGE_1, "s1"), + getBitmapFilename(USER_10, CALLING_PACKAGE_1, "s2"), + getBitmapFilename(USER_10, CALLING_PACKAGE_1, "s3") ); - assertBitmapFiles(USER_0, CALLING_PACKAGE_2, - getBitmapFilename(USER_0, CALLING_PACKAGE_2, "s4"), - getBitmapFilename(USER_0, CALLING_PACKAGE_2, "s5"), - getBitmapFilename(USER_0, CALLING_PACKAGE_2, "s6") + assertBitmapFiles(USER_10, CALLING_PACKAGE_2, + getBitmapFilename(USER_10, CALLING_PACKAGE_2, "s4"), + getBitmapFilename(USER_10, CALLING_PACKAGE_2, "s5"), + getBitmapFilename(USER_10, CALLING_PACKAGE_2, "s6") ); - assertBitmapFiles(USER_0, CALLING_PACKAGE_3, + assertBitmapFiles(USER_10, CALLING_PACKAGE_3, EMPTY_STRINGS ); - assertBitmapFiles(USER_10, CALLING_PACKAGE_1, - getBitmapFilename(USER_10, CALLING_PACKAGE_1, "10s1"), - getBitmapFilename(USER_10, CALLING_PACKAGE_1, "10s2"), - getBitmapFilename(USER_10, CALLING_PACKAGE_1, "10s3") + assertBitmapFiles(USER_11, CALLING_PACKAGE_1, + getBitmapFilename(USER_11, CALLING_PACKAGE_1, "10s1"), + getBitmapFilename(USER_11, CALLING_PACKAGE_1, "10s2"), + getBitmapFilename(USER_11, CALLING_PACKAGE_1, "10s3") ); - assertBitmapFiles(USER_10, CALLING_PACKAGE_2, - getBitmapFilename(USER_10, CALLING_PACKAGE_2, "10s4"), - getBitmapFilename(USER_10, CALLING_PACKAGE_2, "10s5"), - getBitmapFilename(USER_10, CALLING_PACKAGE_2, "10s6") + assertBitmapFiles(USER_11, CALLING_PACKAGE_2, + getBitmapFilename(USER_11, CALLING_PACKAGE_2, "10s4"), + getBitmapFilename(USER_11, CALLING_PACKAGE_2, "10s5"), + getBitmapFilename(USER_11, CALLING_PACKAGE_2, "10s6") ); - assertBitmapFiles(USER_10, CALLING_PACKAGE_3, + assertBitmapFiles(USER_11, CALLING_PACKAGE_3, EMPTY_STRINGS ); // Then create random directories and files. - makeFile(mService.getUserBitmapFilePath(USER_0), "a.b.c").mkdir(); - makeFile(mService.getUserBitmapFilePath(USER_0), "d.e.f").mkdir(); - makeFile(mService.getUserBitmapFilePath(USER_0), "d.e.f", "123").createNewFile(); - makeFile(mService.getUserBitmapFilePath(USER_0), "d.e.f", "456").createNewFile(); + makeFile(mService.getUserBitmapFilePath(USER_10), "a.b.c").mkdir(); + makeFile(mService.getUserBitmapFilePath(USER_10), "d.e.f").mkdir(); + makeFile(mService.getUserBitmapFilePath(USER_10), "d.e.f", "123").createNewFile(); + makeFile(mService.getUserBitmapFilePath(USER_10), "d.e.f", "456").createNewFile(); - makeFile(mService.getUserBitmapFilePath(USER_0), CALLING_PACKAGE_3).mkdir(); + makeFile(mService.getUserBitmapFilePath(USER_10), CALLING_PACKAGE_3).mkdir(); - makeFile(mService.getUserBitmapFilePath(USER_0), CALLING_PACKAGE_1, "1").createNewFile(); - makeFile(mService.getUserBitmapFilePath(USER_0), CALLING_PACKAGE_1, "2").createNewFile(); - makeFile(mService.getUserBitmapFilePath(USER_0), CALLING_PACKAGE_1, "3").createNewFile(); - makeFile(mService.getUserBitmapFilePath(USER_0), CALLING_PACKAGE_1, "4").createNewFile(); + makeFile(mService.getUserBitmapFilePath(USER_10), CALLING_PACKAGE_1, "1").createNewFile(); + makeFile(mService.getUserBitmapFilePath(USER_10), CALLING_PACKAGE_1, "2").createNewFile(); + makeFile(mService.getUserBitmapFilePath(USER_10), CALLING_PACKAGE_1, "3").createNewFile(); + makeFile(mService.getUserBitmapFilePath(USER_10), CALLING_PACKAGE_1, "4").createNewFile(); - makeFile(mService.getUserBitmapFilePath(USER_10), "10a.b.c").mkdir(); - makeFile(mService.getUserBitmapFilePath(USER_10), "10d.e.f").mkdir(); - makeFile(mService.getUserBitmapFilePath(USER_10), "10d.e.f", "123").createNewFile(); - makeFile(mService.getUserBitmapFilePath(USER_10), "10d.e.f", "456").createNewFile(); + makeFile(mService.getUserBitmapFilePath(USER_11), "10a.b.c").mkdir(); + makeFile(mService.getUserBitmapFilePath(USER_11), "10d.e.f").mkdir(); + makeFile(mService.getUserBitmapFilePath(USER_11), "10d.e.f", "123").createNewFile(); + makeFile(mService.getUserBitmapFilePath(USER_11), "10d.e.f", "456").createNewFile(); - makeFile(mService.getUserBitmapFilePath(USER_10), CALLING_PACKAGE_2, "1").createNewFile(); - makeFile(mService.getUserBitmapFilePath(USER_10), CALLING_PACKAGE_2, "2").createNewFile(); - makeFile(mService.getUserBitmapFilePath(USER_10), CALLING_PACKAGE_2, "3").createNewFile(); - makeFile(mService.getUserBitmapFilePath(USER_10), CALLING_PACKAGE_2, "4").createNewFile(); + makeFile(mService.getUserBitmapFilePath(USER_11), CALLING_PACKAGE_2, "1").createNewFile(); + makeFile(mService.getUserBitmapFilePath(USER_11), CALLING_PACKAGE_2, "2").createNewFile(); + makeFile(mService.getUserBitmapFilePath(USER_11), CALLING_PACKAGE_2, "3").createNewFile(); + makeFile(mService.getUserBitmapFilePath(USER_11), CALLING_PACKAGE_2, "4").createNewFile(); mService.waitForBitmapSavesForTest(); - assertBitmapDirectories(USER_0, CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3, + assertBitmapDirectories(USER_10, CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3, "a.b.c", "d.e.f"); // Save and load. When a user is loaded, we do the cleanup. mService.saveDirtyInfo(); initService(); - mService.handleUnlockUser(USER_0); mService.handleUnlockUser(USER_10); + mService.handleUnlockUser(USER_11); mService.handleUnlockUser(20); // Make sure the logic will still work for nonexistent user. // The below check is the same as above, except this time USER_0 use the CALLING_PACKAGE_3 // directory. mService.waitForBitmapSavesForTest(); - assertBitmapDirectories(USER_0, CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3); - assertBitmapDirectories(USER_10, CALLING_PACKAGE_1, CALLING_PACKAGE_2); + assertBitmapDirectories(USER_10, CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3); + assertBitmapDirectories(USER_11, CALLING_PACKAGE_1, CALLING_PACKAGE_2); - assertBitmapFiles(USER_0, CALLING_PACKAGE_1, - getBitmapFilename(USER_0, CALLING_PACKAGE_1, "s1"), - getBitmapFilename(USER_0, CALLING_PACKAGE_1, "s2"), - getBitmapFilename(USER_0, CALLING_PACKAGE_1, "s3") + assertBitmapFiles(USER_10, CALLING_PACKAGE_1, + getBitmapFilename(USER_10, CALLING_PACKAGE_1, "s1"), + getBitmapFilename(USER_10, CALLING_PACKAGE_1, "s2"), + getBitmapFilename(USER_10, CALLING_PACKAGE_1, "s3") ); - assertBitmapFiles(USER_0, CALLING_PACKAGE_2, - getBitmapFilename(USER_0, CALLING_PACKAGE_2, "s4"), - getBitmapFilename(USER_0, CALLING_PACKAGE_2, "s5"), - getBitmapFilename(USER_0, CALLING_PACKAGE_2, "s6") + assertBitmapFiles(USER_10, CALLING_PACKAGE_2, + getBitmapFilename(USER_10, CALLING_PACKAGE_2, "s4"), + getBitmapFilename(USER_10, CALLING_PACKAGE_2, "s5"), + getBitmapFilename(USER_10, CALLING_PACKAGE_2, "s6") ); - assertBitmapFiles(USER_0, CALLING_PACKAGE_3, + assertBitmapFiles(USER_10, CALLING_PACKAGE_3, EMPTY_STRINGS ); - assertBitmapFiles(USER_10, CALLING_PACKAGE_1, - getBitmapFilename(USER_10, CALLING_PACKAGE_1, "10s1"), - getBitmapFilename(USER_10, CALLING_PACKAGE_1, "10s2"), - getBitmapFilename(USER_10, CALLING_PACKAGE_1, "10s3") + assertBitmapFiles(USER_11, CALLING_PACKAGE_1, + getBitmapFilename(USER_11, CALLING_PACKAGE_1, "10s1"), + getBitmapFilename(USER_11, CALLING_PACKAGE_1, "10s2"), + getBitmapFilename(USER_11, CALLING_PACKAGE_1, "10s3") ); - assertBitmapFiles(USER_10, CALLING_PACKAGE_2, - getBitmapFilename(USER_10, CALLING_PACKAGE_2, "10s4"), - getBitmapFilename(USER_10, CALLING_PACKAGE_2, "10s5"), - getBitmapFilename(USER_10, CALLING_PACKAGE_2, "10s6") + assertBitmapFiles(USER_11, CALLING_PACKAGE_2, + getBitmapFilename(USER_11, CALLING_PACKAGE_2, "10s4"), + getBitmapFilename(USER_11, CALLING_PACKAGE_2, "10s5"), + getBitmapFilename(USER_11, CALLING_PACKAGE_2, "10s6") ); - assertBitmapFiles(USER_10, CALLING_PACKAGE_3, + assertBitmapFiles(USER_11, CALLING_PACKAGE_3, EMPTY_STRINGS ); } @@ -1301,7 +1302,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } public void UpdateShortcuts() { - runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), @@ -1310,7 +1311,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { makeShortcut("s5") ))); }); - runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), @@ -1319,22 +1320,22 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { makeShortcut("s5") ))); }); - runWithCaller(LAUNCHER_1, UserHandle.USER_SYSTEM, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s3"), getCallingUser()); mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s4", "s5"), getCallingUser()); }); - runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.removeDynamicShortcuts(list("s1")); mManager.removeDynamicShortcuts(list("s2")); }); - runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { mManager.removeDynamicShortcuts(list("s1")); mManager.removeDynamicShortcuts(list("s3")); mManager.removeDynamicShortcuts(list("s5")); }); - runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllDynamic( mManager.getDynamicShortcuts()), "s3", "s4", "s5"); @@ -1342,7 +1343,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mManager.getPinnedShortcuts()), "s2", "s3"); }); - runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertShortcutIds(assertAllDynamic( mManager.getDynamicShortcuts()), "s2", "s4"); @@ -1351,7 +1352,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { "s4", "s5"); }); - runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { ShortcutInfo s2 = makeShortcutBuilder() .setId("s2") .setIcon(Icon.createWithResource(getTestContext(), R.drawable.black_32x32)) @@ -1364,7 +1365,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mManager.updateShortcuts(list(s2, s4)); }); - runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { ShortcutInfo s2 = makeShortcutBuilder() .setId("s2") .setIntent(makeIntent(Intent.ACTION_ANSWER, ShortcutActivity.class, @@ -1379,7 +1380,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mManager.updateShortcuts(list(s2, s4)); }); - runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllDynamic( mManager.getDynamicShortcuts()), "s3", "s4", "s5"); @@ -1398,7 +1399,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(0, s.getIconResourceId()); assertEquals("new title", s.getTitle()); }); - runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertShortcutIds(assertAllDynamic( mManager.getDynamicShortcuts()), "s2", "s4"); @@ -1424,15 +1425,15 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // TODO Check bitmap removal too. - mRunningUsers.put(USER_11, true); + mRunningUsers.put(USER_12, true); - runWithCaller(CALLING_PACKAGE_2, USER_11, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_12, () -> { mManager.updateShortcuts(list()); }); } public void UpdateShortcuts_icons() { - runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1") ))); @@ -1533,26 +1534,26 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_3); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeLongLivedShortcut("s1"), makeLongLivedShortcut("s2"), makeShortcut("s3")))); }); // Pin 2 and 3 - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "ms3", "s2", "s3"), - HANDLE_USER_0); + HANDLE_USER_10); }); // Cache 1 and 2 - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mInjectCheckAccessShortcutsPermission = true; mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1"), - HANDLE_USER_0, CACHE_OWNER_0); + HANDLE_USER_10, CACHE_OWNER_0); mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), - HANDLE_USER_0, CACHE_OWNER_1); + HANDLE_USER_10, CACHE_OWNER_1); }); setCaller(CALLING_PACKAGE_1); @@ -1617,7 +1618,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } public void CachedShortcuts() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"), makeLongLivedShortcut("s2"), makeLongLivedShortcut("s3"), makeLongLivedShortcut("s4"), makeLongLivedShortcut("s5"), @@ -1625,20 +1626,20 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Pin s2 - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), - HANDLE_USER_0); + HANDLE_USER_10); }); // Cache some, but non long lived shortcuts will be ignored. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mInjectCheckAccessShortcutsPermission = true; mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), - HANDLE_USER_0, CACHE_OWNER_0); + HANDLE_USER_10, CACHE_OWNER_0); mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2", "s4", "s5"), - HANDLE_USER_0, CACHE_OWNER_1); + HANDLE_USER_10, CACHE_OWNER_1); mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s5", "s6"), - HANDLE_USER_0, CACHE_OWNER_2); + HANDLE_USER_10, CACHE_OWNER_2); }); setCaller(CALLING_PACKAGE_1); @@ -1660,32 +1661,32 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED), "s2", "s4", "s5", "s6"); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s2", "s4"), - HANDLE_USER_0, CACHE_OWNER_0); + HANDLE_USER_10, CACHE_OWNER_0); }); // s2 still cached by owner1. s4 wasn't cached by owner0 so didn't get removed. assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED), "s2", "s4", "s5", "s6"); // uncache a non-dynamic shortcut. Should be removed. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s4"), - HANDLE_USER_0, CACHE_OWNER_1); + HANDLE_USER_10, CACHE_OWNER_1); }); // uncache s6 by its only owner. s5 still cached by owner1 - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s5", "s6"), - HANDLE_USER_0, CACHE_OWNER_2); + HANDLE_USER_10, CACHE_OWNER_2); }); assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED), "s2", "s5"); // Cache another shortcut - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s3"), - HANDLE_USER_0, CACHE_OWNER_0); + HANDLE_USER_10, CACHE_OWNER_0); }); assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED), "s2", "s3", "s5"); @@ -1701,24 +1702,24 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } public void CachedShortcuts_accessShortcutsPermission() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"), makeLongLivedShortcut("s2"), makeLongLivedShortcut("s3"), makeLongLivedShortcut("s4")))); }); // s1 is not long lived and will be ignored. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mInjectCheckAccessShortcutsPermission = false; assertExpectException( SecurityException.class, "Caller can't access shortcut information", () -> { mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3"), - HANDLE_USER_0, CACHE_OWNER_0); + HANDLE_USER_10, CACHE_OWNER_0); }); // Give ACCESS_SHORTCUTS permission to LAUNCHER_1 mInjectCheckAccessShortcutsPermission = true; mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3"), - HANDLE_USER_0, CACHE_OWNER_0); + HANDLE_USER_10, CACHE_OWNER_0); }); setCaller(CALLING_PACKAGE_1); @@ -1726,17 +1727,17 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Get cached shortcuts assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED), "s2", "s3"); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mInjectCheckAccessShortcutsPermission = false; assertExpectException( SecurityException.class, "Caller can't access shortcut information", () -> { mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s2", "s4"), - HANDLE_USER_0, CACHE_OWNER_0); + HANDLE_USER_10, CACHE_OWNER_0); }); // Give ACCESS_SHORTCUTS permission to LAUNCHER_1 mInjectCheckAccessShortcutsPermission = true; mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s2", "s4"), - HANDLE_USER_0, CACHE_OWNER_0); + HANDLE_USER_10, CACHE_OWNER_0); }); assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED), "s3"); @@ -1746,17 +1747,17 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Change the max number of shortcuts. mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=4"); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list(makeLongLivedShortcut("s1"), makeLongLivedShortcut("s2"), makeLongLivedShortcut("s3"), makeLongLivedShortcut("s4")))); }); // Cache All - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mInjectCheckAccessShortcutsPermission = true; mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3", "s4"), - HANDLE_USER_0, CACHE_OWNER_0); + HANDLE_USER_10, CACHE_OWNER_0); }); setCaller(CALLING_PACKAGE_1); @@ -2004,17 +2005,17 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_3); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); // Pin 2 and 3 - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "ms3", "s2", "s3"), - HANDLE_USER_0); + HANDLE_USER_10); }); // Remove ms3 and s3 @@ -2023,15 +2024,15 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2")))); }); // Check their status. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2", "ms3", "s1", "s2", "s3") @@ -2071,45 +2072,45 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Finally, actual tests. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { assertWith(mLauncherApps.getShortcuts( - buildQueryWithFlags(ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)) + buildQueryWithFlags(ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)) .haveIds("s1", "s2"); assertWith(mLauncherApps.getShortcuts( - buildQueryWithFlags(ShortcutQuery.FLAG_GET_MANIFEST), HANDLE_USER_0)) + buildQueryWithFlags(ShortcutQuery.FLAG_GET_MANIFEST), HANDLE_USER_10)) .haveIds("ms1", "ms2"); assertWith(mLauncherApps.getShortcuts( - buildQueryWithFlags(ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)) + buildQueryWithFlags(ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)) .haveIds("s2", "s3", "ms2", "ms3"); assertWith(mLauncherApps.getShortcuts( buildQueryWithFlags( ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED - ), HANDLE_USER_0)) + ), HANDLE_USER_10)) .haveIds("s1", "s2", "s3", "ms2", "ms3"); assertWith(mLauncherApps.getShortcuts( buildQueryWithFlags( ShortcutQuery.FLAG_GET_MANIFEST | ShortcutQuery.FLAG_GET_PINNED - ), HANDLE_USER_0)) + ), HANDLE_USER_10)) .haveIds("ms1", "s2", "s3", "ms2", "ms3"); assertWith(mLauncherApps.getShortcuts( buildQueryWithFlags( ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_MANIFEST - ), HANDLE_USER_0)) + ), HANDLE_USER_10)) .haveIds("ms1", "ms2", "s1", "s2"); assertWith(mLauncherApps.getShortcuts( buildQueryWithFlags( ShortcutQuery.FLAG_GET_ALL_KINDS - ), HANDLE_USER_0)) + ), HANDLE_USER_10)) .haveIds("ms1", "ms2", "ms3", "s1", "s2", "s3"); }); } public void GetShortcuts_resolveStrings() throws Exception { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { ShortcutInfo si = new ShortcutInfo.Builder(mClientContext) .setId("id") .setActivity(new ComponentName(mClientContext, "dummy")) @@ -2132,17 +2133,17 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mManager.setDynamicShortcuts(list(si)); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { final ShortcutQuery q = new ShortcutQuery(); q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC); // USER 0 List<ShortcutInfo> ret = assertShortcutIds( - assertAllStringsResolved(mLauncherApps.getShortcuts(q, HANDLE_USER_0)), + assertAllStringsResolved(mLauncherApps.getShortcuts(q, HANDLE_USER_10)), "id"); - assertEquals("string-com.android.test.1-user:0-res:10/en", ret.get(0).getTitle()); - assertEquals("string-com.android.test.1-user:0-res:11/en", ret.get(0).getText()); - assertEquals("string-com.android.test.1-user:0-res:12/en", + assertEquals("string-com.android.test.1-user:10-res:10/en", ret.get(0).getTitle()); + assertEquals("string-com.android.test.1-user:10-res:11/en", ret.get(0).getText()); + assertEquals("string-com.android.test.1-user:10-res:12/en", ret.get(0).getDisabledMessage()); // USER P0 @@ -2280,27 +2281,27 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } public void PinShortcutAndGetPinnedShortcuts() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { final ShortcutInfo s1_1 = makeShortcutWithTimestamp("s1", 1000); final ShortcutInfo s1_2 = makeShortcutWithTimestamp("s2", 2000); assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2))); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { final ShortcutInfo s2_2 = makeShortcutWithTimestamp("s2", 1500); final ShortcutInfo s2_3 = makeShortcutWithTimestamp("s3", 3000); final ShortcutInfo s2_4 = makeShortcutWithTimestamp("s4", 500); assertTrue(mManager.setDynamicShortcuts(list(s2_2, s2_3, s2_4))); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { final ShortcutInfo s3_2 = makeShortcutWithTimestamp("s2", 1000); assertTrue(mManager.setDynamicShortcuts(list(s3_2))); }); // Pin some. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s3"), getCallingUser()); @@ -2312,7 +2313,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Delete some. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(mManager.getPinnedShortcuts(), "s2"); mManager.removeDynamicShortcuts(list("s2")); assertShortcutIds(mManager.getPinnedShortcuts(), "s2"); @@ -2320,7 +2321,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertShortcutIds(mManager.getDynamicShortcuts(), "s1"); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4"); mManager.removeDynamicShortcuts(list("s3")); assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4"); @@ -2328,7 +2329,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertShortcutIds(mManager.getDynamicShortcuts(), "s2", "s4"); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertShortcutIds(mManager.getPinnedShortcuts() /* none */); mManager.removeDynamicShortcuts(list("s2")); assertShortcutIds(mManager.getPinnedShortcuts() /* none */); @@ -2337,7 +2338,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Get pinned shortcuts from launcher - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // CALLING_PACKAGE_1 deleted s2, but it's pinned, so it still exists. assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(assertAllEnabled( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, @@ -2361,27 +2362,27 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { * does "enable". */ public void DisableAndEnableShortcuts() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { final ShortcutInfo s1_1 = makeShortcutWithTimestamp("s1", 1000); final ShortcutInfo s1_2 = makeShortcutWithTimestamp("s2", 2000); assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2))); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { final ShortcutInfo s2_2 = makeShortcutWithTimestamp("s2", 1500); final ShortcutInfo s2_3 = makeShortcutWithTimestamp("s3", 3000); final ShortcutInfo s2_4 = makeShortcutWithTimestamp("s4", 500); assertTrue(mManager.setDynamicShortcuts(list(s2_2, s2_3, s2_4))); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { final ShortcutInfo s3_2 = makeShortcutWithTimestamp("s2", 1000); assertTrue(mManager.setDynamicShortcuts(list(s3_2))); }); // Pin some. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s3"), getCallingUser()); @@ -2393,7 +2394,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Disable some. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(mManager.getPinnedShortcuts(), "s2"); mManager.updateShortcuts(list( @@ -2406,7 +2407,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertShortcutIds(mManager.getDynamicShortcuts(), "s1"); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4"); // disable should work even if a shortcut is not dynamic, so try calling "remove" first @@ -2418,7 +2419,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertShortcutIds(mManager.getDynamicShortcuts(), "s2", "s4"); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertShortcutIds(mManager.getPinnedShortcuts() /* none */); mManager.disableShortcuts(list("s2")); @@ -2430,7 +2431,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Get pinned shortcuts from launcher - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // CALLING_PACKAGE_1 deleted s2, but it's pinned, so it still exists, and disabled. assertWith(mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())) @@ -2442,7 +2443,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .areAllPinned() .areAllNotWithKeyFieldsOnly() .areAllDisabled(); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_0, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10, ActivityNotFoundException.class); // Here, s4 is still enabled and launchable, but s3 is disabled. @@ -2459,9 +2460,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .selectByIds("s4") .areAllEnabled(); - assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s3", USER_0, + assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s3", USER_10, ActivityNotFoundException.class); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s4", USER_0); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s4", USER_10); assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(assertAllEnabled( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_3, @@ -2469,30 +2470,30 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { /* none */); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.enableShortcuts(list("s2")); assertShortcutIds(mManager.getPinnedShortcuts(), "s2"); assertShortcutIds(mManager.getDynamicShortcuts(), "s1"); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // CALLING_PACKAGE_1 deleted s2, but it's pinned, so it still exists. assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(assertAllEnabled( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))), "s2"); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_10); }); } public void DisableShortcuts_thenRepublish() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts( - CALLING_PACKAGE_1, list("s1", "s2", "s3"), HANDLE_USER_0); + CALLING_PACKAGE_1, list("s1", "s2", "s3"), HANDLE_USER_10); }); mManager.disableShortcuts(list("s1", "s2", "s3")); @@ -2557,12 +2558,12 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { public void PinShortcutAndGetPinnedShortcuts_multi() { // Create some shortcuts. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); @@ -2570,7 +2571,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { dumpsysOnLogcat(); // Pin some. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s4"), getCallingUser()); @@ -2581,7 +2582,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { dumpsysOnLogcat(); // Delete some. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(mManager.getPinnedShortcuts(), "s3"); mManager.removeDynamicShortcuts(list("s3")); assertShortcutIds(mManager.getPinnedShortcuts(), "s3"); @@ -2589,7 +2590,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { dumpsysOnLogcat(); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertShortcutIds(mManager.getPinnedShortcuts(), "s1", "s2"); mManager.removeDynamicShortcuts(list("s1")); mManager.removeDynamicShortcuts(list("s3")); @@ -2599,7 +2600,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { dumpsysOnLogcat(); // Get pinned shortcuts from launcher - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))), @@ -2625,7 +2626,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { dumpsysOnLogcat("Before launcher 2"); - runWithCaller(LAUNCHER_2, USER_0, () -> { + runWithCaller(LAUNCHER_2, USER_10, () -> { // Launcher2 still has no pinned ones. assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, @@ -2698,10 +2699,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { initService(); // Load from file. - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); // Make sure package info is restored too. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))), @@ -2711,7 +2712,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))), "s1", "s2"); }); - runWithCaller(LAUNCHER_2, USER_0, () -> { + runWithCaller(LAUNCHER_2, USER_10, () -> { assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED @@ -2725,20 +2726,20 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Delete all dynamic. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.removeAllDynamicShortcuts(); assertEquals(0, mManager.getDynamicShortcuts().size()); assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3"); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { mManager.removeAllDynamicShortcuts(); assertEquals(0, mManager.getDynamicShortcuts().size()); assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s2", "s1"); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))), @@ -2766,13 +2767,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { "s3"); }); // Re-publish s1. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1")))); assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1"); assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3"); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))), @@ -2789,7 +2790,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Now clear pinned shortcuts. First, from launcher 1. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), getCallingUser()); mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), getCallingUser()); @@ -2800,17 +2801,17 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1"); assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2"); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertEquals(0, mManager.getDynamicShortcuts().size()); assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s2"); }); // Clear all pins from launcher 2. - runWithCaller(LAUNCHER_2, USER_0, () -> { + runWithCaller(LAUNCHER_2, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), getCallingUser()); mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), getCallingUser()); @@ -2821,11 +2822,11 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1"); assertEquals(0, mManager.getPinnedShortcuts().size()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertEquals(0, mManager.getDynamicShortcuts().size()); assertEquals(0, mManager.getPinnedShortcuts().size()); }); @@ -2833,74 +2834,74 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { public void PinShortcutAndGetPinnedShortcuts_assistant() { // Create some shortcuts. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); // Pin some. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s4"), getCallingUser()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1")))); }); - runWithCaller(LAUNCHER_2, USER_0, () -> { + runWithCaller(LAUNCHER_2, USER_10, () -> { final ShortcutQuery allPinned = new ShortcutQuery().setQueryFlags( ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER); - assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_10)) .isEmpty(); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0); - assertShortcutNotLaunched(CALLING_PACKAGE_1, "s3", USER_0); - assertShortcutNotLaunched(CALLING_PACKAGE_1, "s4", USER_0); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_10); + assertShortcutNotLaunched(CALLING_PACKAGE_1, "s3", USER_10); + assertShortcutNotLaunched(CALLING_PACKAGE_1, "s4", USER_10); // Make it the assistant app. - mInternal.setShortcutHostPackage("assistant", LAUNCHER_2, USER_0); - assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_0)) + mInternal.setShortcutHostPackage("assistant", LAUNCHER_2, USER_10); + assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_10)) .haveIds("s3"); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0); - assertShortcutNotLaunched(CALLING_PACKAGE_1, "s4", USER_0); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_10); + assertShortcutNotLaunched(CALLING_PACKAGE_1, "s4", USER_10); - mInternal.setShortcutHostPackage("another-type", LAUNCHER_3, USER_0); - assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_0)) + mInternal.setShortcutHostPackage("another-type", LAUNCHER_3, USER_10); + assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_10)) .haveIds("s3"); - mInternal.setShortcutHostPackage("assistant", null, USER_0); - assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_0)) + mInternal.setShortcutHostPackage("assistant", null, USER_10); + assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_10)) .isEmpty(); - mInternal.setShortcutHostPackage("assistant", LAUNCHER_2, USER_0); - assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_0)) + mInternal.setShortcutHostPackage("assistant", LAUNCHER_2, USER_10); + assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_10)) .haveIds("s3"); - mInternal.setShortcutHostPackage("assistant", LAUNCHER_1, USER_0); - assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_0)) + mInternal.setShortcutHostPackage("assistant", LAUNCHER_1, USER_10); + assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_10)) .isEmpty(); }); } public void PinShortcutAndGetPinnedShortcuts_crossProfile_plusLaunch() { // Create some shortcuts. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"), makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6")))); @@ -2908,33 +2909,33 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Pin some shortcuts and see the result. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, - list("s1"), HANDLE_USER_0); + list("s1"), HANDLE_USER_10); mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, - list("s1", "s2", "s3"), HANDLE_USER_0); + list("s1", "s2", "s3"), HANDLE_USER_10); }); runWithCaller(LAUNCHER_1, USER_P0, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, - list("s2"), HANDLE_USER_0); + list("s2"), HANDLE_USER_10); mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, - list("s2", "s3"), HANDLE_USER_0); + list("s2", "s3"), HANDLE_USER_10); }); runWithCaller(LAUNCHER_2, USER_P0, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, - list("s3"), HANDLE_USER_0); + list("s3"), HANDLE_USER_10); mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, - list("s3"), HANDLE_USER_0); + list("s3"), HANDLE_USER_10); }); - runWithCaller(LAUNCHER_2, USER_10, () -> { + runWithCaller(LAUNCHER_2, USER_11, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, - list("s1", "s2", "s3"), HANDLE_USER_10); + list("s1", "s2", "s3"), HANDLE_USER_11); }); // First, make sure managed profile can't see other profiles. @@ -2945,540 +2946,540 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { | ShortcutQuery.FLAG_MATCH_MANIFEST); // No shortcuts are visible. - assertWith(mLauncherApps.getShortcuts(q, HANDLE_USER_0)).isEmpty(); + assertWith(mLauncherApps.getShortcuts(q, HANDLE_USER_10)).isEmpty(); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_10); // Should have no effects. - assertWith(mLauncherApps.getShortcuts(q, HANDLE_USER_0)).isEmpty(); + assertWith(mLauncherApps.getShortcuts(q, HANDLE_USER_10)).isEmpty(); - assertShortcutNotLaunched(CALLING_PACKAGE_1, "s1", USER_0); + assertShortcutNotLaunched(CALLING_PACKAGE_1, "s1", USER_10); }); // Cross profile pinning. final int PIN_AND_DYNAMIC = ShortcutQuery.FLAG_GET_PINNED | ShortcutQuery.FLAG_GET_DYNAMIC; - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), "s1"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), "s1", "s2", "s3"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), "s1", "s2", "s3"); assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), "s1", "s2", "s3"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), "s1", "s2", "s3"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), "s1", "s2", "s3"); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_10); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_10); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_11, SecurityException.class); }); runWithCaller(LAUNCHER_1, USER_P0, () -> { assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), "s2"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), "s1", "s2", "s3"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), "s1", "s2", "s3"); assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), "s2", "s3"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), "s1", "s2", "s3"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), "s1", "s2", "s3"); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_10); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_10); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_11, SecurityException.class); }); runWithCaller(LAUNCHER_2, USER_P0, () -> { assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), "s3"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), "s1", "s2", "s3"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), "s1", "s2", "s3"); assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), "s3"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), "s1", "s2", "s3"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), "s1", "s2", "s3"); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_10); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_10); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_11, SecurityException.class); }); - runWithCaller(LAUNCHER_2, USER_10, () -> { + runWithCaller(LAUNCHER_2, USER_11, () -> { assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_11)), "s1", "s2", "s3"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_11)), "s1", "s2", "s3", "s4", "s5", "s6"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_11)), "s1", "s2", "s3", "s4", "s5", "s6"); }); // Remove some dynamic shortcuts. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1")))); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1")))); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1")))); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), "s1"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), "s1"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), "s1"); assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), "s1", "s2", "s3"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), "s1"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), "s1", "s2", "s3"); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_0, + assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_10); + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10, ActivityNotFoundException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_0, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10, ActivityNotFoundException.class); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_10); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_11, SecurityException.class); }); runWithCaller(LAUNCHER_1, USER_P0, () -> { assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), "s2"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), "s1"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), "s1", "s2"); assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), "s2", "s3"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), "s1"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), "s1", "s2", "s3"); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_0, + assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_10); + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10, ActivityNotFoundException.class); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_10); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_11, SecurityException.class); }); runWithCaller(LAUNCHER_2, USER_P0, () -> { assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), "s3"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), "s1"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), "s1", "s3"); assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), "s3"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), "s1"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), "s1", "s3"); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_0, + assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_10); + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10, ActivityNotFoundException.class); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_10); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0); - assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s2", USER_0, + assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_10); + assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s2", USER_10, ActivityNotFoundException.class); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_10); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_11, SecurityException.class); }); - runWithCaller(LAUNCHER_2, USER_10, () -> { + runWithCaller(LAUNCHER_2, USER_11, () -> { assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_11)), "s1", "s2", "s3"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_11)), "s1"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_11)), "s1", "s2", "s3"); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_0, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_0, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_0, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s1", USER_0, + assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s1", USER_10, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s2", USER_0, + assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s2", USER_10, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s3", USER_0, + assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s3", USER_10, SecurityException.class); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_10); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_10); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_10); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10, + assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_11); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_11); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_11); + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_11, ActivityNotFoundException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_11, ActivityNotFoundException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_11, ActivityNotFoundException.class); }); // Save & load and make sure we still have the same information. mService.saveDirtyInfo(); initService(); - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), "s1"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), "s1"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), "s1"); assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), "s1", "s2", "s3"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), "s1"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), "s1", "s2", "s3"); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_0, + assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_10); + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10, ActivityNotFoundException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_0, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10, ActivityNotFoundException.class); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_10); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_11, SecurityException.class); }); runWithCaller(LAUNCHER_1, USER_P0, () -> { assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), "s2"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), "s1"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), "s1", "s2"); assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), "s2", "s3"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), "s1"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), "s1", "s2", "s3"); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_0, + assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_10); + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10, ActivityNotFoundException.class); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_10); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_10); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_11, SecurityException.class); }); runWithCaller(LAUNCHER_2, USER_P0, () -> { assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), "s3"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), "s1"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), "s1", "s3"); assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)), "s3"); assertShortcutIds(assertAllDynamic( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)), "s1"); assertShortcutIds(assertAllDynamicOrPinned( mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2, - /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)), + /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)), "s1", "s3"); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_0, + assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_10); + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10, ActivityNotFoundException.class); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_10); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0); - assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s2", USER_0, + assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_10); + assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s2", USER_10, ActivityNotFoundException.class); - assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0); + assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_10); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_11, SecurityException.class); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_11, SecurityException.class); }); } public void StartShortcut() { // Create some shortcuts. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { final ShortcutInfo s1_1 = makeShortcut( "s1", "Title 1", @@ -3503,7 +3504,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3))); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { final ShortcutInfo s2_1 = makeShortcut( "s1", "ABC", @@ -3516,7 +3517,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Pin some. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), getCallingUser()); @@ -3525,12 +3526,12 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Just to make it complicated, delete some. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.removeDynamicShortcuts(list("s2")); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { - final Intent[] intents = launchShortcutAndGetIntents(CALLING_PACKAGE_1, "s1", USER_0); + runWithCaller(LAUNCHER_1, USER_10, () -> { + final Intent[] intents = launchShortcutAndGetIntents(CALLING_PACKAGE_1, "s1", USER_10); assertEquals(ShortcutActivity2.class.getName(), intents[0].getComponent().getClassName()); assertEquals(Intent.ACTION_ASSIST, @@ -3545,25 +3546,25 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals( ShortcutActivity3.class.getName(), - launchShortcutAndGetIntent(CALLING_PACKAGE_1, "s2", USER_0) + launchShortcutAndGetIntent(CALLING_PACKAGE_1, "s2", USER_10) .getComponent().getClassName()); assertEquals( ShortcutActivity.class.getName(), - launchShortcutAndGetIntent(CALLING_PACKAGE_2, "s1", USER_0) + launchShortcutAndGetIntent(CALLING_PACKAGE_2, "s1", USER_10) .getComponent().getClassName()); - assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0); + assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_10); - assertShortcutNotLaunched("no-such-package", "s2", USER_0); - assertShortcutNotLaunched(CALLING_PACKAGE_1, "xxxx", USER_0); + assertShortcutNotLaunched("no-such-package", "s2", USER_10); + assertShortcutNotLaunched(CALLING_PACKAGE_1, "xxxx", USER_10); }); // LAUNCHER_1 is no longer the default launcher setDefaultLauncherChecker((pkg, userId) -> false); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Not the default launcher, but pinned shortcuts are still lauchable. - final Intent[] intents = launchShortcutAndGetIntents(CALLING_PACKAGE_1, "s1", USER_0); + final Intent[] intents = launchShortcutAndGetIntents(CALLING_PACKAGE_1, "s1", USER_10); assertEquals(ShortcutActivity2.class.getName(), intents[0].getComponent().getClassName()); assertEquals(Intent.ACTION_ASSIST, @@ -3577,24 +3578,24 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { intents[1].getFlags()); assertEquals( ShortcutActivity3.class.getName(), - launchShortcutAndGetIntent(CALLING_PACKAGE_1, "s2", USER_0) + launchShortcutAndGetIntent(CALLING_PACKAGE_1, "s2", USER_10) .getComponent().getClassName()); assertEquals( ShortcutActivity.class.getName(), - launchShortcutAndGetIntent(CALLING_PACKAGE_2, "s1", USER_0) + launchShortcutAndGetIntent(CALLING_PACKAGE_2, "s1", USER_10) .getComponent().getClassName()); // Not pinned, so not lauchable. }); // Test inner errors. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Not launchable. doReturn(ActivityManager.START_CLASS_NOT_FOUND) .when(mMockActivityTaskManagerInternal).startActivitiesAsPackage( anyStringOrNull(), anyStringOrNull(), anyInt(), anyOrNull(Intent[].class), anyOrNull(Bundle.class)); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_0, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10, ActivityNotFoundException.class); // Still not launchable. @@ -3603,7 +3604,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .startActivitiesAsPackage( anyStringOrNull(), anyStringOrNull(), anyInt(), anyOrNull(Intent[].class), anyOrNull(Bundle.class)); - assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_0, + assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10, ActivityNotFoundException.class); }); @@ -3618,34 +3619,34 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { + ConfigConstants.KEY_MAX_SHORTCUTS + "=99999999" ); - setCaller(LAUNCHER_1, USER_0); + setCaller(LAUNCHER_1, USER_10); assertForLauncherCallback(mLauncherApps, () -> { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); - }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0) + }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_10) .haveIds("s1", "s2", "s3") .areAllWithKeyFieldsOnly() .areAllDynamic(); // From different package. assertForLauncherCallback(mLauncherApps, () -> { - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); - }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_2, HANDLE_USER_0) + }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_2, HANDLE_USER_10) .haveIds("s1", "s2", "s3") .areAllWithKeyFieldsOnly() .areAllDynamic(); - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); // Different user, callback shouldn't be called. assertForLauncherCallback(mLauncherApps, () -> { - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); @@ -3654,31 +3655,31 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Test for addDynamicShortcuts. assertForLauncherCallback(mLauncherApps, () -> { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s4")))); }); - }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0) + }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_10) .haveIds("s1", "s2", "s3", "s4") .areAllWithKeyFieldsOnly() .areAllDynamic(); // Test for remove assertForLauncherCallback(mLauncherApps, () -> { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.removeDynamicShortcuts(list("s1")); }); - }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0) + }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_10) .haveIds("s2", "s3", "s4") .areAllWithKeyFieldsOnly() .areAllDynamic(); // Test for update assertForLauncherCallback(mLauncherApps, () -> { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.updateShortcuts(list( makeShortcut("s1"), makeShortcut("s2")))); }); - }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0) + }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_10) // All remaining shortcuts will be passed regardless of what's been updated. .haveIds("s2", "s3", "s4") .areAllWithKeyFieldsOnly() @@ -3686,10 +3687,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Test for deleteAll assertForLauncherCallback(mLauncherApps, () -> { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.removeAllDynamicShortcuts(); }); - }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0) + }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_10) .isEmpty(); // Update package1 with manifest shortcuts @@ -3699,24 +3700,24 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); - }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0) + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); + }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_10) .areAllManifest() .areAllWithKeyFieldsOnly() .haveIds("ms1", "ms2"); // Make sure pinned shortcuts are passed too. // 1. Add dynamic shortcuts. - runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2")))); }); // 2. Pin some. - runWithCaller(LAUNCHER_1, UserHandle.USER_SYSTEM, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "s2"), HANDLE_USER_0); + runWithCaller(LAUNCHER_1, USER_10, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "s2"), HANDLE_USER_10); }); - runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2", "s1", "s2") .areAllEnabled() @@ -3736,10 +3737,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_0); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); assertForLauncherCallback(mLauncherApps, () -> { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.removeDynamicShortcuts(list("s2")); assertWith(getCallerShortcuts()) @@ -3764,16 +3765,16 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .areAllEnabled() ; }); - }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0) + }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_10) .haveIds("ms2", "s1", "s2") .areAllWithKeyFieldsOnly(); // Remove CALLING_PACKAGE_2 assertForLauncherCallback(mLauncherApps, () -> { - uninstallPackage(USER_0, CALLING_PACKAGE_2); - mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_0, USER_0, + uninstallPackage(USER_10, CALLING_PACKAGE_2); + mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_10, USER_10, /* appStillExists = */ false); - }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_2, HANDLE_USER_0) + }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_2, HANDLE_USER_10) .isEmpty(); } @@ -3798,35 +3799,35 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { setDefaultLauncherChecker((pkg, userId) -> { switch (userId) { - case USER_0: + case USER_10: return LAUNCHER_2.equals(pkg); case USER_P0: return LAUNCHER_1.equals(pkg); case USER_P1: return LAUNCHER_1.equals(pkg); - case USER_10: - return LAUNCHER_1.equals(pkg); case USER_11: return LAUNCHER_1.equals(pkg); + case USER_12: + return LAUNCHER_1.equals(pkg); default: return false; } }); - runWithCaller(LAUNCHER_1, USER_0, () -> mLauncherApps.registerCallback(c0_1, h)); - runWithCaller(LAUNCHER_2, USER_0, () -> mLauncherApps.registerCallback(c0_2, h)); - runWithCaller(LAUNCHER_3, USER_0, () -> mLauncherApps.registerCallback(c0_3, h)); - runWithCaller(LAUNCHER_4, USER_0, () -> mLauncherApps.registerCallback(c0_4, h)); + runWithCaller(LAUNCHER_1, USER_10, () -> mLauncherApps.registerCallback(c0_1, h)); + runWithCaller(LAUNCHER_2, USER_10, () -> mLauncherApps.registerCallback(c0_2, h)); + runWithCaller(LAUNCHER_3, USER_10, () -> mLauncherApps.registerCallback(c0_3, h)); + runWithCaller(LAUNCHER_4, USER_10, () -> mLauncherApps.registerCallback(c0_4, h)); runWithCaller(LAUNCHER_1, USER_P0, () -> mLauncherApps.registerCallback(cP0_1, h)); runWithCaller(LAUNCHER_1, USER_P1, () -> mLauncherApps.registerCallback(cP1_1, h)); - runWithCaller(LAUNCHER_1, USER_10, () -> mLauncherApps.registerCallback(c10_1, h)); - runWithCaller(LAUNCHER_2, USER_10, () -> mLauncherApps.registerCallback(c10_2, h)); - runWithCaller(LAUNCHER_1, USER_11, () -> mLauncherApps.registerCallback(c11_1, h)); + runWithCaller(LAUNCHER_1, USER_11, () -> mLauncherApps.registerCallback(c10_1, h)); + runWithCaller(LAUNCHER_2, USER_11, () -> mLauncherApps.registerCallback(c10_2, h)); + runWithCaller(LAUNCHER_1, USER_12, () -> mLauncherApps.registerCallback(c11_1, h)); // User 0. resetAll(all); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.removeDynamicShortcuts(list()); }); waitOnMainThread(); @@ -3837,14 +3838,14 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertCallbackNotReceived(c10_1); assertCallbackNotReceived(c10_2); assertCallbackNotReceived(c11_1); - assertCallbackReceived(c0_2, HANDLE_USER_0, CALLING_PACKAGE_1, "s1", "s2", "s3"); - assertCallbackReceived(cP0_1, HANDLE_USER_0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s4"); + assertCallbackReceived(c0_2, HANDLE_USER_10, CALLING_PACKAGE_1, "s1", "s2", "s3"); + assertCallbackReceived(cP0_1, HANDLE_USER_10, CALLING_PACKAGE_1, "s1", "s2", "s3", "s4"); assertCallbackNotReceived(cP1_1); // User 0, different package. resetAll(all); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { mManager.removeDynamicShortcuts(list()); }); waitOnMainThread(); @@ -3855,8 +3856,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertCallbackNotReceived(c10_1); assertCallbackNotReceived(c10_2); assertCallbackNotReceived(c11_1); - assertCallbackReceived(c0_2, HANDLE_USER_0, CALLING_PACKAGE_3, "s1", "s2", "s3", "s4"); - assertCallbackReceived(cP0_1, HANDLE_USER_0, CALLING_PACKAGE_3, + assertCallbackReceived(c0_2, HANDLE_USER_10, CALLING_PACKAGE_3, "s1", "s2", "s3", "s4"); + assertCallbackReceived(cP0_1, HANDLE_USER_10, CALLING_PACKAGE_3, "s1", "s2", "s3", "s4", "s5", "s6"); assertCallbackNotReceived(cP1_1); @@ -3878,10 +3879,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertCallbackNotReceived(cP1_1); // Normal secondary user. - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); resetAll(all); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { mManager.removeDynamicShortcuts(list()); }); waitOnMainThread(); @@ -3893,7 +3894,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertCallbackNotReceived(cP0_1); assertCallbackNotReceived(c10_2); assertCallbackNotReceived(c11_1); - assertCallbackReceived(c10_1, HANDLE_USER_10, CALLING_PACKAGE_1, + assertCallbackReceived(c10_1, HANDLE_USER_11, CALLING_PACKAGE_1, "x1", "x2", "x3", "x4", "x5"); assertCallbackNotReceived(cP1_1); } @@ -3905,7 +3906,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { Log.i(TAG, "Saved state"); dumpsysOnLogcat(); - dumpUserFile(0); + dumpUserFile(USER_10); // Restore. mService.saveDirtyInfo(); @@ -3919,7 +3920,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { */ public void SaveAndLoadUser() { // First, create some shortcuts and save. - runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.black_64x16); final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.icon2)); @@ -3946,7 +3947,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime()); assertEquals(2, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.black_16x64); final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.icon2)); @@ -3974,9 +3975,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(2, mManager.getRemainingCallCount()); }); - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.black_64x64); final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.icon2)); @@ -4012,12 +4013,12 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(0, mService.getShortcutsForTest().size()); // this will pre-load the per-user info. - mService.handleUnlockUser(UserHandle.USER_SYSTEM); + mService.handleUnlockUser(USER_10); // Now it's loaded. assertEquals(1, mService.getShortcutsForTest().size()); - runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllDynamic(assertAllHaveIntents(assertAllHaveIcon( mManager.getDynamicShortcuts()))), "s1", "s2"); assertEquals(2, mManager.getRemainingCallCount()); @@ -4025,7 +4026,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals("title1-1", getCallerShortcut("s1").getTitle()); assertEquals("title1-2", getCallerShortcut("s2").getTitle()); }); - runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertShortcutIds(assertAllDynamic(assertAllHaveIntents(assertAllHaveIcon( mManager.getDynamicShortcuts()))), "s1", "s2"); assertEquals(2, mManager.getRemainingCallCount()); @@ -4035,12 +4036,12 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Start another user - mService.handleUnlockUser(USER_10); + mService.handleUnlockUser(USER_11); // Now the size is 2. assertEquals(2, mService.getShortcutsForTest().size()); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertShortcutIds(assertAllDynamic(assertAllHaveIntents(assertAllHaveIcon( mManager.getDynamicShortcuts()))), "s1", "s2"); assertEquals(2, mManager.getRemainingCallCount()); @@ -4050,7 +4051,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Try stopping the user - mService.handleStopUser(USER_10); + mService.handleStopUser(USER_11); // Now it's unloaded. assertEquals(1, mService.getShortcutsForTest().size()); @@ -4074,7 +4075,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { public void SaveCorruptAndLoadUser() throws Exception { // First, create some shortcuts and save. - runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.black_64x16); final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.icon2)); @@ -4101,7 +4102,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime()); assertEquals(2, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.black_16x64); final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.icon2)); @@ -4129,9 +4130,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(2, mManager.getRemainingCallCount()); }); - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.black_64x64); final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.icon2)); @@ -4162,14 +4163,14 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Save and corrupt the primary files. mService.saveDirtyInfo(); try (Writer os = new FileWriter( - mService.getUserFile(UserHandle.USER_SYSTEM).getBaseFile())) { + mService.getUserFile(USER_10).getBaseFile())) { os.write("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" + "<user locales=\"en\" last-app-scan-time2=\"14400000"); } - try (Writer os = new FileWriter(mService.getUserFile(USER_10).getBaseFile())) { + try (Writer os = new FileWriter(mService.getUserFile(USER_11).getBaseFile())) { os.write("<?xml version='1.0' encoding='utf"); } - ShortcutPackage sp = mService.getUserShortcutsLocked(USER_0).getPackageShortcutsIfExists( + ShortcutPackage sp = mService.getUserShortcutsLocked(USER_10).getPackageShortcutsIfExists( CALLING_PACKAGE_1); try (Writer os = new FileWriter(sp.getShortcutPackageItemFile().getPath())) { os.write("<?xml version='1.0' encoding='utf"); @@ -4182,12 +4183,12 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(0, mService.getShortcutsForTest().size()); // this will pre-load the per-user info. - mService.handleUnlockUser(UserHandle.USER_SYSTEM); + mService.handleUnlockUser(USER_10); // Now it's loaded. assertEquals(1, mService.getShortcutsForTest().size()); - runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllDynamic(assertAllHaveIntents(assertAllHaveIcon( mManager.getDynamicShortcuts()))), "s1", "s2"); assertEquals(2, mManager.getRemainingCallCount()); @@ -4195,7 +4196,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals("title1-1", getCallerShortcut("s1").getTitle()); assertEquals("title1-2", getCallerShortcut("s2").getTitle()); }); - runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertShortcutIds(assertAllDynamic(assertAllHaveIntents(assertAllHaveIcon( mManager.getDynamicShortcuts()))), "s1", "s2"); assertEquals(2, mManager.getRemainingCallCount()); @@ -4205,12 +4206,12 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Start another user - mService.handleUnlockUser(USER_10); + mService.handleUnlockUser(USER_11); // Now the size is 2. assertEquals(2, mService.getShortcutsForTest().size()); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertShortcutIds(assertAllDynamic(assertAllHaveIntents(assertAllHaveIcon( mManager.getDynamicShortcuts()))), "s1", "s2"); assertEquals(2, mManager.getRemainingCallCount()); @@ -4220,7 +4221,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Try stopping the user - mService.handleStopUser(USER_10); + mService.handleStopUser(USER_11); // Now it's unloaded. assertEquals(1, mService.getShortcutsForTest().size()); @@ -4229,72 +4230,72 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } public void CleanupPackage() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s0_1")))); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s0_2")))); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s0_1"), - HANDLE_USER_0); + HANDLE_USER_10); mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s0_2"), - HANDLE_USER_0); + HANDLE_USER_10); }); - runWithCaller(LAUNCHER_2, USER_0, () -> { + runWithCaller(LAUNCHER_2, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s0_1"), - HANDLE_USER_0); + HANDLE_USER_10); mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s0_2"), - HANDLE_USER_0); + HANDLE_USER_10); }); - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s10_1")))); }); - runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_11, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s10_2")))); }); - runWithCaller(LAUNCHER_1, USER_10, () -> { + runWithCaller(LAUNCHER_1, USER_11, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s10_1"), - HANDLE_USER_10); + HANDLE_USER_11); mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s10_2"), - HANDLE_USER_10); + HANDLE_USER_11); }); - runWithCaller(LAUNCHER_2, USER_10, () -> { + runWithCaller(LAUNCHER_2, USER_11, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s10_1"), - HANDLE_USER_10); + HANDLE_USER_11); mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s10_2"), - HANDLE_USER_10); + HANDLE_USER_11); }); // Remove all dynamic shortcuts; now all shortcuts are just pinned. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.removeAllDynamicShortcuts(); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { mManager.removeAllDynamicShortcuts(); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { mManager.removeAllDynamicShortcuts(); }); - runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_11, () -> { mManager.removeAllDynamicShortcuts(); }); final SparseArray<ShortcutUser> users = mService.getShortcutsForTest(); assertEquals(2, users.size()); - assertEquals(USER_0, users.keyAt(0)); - assertEquals(USER_10, users.keyAt(1)); + assertEquals(USER_10, users.keyAt(0)); + assertEquals(USER_11, users.keyAt(1)); - final ShortcutUser user0 = users.get(USER_0); - final ShortcutUser user10 = users.get(USER_10); + final ShortcutUser user0 = users.get(USER_10); + final ShortcutUser user10 = users.get(USER_11); // Check the registered packages. @@ -4304,31 +4305,31 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2), hashSet(user10.getAllPackagesForTest().keySet())); assertEquals( - set(UserPackage.of(USER_0, LAUNCHER_1), - UserPackage.of(USER_0, LAUNCHER_2)), - hashSet(user0.getAllLaunchersForTest().keySet())); - assertEquals( set(UserPackage.of(USER_10, LAUNCHER_1), UserPackage.of(USER_10, LAUNCHER_2)), + hashSet(user0.getAllLaunchersForTest().keySet())); + assertEquals( + set(UserPackage.of(USER_11, LAUNCHER_1), + UserPackage.of(USER_11, LAUNCHER_2)), hashSet(user10.getAllLaunchersForTest().keySet())); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0), + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10), "s0_1", "s0_2"); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0), + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10), "s0_1", "s0_2"); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10), + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_11), "s10_1", "s10_2"); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10), + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_11), "s10_1", "s10_2"); - assertShortcutExists(CALLING_PACKAGE_1, "s0_1", USER_0); - assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0); - assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10); - assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10); + assertShortcutExists(CALLING_PACKAGE_1, "s0_1", USER_10); + assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_10); + assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_11); + assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_11); mService.saveDirtyInfo(); // Nonexistent package. - uninstallPackage(USER_0, "abc"); - mService.cleanUpPackageLocked("abc", USER_0, USER_0, /* appStillExists = */ false); + uninstallPackage(USER_10, "abc"); + mService.cleanUpPackageLocked("abc", USER_10, USER_10, /* appStillExists = */ false); // No changes. assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2), @@ -4336,31 +4337,31 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2), hashSet(user10.getAllPackagesForTest().keySet())); assertEquals( - set(UserPackage.of(USER_0, LAUNCHER_1), - UserPackage.of(USER_0, LAUNCHER_2)), - hashSet(user0.getAllLaunchersForTest().keySet())); - assertEquals( set(UserPackage.of(USER_10, LAUNCHER_1), UserPackage.of(USER_10, LAUNCHER_2)), + hashSet(user0.getAllLaunchersForTest().keySet())); + assertEquals( + set(UserPackage.of(USER_11, LAUNCHER_1), + UserPackage.of(USER_11, LAUNCHER_2)), hashSet(user10.getAllLaunchersForTest().keySet())); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0), + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10), "s0_1", "s0_2"); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0), + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10), "s0_1", "s0_2"); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10), + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_11), "s10_1", "s10_2"); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10), + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_11), "s10_1", "s10_2"); - assertShortcutExists(CALLING_PACKAGE_1, "s0_1", USER_0); - assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0); - assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10); - assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10); + assertShortcutExists(CALLING_PACKAGE_1, "s0_1", USER_10); + assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_10); + assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_11); + assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_11); mService.saveDirtyInfo(); // Remove a package. - uninstallPackage(USER_0, CALLING_PACKAGE_1); - mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_0, USER_0, + uninstallPackage(USER_10, CALLING_PACKAGE_1); + mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_10, USER_10, /* appStillExists = */ false); assertEquals(set(CALLING_PACKAGE_2), @@ -4368,59 +4369,59 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2), hashSet(user10.getAllPackagesForTest().keySet())); assertEquals( - set(UserPackage.of(USER_0, LAUNCHER_1), - UserPackage.of(USER_0, LAUNCHER_2)), - hashSet(user0.getAllLaunchersForTest().keySet())); - assertEquals( set(UserPackage.of(USER_10, LAUNCHER_1), UserPackage.of(USER_10, LAUNCHER_2)), + hashSet(user0.getAllLaunchersForTest().keySet())); + assertEquals( + set(UserPackage.of(USER_11, LAUNCHER_1), + UserPackage.of(USER_11, LAUNCHER_2)), hashSet(user10.getAllLaunchersForTest().keySet())); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0), + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10), "s0_2"); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0), + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10), "s0_2"); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10), + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_11), "s10_1", "s10_2"); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10), + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_11), "s10_1", "s10_2"); - assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0); - assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0); - assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10); - assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10); + assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_10); + assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_10); + assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_11); + assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_11); mService.saveDirtyInfo(); // Remove a launcher. - uninstallPackage(USER_10, LAUNCHER_1); - mService.cleanUpPackageLocked(LAUNCHER_1, USER_10, USER_10, /* appStillExists = */ false); + uninstallPackage(USER_11, LAUNCHER_1); + mService.cleanUpPackageLocked(LAUNCHER_1, USER_11, USER_11, /* appStillExists = */ false); assertEquals(set(CALLING_PACKAGE_2), hashSet(user0.getAllPackagesForTest().keySet())); assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2), hashSet(user10.getAllPackagesForTest().keySet())); assertEquals( - set(UserPackage.of(USER_0, LAUNCHER_1), - UserPackage.of(USER_0, LAUNCHER_2)), + set(UserPackage.of(USER_10, LAUNCHER_1), + UserPackage.of(USER_10, LAUNCHER_2)), hashSet(user0.getAllLaunchersForTest().keySet())); assertEquals( - set(UserPackage.of(USER_10, LAUNCHER_2)), + set(UserPackage.of(USER_11, LAUNCHER_2)), hashSet(user10.getAllLaunchersForTest().keySet())); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0), - "s0_2"); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0), + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10), "s0_2"); assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10), + "s0_2"); + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_11), "s10_1", "s10_2"); - assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0); - assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0); - assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10); - assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10); + assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_10); + assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_10); + assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_11); + assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_11); mService.saveDirtyInfo(); // Remove a package. - uninstallPackage(USER_10, CALLING_PACKAGE_2); - mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_10, USER_10, + uninstallPackage(USER_11, CALLING_PACKAGE_2); + mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_11, USER_11, /* appStillExists = */ false); assertEquals(set(CALLING_PACKAGE_2), @@ -4428,28 +4429,28 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(set(CALLING_PACKAGE_1), hashSet(user10.getAllPackagesForTest().keySet())); assertEquals( - set(UserPackage.of(USER_0, LAUNCHER_1), - UserPackage.of(USER_0, LAUNCHER_2)), + set(UserPackage.of(USER_10, LAUNCHER_1), + UserPackage.of(USER_10, LAUNCHER_2)), hashSet(user0.getAllLaunchersForTest().keySet())); assertEquals( - set(UserPackage.of(USER_10, LAUNCHER_2)), + set(UserPackage.of(USER_11, LAUNCHER_2)), hashSet(user10.getAllLaunchersForTest().keySet())); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0), - "s0_2"); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0), + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10), "s0_2"); assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10), + "s0_2"); + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_11), "s10_1"); - assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0); - assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0); - assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10); - assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_10); + assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_10); + assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_10); + assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_11); + assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_11); mService.saveDirtyInfo(); // Remove the other launcher from user 10 too. - uninstallPackage(USER_10, LAUNCHER_2); - mService.cleanUpPackageLocked(LAUNCHER_2, USER_10, USER_10, + uninstallPackage(USER_11, LAUNCHER_2); + mService.cleanUpPackageLocked(LAUNCHER_2, USER_11, USER_11, /* appStillExists = */ false); assertEquals(set(CALLING_PACKAGE_2), @@ -4457,28 +4458,28 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(set(CALLING_PACKAGE_1), hashSet(user10.getAllPackagesForTest().keySet())); assertEquals( - set(UserPackage.of(USER_0, LAUNCHER_1), - UserPackage.of(USER_0, LAUNCHER_2)), + set(UserPackage.of(USER_10, LAUNCHER_1), + UserPackage.of(USER_10, LAUNCHER_2)), hashSet(user0.getAllLaunchersForTest().keySet())); assertEquals( set(), hashSet(user10.getAllLaunchersForTest().keySet())); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0), + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10), "s0_2"); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0), + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10), "s0_2"); // Note the pinned shortcuts on user-10 no longer referred, so they should both be removed. - assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0); - assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0); - assertShortcutNotExists(CALLING_PACKAGE_1, "s10_1", USER_10); - assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_10); + assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_10); + assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_10); + assertShortcutNotExists(CALLING_PACKAGE_1, "s10_1", USER_11); + assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_11); mService.saveDirtyInfo(); // More remove. - uninstallPackage(USER_10, CALLING_PACKAGE_1); - mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_10, USER_10, + uninstallPackage(USER_11, CALLING_PACKAGE_1); + mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_11, USER_11, /* appStillExists = */ false); assertEquals(set(CALLING_PACKAGE_2), @@ -4486,21 +4487,21 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(set(), hashSet(user10.getAllPackagesForTest().keySet())); assertEquals( - set(UserPackage.of(USER_0, LAUNCHER_1), - UserPackage.of(USER_0, LAUNCHER_2)), + set(UserPackage.of(USER_10, LAUNCHER_1), + UserPackage.of(USER_10, LAUNCHER_2)), hashSet(user0.getAllLaunchersForTest().keySet())); assertEquals(set(), hashSet(user10.getAllLaunchersForTest().keySet())); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0), + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10), "s0_2"); - assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0), + assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10), "s0_2"); // Note the pinned shortcuts on user-10 no longer referred, so they should both be removed. - assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0); - assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0); - assertShortcutNotExists(CALLING_PACKAGE_1, "s10_1", USER_10); - assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_10); + assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_10); + assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_10); + assertShortcutNotExists(CALLING_PACKAGE_1, "s10_1", USER_11); + assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_11); mService.saveDirtyInfo(); } @@ -4511,15 +4512,15 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, - list("s2", "s3", "ms1", "ms2"), HANDLE_USER_0); + list("s2", "s3", "ms1", "ms2"), HANDLE_USER_10); }); // Remove ms2 from manifest. @@ -4528,9 +4529,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2")))); @@ -4564,9 +4565,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Clean up + re-publish manifests. - mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_0, USER_0, + mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_10, USER_10, /* appStillExists = */ true); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1") .areAllManifest(); @@ -4575,7 +4576,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { public void HandleGonePackage_crossProfile() { // Create some shortcuts. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); @@ -4583,253 +4584,253 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0)); assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0)); assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_10)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_11)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_11)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_11)); // Pin some. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, - list("s1"), HANDLE_USER_0); + list("s1"), HANDLE_USER_10); mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), UserHandle.of(USER_P0)); mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, - list("s3"), HANDLE_USER_0); + list("s3"), HANDLE_USER_10); }); runWithCaller(LAUNCHER_1, USER_P0, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, - list("s2"), HANDLE_USER_0); + list("s2"), HANDLE_USER_10); mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), UserHandle.of(USER_P0)); mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, - list("s1"), HANDLE_USER_0); + list("s1"), HANDLE_USER_10); }); - runWithCaller(LAUNCHER_1, USER_10, () -> { + runWithCaller(LAUNCHER_1, USER_11, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, - list("s3"), HANDLE_USER_10); + list("s3"), HANDLE_USER_11); }); // Check the state. - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0)); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0)); assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0)); assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0)); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0)); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_10)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_10)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_11)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_11)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_11)); // Make sure all the information is persisted. mService.saveDirtyInfo(); initService(); - mService.handleUnlockUser(USER_0); - mService.handleUnlockUser(USER_P0); mService.handleUnlockUser(USER_10); + mService.handleUnlockUser(USER_P0); + mService.handleUnlockUser(USER_11); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0)); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0)); assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0)); assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0)); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0)); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_10)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_10)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_11)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_11)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_11)); // Start uninstalling. - uninstallPackage(USER_10, LAUNCHER_1); - mService.checkPackageChanges(USER_10); + uninstallPackage(USER_11, LAUNCHER_1); + mService.checkPackageChanges(USER_11); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0)); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0)); assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0)); assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0)); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0)); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_10)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_10)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_11)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_11)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_11)); // Uninstall. - uninstallPackage(USER_10, CALLING_PACKAGE_1); - mService.checkPackageChanges(USER_10); + uninstallPackage(USER_11, CALLING_PACKAGE_1); + mService.checkPackageChanges(USER_11); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0)); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0)); assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0)); assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0)); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0)); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_10)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_10)); - assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); - assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); - assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); + assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_11)); + assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_11)); + assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_11)); uninstallPackage(USER_P0, LAUNCHER_1); - mService.checkPackageChanges(USER_0); + mService.checkPackageChanges(USER_10); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0)); assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0)); assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0)); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_10)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_10)); - assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); - assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); - assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); + assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_11)); + assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_11)); + assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_11)); mService.checkPackageChanges(USER_P0); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0)); assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0)); assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0)); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_10)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_10)); - assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); - assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); - assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); + assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_11)); + assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_11)); + assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_11)); uninstallPackage(USER_P0, CALLING_PACKAGE_1); mService.saveDirtyInfo(); initService(); - mService.handleUnlockUser(USER_0); - mService.handleUnlockUser(USER_P0); mService.handleUnlockUser(USER_10); + mService.handleUnlockUser(USER_P0); + mService.handleUnlockUser(USER_11); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0)); assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0)); assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0)); - assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_10)); + assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_10)); - assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); - assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); - assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); + assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_11)); + assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_11)); + assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_11)); // Uninstall - uninstallPackage(USER_0, LAUNCHER_1); + uninstallPackage(USER_10, LAUNCHER_1); mService.saveDirtyInfo(); initService(); - mService.handleUnlockUser(USER_0); - mService.handleUnlockUser(USER_P0); mService.handleUnlockUser(USER_10); + mService.handleUnlockUser(USER_P0); + mService.handleUnlockUser(USER_11); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0)); assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0)); assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_10)); - assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); - assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); - assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); + assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_11)); + assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_11)); + assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_11)); - uninstallPackage(USER_0, CALLING_PACKAGE_2); + uninstallPackage(USER_10, CALLING_PACKAGE_2); mService.saveDirtyInfo(); initService(); - mService.handleUnlockUser(USER_0); - mService.handleUnlockUser(USER_P0); mService.handleUnlockUser(USER_10); + mService.handleUnlockUser(USER_P0); + mService.handleUnlockUser(USER_11); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0)); - assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); + assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0)); assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0)); assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0)); - assertNull(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0)); - assertNull(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0)); - assertNull(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0)); + assertNull(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_10)); + assertNull(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_10)); + assertNull(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_10)); - assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10)); - assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10)); - assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); + assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_11)); + assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_11)); + assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_11)); } protected void checkCanRestoreTo(int expected, ShortcutPackageInfo spi, @@ -4854,11 +4855,11 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP); final ShortcutPackageInfo spi1 = ShortcutPackageInfo.generateForInstalledPackageForTest( - mService, CALLING_PACKAGE_1, USER_0); + mService, CALLING_PACKAGE_1, USER_10); final ShortcutPackageInfo spi2 = ShortcutPackageInfo.generateForInstalledPackageForTest( - mService, CALLING_PACKAGE_2, USER_0); + mService, CALLING_PACKAGE_2, USER_10); final ShortcutPackageInfo spi3 = ShortcutPackageInfo.generateForInstalledPackageForTest( - mService, CALLING_PACKAGE_3, USER_0); + mService, CALLING_PACKAGE_3, USER_10); checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi1, false, 10, true, "sig1"); checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi1, false, 10, true, "x", "sig1"); @@ -4927,7 +4928,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { private void checkHandlePackageDeleteInner(BiConsumer<Integer, String> remover) { final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.black_32x32)); - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); assertTrue(mManager.addDynamicShortcuts(list( makeShortcutWithIcon("s1", bmp32x32), makeShortcutWithIcon("s2", bmp32x32) ))); @@ -4937,8 +4938,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("s1", "s2", "ms1") @@ -4946,187 +4947,187 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .haveIds("ms1"); }); - setCaller(CALLING_PACKAGE_2, USER_0); + setCaller(CALLING_PACKAGE_2, USER_10); assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); - setCaller(CALLING_PACKAGE_3, USER_0); + setCaller(CALLING_PACKAGE_3, USER_10); assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - setCaller(CALLING_PACKAGE_1, USER_10); + setCaller(CALLING_PACKAGE_1, USER_11); assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); - setCaller(CALLING_PACKAGE_2, USER_10); + setCaller(CALLING_PACKAGE_2, USER_11); assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); - setCaller(CALLING_PACKAGE_3, USER_10); + setCaller(CALLING_PACKAGE_3, USER_11); assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0)); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_11)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_11)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_11)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0)); assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_11)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_11)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_11)); - remover.accept(USER_0, CALLING_PACKAGE_1); + remover.accept(USER_10, CALLING_PACKAGE_1); - assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0)); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0)); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10)); + assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_11)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_11)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_11)); - assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_11)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_11)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_11)); - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - remover.accept(USER_10, CALLING_PACKAGE_2); + remover.accept(USER_11, CALLING_PACKAGE_2); - assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0)); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0)); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10)); - assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); + assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_11)); + assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_11)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_11)); - assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); - assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_11)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_11)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_11)); mInjectedPackages.remove(CALLING_PACKAGE_1); mInjectedPackages.remove(CALLING_PACKAGE_3); - mService.checkPackageChanges(USER_0); + mService.checkPackageChanges(USER_10); - assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0)); - assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0)); // --------------- - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10)); - assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10)); + assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); + assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10)); // --------------- + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_11)); + assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_11)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_11)); - assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0)); - assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); - assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_11)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_11)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_11)); - mService.checkPackageChanges(USER_10); + mService.checkPackageChanges(USER_11); - assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0)); - assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0)); assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10)); - assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10)); + assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_11)); + assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_11)); + assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_11)); - assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0)); - assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0)); assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); - assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_11)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_11)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_11)); } /** Almost ame as testHandlePackageDelete, except it doesn't uninstall packages. */ public void HandlePackageClearData() { final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.black_32x32)); - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); assertTrue(mManager.addDynamicShortcuts(list( makeShortcutWithIcon("s1", bmp32x32), makeShortcutWithIcon("s2", bmp32x32) ))); - setCaller(CALLING_PACKAGE_2, USER_0); + setCaller(CALLING_PACKAGE_2, USER_10); assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); - setCaller(CALLING_PACKAGE_3, USER_0); + setCaller(CALLING_PACKAGE_3, USER_10); assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - setCaller(CALLING_PACKAGE_1, USER_10); + setCaller(CALLING_PACKAGE_1, USER_11); assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); - setCaller(CALLING_PACKAGE_2, USER_10); + setCaller(CALLING_PACKAGE_2, USER_11); assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); - setCaller(CALLING_PACKAGE_3, USER_10); + setCaller(CALLING_PACKAGE_3, USER_11); assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0)); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_11)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_11)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_11)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0)); assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_11)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_11)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_11)); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageDataClear(CALLING_PACKAGE_1, USER_0)); + genPackageDataClear(CALLING_PACKAGE_1, USER_10)); - assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0)); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0)); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10)); + assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_11)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_11)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_11)); - assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_11)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_11)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_11)); - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageDataClear(CALLING_PACKAGE_2, USER_10)); + genPackageDataClear(CALLING_PACKAGE_2, USER_11)); - assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0)); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0)); - assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10)); - assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); + assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_11)); + assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_11)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_11)); - assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0)); - assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); - assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_11)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_11)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_11)); } public void HandlePackageClearData_manifestRepublished() { - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); // Add two manifests and two dynamics. addManifestShortcutResource( @@ -5134,17 +5135,17 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_11)); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.addDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2")))); }); - runWithCaller(LAUNCHER_1, USER_10, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "s2"), HANDLE_USER_10); + runWithCaller(LAUNCHER_1, USER_11, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "s2"), HANDLE_USER_11); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2", "s1", "s2") .areAllEnabled() @@ -5155,10 +5156,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Clear data mService.mPackageMonitor.onReceive(getTestContext(), - genPackageDataClear(CALLING_PACKAGE_1, USER_10)); + genPackageDataClear(CALLING_PACKAGE_1, USER_11)); // Only manifest shortcuts will remain, and are no longer pinned. - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2") .areAllEnabled() @@ -5173,31 +5174,31 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.black_32x32)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcutWithIcon("s2", res32x32), makeShortcutWithIcon("s3", res32x32), makeShortcutWithIcon("s4", bmp32x32)))); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcutWithIcon("s2", bmp32x32)))); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcutWithIcon("s1", res32x32)))); }); - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcutWithIcon("s1", res32x32), makeShortcutWithIcon("s2", res32x32)))); }); - runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_11, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcutWithIcon("s1", bmp32x32), makeShortcutWithIcon("s2", bmp32x32)))); @@ -5206,10 +5207,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { LauncherApps.Callback c0 = mock(LauncherApps.Callback.class); LauncherApps.Callback c10 = mock(LauncherApps.Callback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.registerCallback(c0, new Handler(Looper.getMainLooper())); }); - runWithCaller(LAUNCHER_1, USER_10, () -> { + runWithCaller(LAUNCHER_1, USER_11, () -> { mLauncherApps.registerCallback(c10, new Handler(Looper.getMainLooper())); }); @@ -5224,7 +5225,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Then send the broadcast, to only user-0. mService.mPackageMonitor.onReceive(getTestContext(), - genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0)); + genPackageUpdateIntent(CALLING_PACKAGE_1, USER_10)); waitOnMainThread(); @@ -5233,7 +5234,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { verify(c0).onShortcutsChanged( eq(CALLING_PACKAGE_1), shortcuts.capture(), - eq(HANDLE_USER_0)); + eq(HANDLE_USER_10)); // User-10 shouldn't yet get the notification. verify(c10, times(0)).onShortcutsChanged( @@ -5254,14 +5255,14 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // notification to the launcher. mInjectedCurrentTimeMillis = START_TIME + 200; - mRunningUsers.put(USER_10, true); - mUnlockedUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); + mUnlockedUsers.put(USER_11, true); reset(c0); reset(c10); setPackageLastUpdateTime(CALLING_PACKAGE_1, mInjectedCurrentTimeMillis); - mService.handleUnlockUser(USER_10); - mService.checkPackageChanges(USER_10); + mService.handleUnlockUser(USER_11); + mService.checkPackageChanges(USER_11); waitOnMainThread(); @@ -5274,7 +5275,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { verify(c10).onShortcutsChanged( eq(CALLING_PACKAGE_1), shortcuts.capture(), - eq(HANDLE_USER_10)); + eq(HANDLE_USER_11)); assertShortcutIds(shortcuts.getValue(), "s1", "s2"); assertEquals(START_TIME + 200, @@ -5292,7 +5293,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Then send the broadcast, to only user-0. mService.mPackageMonitor.onReceive(getTestContext(), - genPackageUpdateIntent(CALLING_PACKAGE_2, USER_0)); + genPackageUpdateIntent(CALLING_PACKAGE_2, USER_10)); waitOnMainThread(); @@ -5315,8 +5316,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Then send the broadcast, to only user-0. mService.mPackageMonitor.onReceive(getTestContext(), - genPackageUpdateIntent(CALLING_PACKAGE_3, USER_0)); - mService.checkPackageChanges(USER_10); + genPackageUpdateIntent(CALLING_PACKAGE_3, USER_10)); + mService.checkPackageChanges(USER_11); waitOnMainThread(); @@ -5324,7 +5325,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { verify(c0).onShortcutsChanged( eq(CALLING_PACKAGE_3), shortcuts.capture(), - eq(HANDLE_USER_0)); + eq(HANDLE_USER_10)); // User 10 doesn't have package 3, so no callback. verify(c10, times(0)).onShortcutsChanged( @@ -5345,7 +5346,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { final Icon icon2 = Icon.createWithResource(getTestContext(), /* res ID */ 1001); // Set up shortcuts. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { // Note resource strings are not officially supported (they're hidden), but // should work. @@ -5371,7 +5372,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Verify. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { final ShortcutInfo s1 = getCallerShortcut("s1"); final ShortcutInfo s2 = getCallerShortcut("s2"); @@ -5397,9 +5398,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Update the package. updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0)); + genPackageUpdateIntent(CALLING_PACKAGE_1, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { final ShortcutInfo s1 = getCallerShortcut("s1"); final ShortcutInfo s2 = getCallerShortcut("s2"); @@ -5422,20 +5423,20 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mSystemPackages.add(CALLING_PACKAGE_1); // Initial state: no shortcuts. - mService.checkPackageChanges(USER_0); + mService.checkPackageChanges(USER_10); assertEquals(mInjectedCurrentTimeMillis, - mService.getUserShortcutsLocked(USER_0).getLastAppScanTime()); + mService.getUserShortcutsLocked(USER_10).getLastAppScanTime()); assertEquals(mInjectedBuildFingerprint, - mService.getUserShortcutsLocked(USER_0).getLastAppScanOsFingerprint()); + mService.getUserShortcutsLocked(USER_10).getLastAppScanOsFingerprint()); // They have no shortcuts. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .isEmpty(); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertWith(getCallerShortcuts()) .isEmpty(); }); @@ -5451,13 +5452,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()), R.xml.shortcut_1); mInjectedCurrentTimeMillis += 1000; - mService.checkPackageChanges(USER_0); + mService.checkPackageChanges(USER_10); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .isEmpty(); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertWith(getCallerShortcuts()) .isEmpty(); }); @@ -5466,13 +5467,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Update the build finger print. All apps will be scanned now. mInjectedBuildFingerprint = "update1"; mInjectedCurrentTimeMillis += 1000; - mService.checkPackageChanges(USER_0); + mService.checkPackageChanges(USER_10); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1"); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1"); }); @@ -5486,14 +5487,14 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()), R.xml.shortcut_2); mInjectedCurrentTimeMillis += 1000; - mService.checkPackageChanges(USER_0); + mService.checkPackageChanges(USER_10); // Fingerprint hasn't changed, so there packages weren't scanned. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1"); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1"); }); @@ -5502,13 +5503,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // all apps anyway. mInjectedBuildFingerprint = "update2"; mInjectedCurrentTimeMillis += 1000; - mService.checkPackageChanges(USER_0); + mService.checkPackageChanges(USER_10); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2"); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2"); }); @@ -5516,9 +5517,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Make sure getLastAppScanTime / getLastAppScanOsFingerprint are persisted. initService(); assertEquals(mInjectedCurrentTimeMillis, - mService.getUserShortcutsLocked(USER_0).getLastAppScanTime()); + mService.getUserShortcutsLocked(USER_10).getLastAppScanTime()); assertEquals(mInjectedBuildFingerprint, - mService.getUserShortcutsLocked(USER_0).getLastAppScanOsFingerprint()); + mService.getUserShortcutsLocked(USER_10).getLastAppScanOsFingerprint()); } public void HandlePackageChanged() { @@ -5528,23 +5529,23 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { addManifestShortcutResource(ACTIVITY1, R.xml.shortcut_1); addManifestShortcutResource(ACTIVITY2, R.xml.shortcut_1_alt); - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_11)); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.addDynamicShortcuts(list( makeShortcutWithActivity("s1", ACTIVITY1), makeShortcutWithActivity("s2", ACTIVITY2) ))); }); - runWithCaller(LAUNCHER_1, USER_10, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1-alt", "s2"), HANDLE_USER_10); + runWithCaller(LAUNCHER_1, USER_11, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1-alt", "s2"), HANDLE_USER_11); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms1-alt", "s1", "s2") .areAllEnabled() @@ -5564,9 +5565,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // First, no changes. mService.mPackageMonitor.onReceive(getTestContext(), - genPackageChangedIntent(CALLING_PACKAGE_1, USER_10)); + genPackageChangedIntent(CALLING_PACKAGE_1, USER_11)); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms1-alt", "s1", "s2") .areAllEnabled() @@ -5587,9 +5588,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Disable activity 1 mEnabledActivityChecker = (activity, userId) -> !ACTIVITY1.equals(activity); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageChangedIntent(CALLING_PACKAGE_1, USER_10)); + genPackageChangedIntent(CALLING_PACKAGE_1, USER_11)); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1-alt", "s2") .areAllEnabled() @@ -5607,9 +5608,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Manifest shortcuts will be re-published, but dynamic ones are not. mEnabledActivityChecker = (activity, userId) -> true; mService.mPackageMonitor.onReceive(getTestContext(), - genPackageChangedIntent(CALLING_PACKAGE_1, USER_10)); + genPackageChangedIntent(CALLING_PACKAGE_1, USER_11)); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms1-alt", "s2") .areAllEnabled() @@ -5631,9 +5632,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Because "ms1-alt" and "s2" are both pinned, they will remain, but disabled. mEnabledActivityChecker = (activity, userId) -> !ACTIVITY2.equals(activity); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageChangedIntent(CALLING_PACKAGE_1, USER_10)); + genPackageChangedIntent(CALLING_PACKAGE_1, USER_11)); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms1-alt", "s2") @@ -5652,7 +5653,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } public void HandlePackageUpdate_activityNoLongerMain() throws Throwable { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcutWithActivity("s1a", new ComponentName(getCallingPackage(), "act1")), @@ -5671,12 +5672,12 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .haveIds("s1a", "s1b", "s2a", "s2b", "s3a", "s3b") .areAllDynamic(); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1b", "s2b", "s3b"), - HANDLE_USER_0); + HANDLE_USER_10); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("s1a", "s1b", "s2a", "s2b", "s3a", "s3b") .areAllDynamic() @@ -5690,17 +5691,17 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { return activity.getClassName().equals("act1"); }; - setCaller(LAUNCHER_1, USER_0); + setCaller(LAUNCHER_1, USER_10); assertForLauncherCallback(mLauncherApps, () -> { updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0)); - }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0) + genPackageUpdateIntent(CALLING_PACKAGE_1, USER_10)); + }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_10) // Make sure the launcher gets callbacks. .haveIds("s1a", "s1b", "s2b", "s3b") .areAllWithKeyFieldsOnly(); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { // s2a and s3a are gone, but s2b and s3b will remain because they're pinned, and // disabled. assertWith(getCallerShortcuts()) @@ -5800,24 +5801,24 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(0, userP0.getAllLaunchersForTest().size()); // Make sure only "allowBackup" apps are restored, and are shadow. - final ShortcutUser user0 = mService.getUserShortcutsLocked(USER_0); + final ShortcutUser user0 = mService.getUserShortcutsLocked(USER_10); assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_1)); assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_2)); assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_3)); assertExistsAndShadow(user0.getAllLaunchersForTest().get( - UserPackage.of(USER_0, LAUNCHER_1))); + UserPackage.of(USER_10, LAUNCHER_1))); assertExistsAndShadow(user0.getAllLaunchersForTest().get( - UserPackage.of(USER_0, LAUNCHER_2))); + UserPackage.of(USER_10, LAUNCHER_2))); - assertNull(user0.getAllLaunchersForTest().get(UserPackage.of(USER_0, LAUNCHER_3))); + assertNull(user0.getAllLaunchersForTest().get(UserPackage.of(USER_10, LAUNCHER_3))); assertNull(user0.getAllLaunchersForTest().get(UserPackage.of(USER_P0, LAUNCHER_1))); doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class), anyString()); - installPackage(USER_0, CALLING_PACKAGE_1); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + installPackage(USER_10, CALLING_PACKAGE_1); + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerVisibleShortcuts()) .selectDynamic() .isEmpty() @@ -5828,25 +5829,25 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .areAllEnabled(); }); - installPackage(USER_0, LAUNCHER_1); - runWithCaller(LAUNCHER_1, USER_0, () -> { - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + installPackage(USER_10, LAUNCHER_1); + runWithCaller(LAUNCHER_1, USER_10, () -> { + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10)) .areAllPinned() .haveIds("s1") .areAllEnabled(); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_10)) .isEmpty(); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_10)) .isEmpty(); assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0)) .isEmpty(); }); - installPackage(USER_0, CALLING_PACKAGE_2); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + installPackage(USER_10, CALLING_PACKAGE_2); + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertWith(getCallerVisibleShortcuts()) .selectDynamic() .isEmpty() @@ -5857,18 +5858,18 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .areAllEnabled(); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + runWithCaller(LAUNCHER_1, USER_10, () -> { + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10)) .areAllPinned() .haveIds("s1") .areAllEnabled(); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_10)) .areAllPinned() .haveIds("s1", "s2") .areAllEnabled(); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_10)) .isEmpty(); assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0)) @@ -5876,19 +5877,19 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // 3 shouldn't be backed up, so no pinned shortcuts. - installPackage(USER_0, CALLING_PACKAGE_3); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + installPackage(USER_10, CALLING_PACKAGE_3); + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertWith(getCallerVisibleShortcuts()) .isEmpty(); }); // Launcher on a different profile shouldn't be restored. runWithCaller(LAUNCHER_1, USER_P0, () -> { - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10)) .isEmpty(); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_10)) .isEmpty(); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_10)) .isEmpty(); }); @@ -5900,21 +5901,21 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Restore launcher 2 on user 0. - installPackage(USER_0, LAUNCHER_2); - runWithCaller(LAUNCHER_2, USER_0, () -> { - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + installPackage(USER_10, LAUNCHER_2); + runWithCaller(LAUNCHER_2, USER_10, () -> { + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10)) .areAllPinned() .haveIds("s2") .areAllEnabled(); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_10)) .areAllPinned() .haveIds("s2", "s3") .areAllEnabled(); if (firstRestore) { assertWith( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_10)) .haveIds("s2", "s3", "s4") .areAllDisabled() .areAllPinned() @@ -5923,7 +5924,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED); } else { assertWith( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_10)) .isEmpty(); } @@ -5934,28 +5935,28 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Restoration of launcher2 shouldn't affect other packages; so do the same checks and // make sure they still have the same result. - installPackage(USER_0, CALLING_PACKAGE_1); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + installPackage(USER_10, CALLING_PACKAGE_1); + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerVisibleShortcuts()) .areAllPinned() .haveIds("s1", "s2"); }); - installPackage(USER_0, LAUNCHER_1); - runWithCaller(LAUNCHER_1, USER_0, () -> { - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + installPackage(USER_10, LAUNCHER_1); + runWithCaller(LAUNCHER_1, USER_10, () -> { + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10)) .areAllPinned() .haveIds("s1") .areAllEnabled(); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_10)) .areAllPinned() .haveIds("s1", "s2") .areAllEnabled(); if (firstRestore) { assertWith( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_10)) .haveIds("s1", "s2", "s3") .areAllDisabled() .areAllPinned() @@ -5963,7 +5964,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .areAllWithDisabledReason(ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED); } else { assertWith( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_10)) .isEmpty(); } @@ -5971,8 +5972,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .isEmpty(); }); - installPackage(USER_0, CALLING_PACKAGE_2); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + installPackage(USER_10, CALLING_PACKAGE_2); + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertWith(getCallerVisibleShortcuts()) .areAllPinned() .haveIds("s1", "s2", "s3") @@ -6004,30 +6005,30 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class), eq(CALLING_PACKAGE_1)); - installPackage(USER_0, CALLING_PACKAGE_1); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + installPackage(USER_10, CALLING_PACKAGE_1); + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(0, mManager.getDynamicShortcuts().size()); assertEquals(0, mManager.getPinnedShortcuts().size()); }); - assertFalse(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, USER_0) + assertFalse(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, USER_10) .getPackageInfo().isShadow()); doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe( any(byte[].class), anyString()); - installPackage(USER_0, CALLING_PACKAGE_2); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + installPackage(USER_10, CALLING_PACKAGE_2); + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertEquals(0, mManager.getDynamicShortcuts().size()); assertShortcutIds(assertAllPinned( mManager.getPinnedShortcuts()), "s1", "s2", "s3"); }); - assertFalse(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, USER_0) + assertFalse(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, USER_10) .getPackageInfo().isShadow()); - installPackage(USER_0, LAUNCHER_1); - runWithCaller(LAUNCHER_1, USER_0, () -> { - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + installPackage(USER_10, LAUNCHER_1); + runWithCaller(LAUNCHER_1, USER_10, () -> { + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10)) .haveIds("s1") .areAllPinned() .areAllDisabled() @@ -6055,61 +6056,61 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { fail("Unhandled disabled reason: " + package1DisabledReason); } }); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_10)) .haveIds("s1", "s2") .areAllPinned() .areAllEnabled(); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_10)) .isEmpty(); }); - installPackage(USER_0, LAUNCHER_2); - runWithCaller(LAUNCHER_2, USER_0, () -> { - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + installPackage(USER_10, LAUNCHER_2); + runWithCaller(LAUNCHER_2, USER_10, () -> { + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10)) .haveIds("s2") .areAllPinned() .areAllDisabled() .areAllWithDisabledReason(package1DisabledReason); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_10)) .haveIds("s2", "s3") .areAllPinned() .areAllEnabled(); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_10)) .isEmpty(); }); - installPackage(USER_0, CALLING_PACKAGE_3); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + installPackage(USER_10, CALLING_PACKAGE_3); + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertEquals(0, mManager.getDynamicShortcuts().size()); assertEquals(0, mManager.getPinnedShortcuts().size()); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + runWithCaller(LAUNCHER_1, USER_10, () -> { + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10)) .haveIds("s1") .areAllPinned() .areAllDisabled() .areAllWithDisabledReason(package1DisabledReason); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_10)) .haveIds("s1", "s2") .areAllPinned() .areAllEnabled(); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_10)) .haveIds("s1", "s2", "s3") .areAllPinned() .areAllDisabled() .areAllWithDisabledReason(ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED); }); - runWithCaller(LAUNCHER_2, USER_0, () -> { - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + runWithCaller(LAUNCHER_2, USER_10, () -> { + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10)) .haveIds("s2") .areAllPinned() .areAllDisabled() .areAllWithDisabledReason(package1DisabledReason); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_10)) .haveIds("s2", "s3") .areAllPinned() .areAllEnabled(); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_10)) .haveIds("s2", "s3", "s4") .areAllPinned() .areAllDisabled() @@ -6147,8 +6148,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe( any(byte[].class), anyString()); - installPackage(USER_0, CALLING_PACKAGE_1); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + installPackage(USER_10, CALLING_PACKAGE_1); + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(0, mManager.getDynamicShortcuts().size()); // s1 was pinned by launcher 1, which is not restored, yet, so we still see "s1" here. @@ -6157,8 +6158,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { "s1", "s2"); }); - installPackage(USER_0, CALLING_PACKAGE_2); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + installPackage(USER_10, CALLING_PACKAGE_2); + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertEquals(0, mManager.getDynamicShortcuts().size()); assertShortcutIds(assertAllPinned( mManager.getPinnedShortcuts()), @@ -6170,22 +6171,22 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Now we try to restore launcher 1. Then we realize it's not restorable, so L1 has no pinned // shortcuts. - installPackage(USER_0, LAUNCHER_1); - runWithCaller(LAUNCHER_1, USER_0, () -> { + installPackage(USER_10, LAUNCHER_1); + runWithCaller(LAUNCHER_1, USER_10, () -> { assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10)) /* empty */); assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_10)) /* empty */); assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_10)) /* empty */); }); - assertFalse(mService.getLauncherShortcutForTest(LAUNCHER_1, USER_0) + assertFalse(mService.getLauncherShortcutForTest(LAUNCHER_1, USER_10) .getPackageInfo().isShadow()); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(0, mManager.getDynamicShortcuts().size()); // Now CALLING_PACKAGE_1 realizes "s1" is no longer pinned. @@ -6197,44 +6198,44 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe( any(byte[].class), anyString()); - installPackage(USER_0, LAUNCHER_2); - runWithCaller(LAUNCHER_2, USER_0, () -> { + installPackage(USER_10, LAUNCHER_2); + runWithCaller(LAUNCHER_2, USER_10, () -> { assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)), + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10)), "s2"); assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)), + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_10)), "s2", "s3"); assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_10)) /* empty */); }); - assertFalse(mService.getLauncherShortcutForTest(LAUNCHER_2, USER_0) + assertFalse(mService.getLauncherShortcutForTest(LAUNCHER_2, USER_10) .getPackageInfo().isShadow()); - installPackage(USER_0, CALLING_PACKAGE_3); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + installPackage(USER_10, CALLING_PACKAGE_3); + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertEquals(0, mManager.getDynamicShortcuts().size()); assertEquals(0, mManager.getPinnedShortcuts().size()); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10)) /* empty */); assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_10)) /* empty */); assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_10)) /* empty */); }); - runWithCaller(LAUNCHER_2, USER_0, () -> { + runWithCaller(LAUNCHER_2, USER_10, () -> { assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)), + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10)), "s2"); assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)), + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_10)), "s2", "s3"); }); } @@ -6254,80 +6255,80 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { protected void checkBackupAndRestore_publisherAndLauncherNotRestored() { doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class), anyString()); - installPackage(USER_0, CALLING_PACKAGE_1); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + installPackage(USER_10, CALLING_PACKAGE_1); + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(0, mManager.getDynamicShortcuts().size()); assertEquals(0, mManager.getPinnedShortcuts().size()); }); - installPackage(USER_0, CALLING_PACKAGE_2); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + installPackage(USER_10, CALLING_PACKAGE_2); + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertEquals(0, mManager.getDynamicShortcuts().size()); assertShortcutIds(assertAllPinned( mManager.getPinnedShortcuts()), "s1", "s2", "s3"); }); - installPackage(USER_0, LAUNCHER_1); - runWithCaller(LAUNCHER_1, USER_0, () -> { + installPackage(USER_10, LAUNCHER_1); + runWithCaller(LAUNCHER_1, USER_10, () -> { assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10)) /* empty */); assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_10)) /* empty */); assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_10)) /* empty */); }); - installPackage(USER_0, LAUNCHER_2); - runWithCaller(LAUNCHER_2, USER_0, () -> { - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + installPackage(USER_10, LAUNCHER_2); + runWithCaller(LAUNCHER_2, USER_10, () -> { + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10)) .areAllPinned() .haveIds("s2") .areAllDisabled(); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_10)) .areAllPinned() .haveIds("s2", "s3"); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_10)) .isEmpty(); }); // Because launcher 1 wasn't restored, "s1" is no longer pinned. - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertEquals(0, mManager.getDynamicShortcuts().size()); assertShortcutIds(assertAllPinned( mManager.getPinnedShortcuts()), "s2", "s3"); }); - installPackage(USER_0, CALLING_PACKAGE_3); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + installPackage(USER_10, CALLING_PACKAGE_3); + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertEquals(0, mManager.getDynamicShortcuts().size()); assertEquals(0, mManager.getPinnedShortcuts().size()); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10)) /* empty */); assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_10)) /* empty */); assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_10)) /* empty */); }); - runWithCaller(LAUNCHER_2, USER_0, () -> { - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + runWithCaller(LAUNCHER_2, USER_10, () -> { + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10)) .areAllPinned() .haveIds("s2") .areAllDisabled(); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_10)) .areAllPinned() .haveIds("s2", "s3"); assertWith( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_10)) .haveIds("s2", "s3", "s4") .areAllDisabled() .areAllPinned() @@ -6341,7 +6342,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { prepareCrossProfileDataSet(); // Before doing backup & restore, disable s1. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.disableShortcuts(list("s1")); }); @@ -6355,23 +6356,23 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(0, userP0.getAllLaunchersForTest().size()); // Make sure only "allowBackup" apps are restored, and are shadow. - final ShortcutUser user0 = mService.getUserShortcutsLocked(USER_0); + final ShortcutUser user0 = mService.getUserShortcutsLocked(USER_10); assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_1)); assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_2)); assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_3)); assertExistsAndShadow(user0.getAllLaunchersForTest().get( - UserPackage.of(USER_0, LAUNCHER_1))); + UserPackage.of(USER_10, LAUNCHER_1))); assertExistsAndShadow(user0.getAllLaunchersForTest().get( - UserPackage.of(USER_0, LAUNCHER_2))); + UserPackage.of(USER_10, LAUNCHER_2))); - assertNull(user0.getAllLaunchersForTest().get(UserPackage.of(USER_0, LAUNCHER_3))); + assertNull(user0.getAllLaunchersForTest().get(UserPackage.of(USER_10, LAUNCHER_3))); assertNull(user0.getAllLaunchersForTest().get(UserPackage.of(USER_P0, LAUNCHER_1))); doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class), anyString()); - installPackage(USER_0, CALLING_PACKAGE_1); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + installPackage(USER_10, CALLING_PACKAGE_1); + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerVisibleShortcuts()) .areAllEnabled() // disabled shortcuts shouldn't be restored. @@ -6384,16 +6385,16 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .haveIds("s2"); }); - installPackage(USER_0, LAUNCHER_1); - runWithCaller(LAUNCHER_1, USER_0, () -> { + installPackage(USER_10, LAUNCHER_1); + runWithCaller(LAUNCHER_1, USER_10, () -> { // Note, s1 was pinned by launcher 1, but was disabled, so isn't restored. - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10)) .isEmpty(); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_10)) .isEmpty(); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_10)) .isEmpty(); assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0)) @@ -6409,17 +6410,17 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(mServiceContext, - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); // Pin from launcher 1. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, - list("ms1", "ms2", "s1", "s2"), HANDLE_USER_0); + list("ms1", "ms2", "s1", "s2"), HANDLE_USER_10); }); // Update and now ms2 is gone -> disabled. @@ -6428,10 +6429,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(mServiceContext, - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); // Make sure the manifest shortcuts have been published. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .selectManifest() .haveIds("ms1") @@ -6461,11 +6462,11 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // When re-installing the app, the manifest shortcut should be re-published. mService.mPackageMonitor.onReceive(mServiceContext, - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); mService.mPackageMonitor.onReceive(mServiceContext, - genPackageAddIntent(LAUNCHER_1, USER_0)); + genPackageAddIntent(LAUNCHER_1, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerVisibleShortcuts()) .selectPinned() // ms2 was disabled, so not restored. @@ -6502,17 +6503,17 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(mServiceContext, - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); }); // Pin from launcher 1. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, - list("ms1", "ms2", "s1", "s2"), HANDLE_USER_0); + list("ms1", "ms2", "s1", "s2"), HANDLE_USER_10); }); // Update and now ms2 is gone -> disabled. @@ -6521,7 +6522,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(mServiceContext, - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); // Set up shortcuts for package 3, which won't be backed up / restored. addManifestShortcutResource( @@ -6529,15 +6530,15 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_3, 1); mService.mPackageMonitor.onReceive(mServiceContext, - genPackageAddIntent(CALLING_PACKAGE_3, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_3, USER_10)); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertTrue(getManager().setDynamicShortcuts(list( makeShortcut("s1")))); }); // Make sure the manifest shortcuts have been published. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .selectManifest() .haveIds("ms1") @@ -6561,7 +6562,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .areAllDisabled(); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("s1", "ms1"); }); @@ -6575,7 +6576,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { dumpsysOnLogcat("Before backup"); - final byte[] payload = mService.getBackupPayload(USER_0); + final byte[] payload = mService.getBackupPayload(USER_10); if (ENABLE_DUMP) { final String xml = new String(payload); Log.v(TAG, "Backup payload:"); @@ -6583,7 +6584,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { Log.v(TAG, line); } } - mService.applyRestore(payload, USER_0); + mService.applyRestore(payload, USER_10); dumpsysOnLogcat("After restore"); @@ -6591,7 +6592,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } // The check is also the same as testBackupAndRestore_manifestRePublished(). - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerVisibleShortcuts()) .selectPinned() // ms2 was disabled, so not restored. @@ -6609,7 +6610,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Package 3 still has the same shortcuts. - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("s1", "ms1"); }); @@ -6627,31 +6628,31 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe( any(byte[].class), anyString()); - runWithSystemUid(() -> mService.applyRestore(payload, USER_0)); + runWithSystemUid(() -> mService.applyRestore(payload, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .areAllPinned() .haveIds("s1") .areAllEnabled(); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { - assertWith(getShortcutAsLauncher(USER_0)) + runWithCaller(LAUNCHER_1, USER_10, () -> { + assertWith(getShortcutAsLauncher(USER_10)) .areAllPinned() .haveIds("s1") .areAllEnabled(); }); // Make sure getBackupSourceVersionCode and isBackupSourceBackupAllowed // are correct. We didn't have them in the old format. - assertEquals(8, mService.getPackageShortcutForTest(CALLING_PACKAGE_1, USER_0) + assertEquals(8, mService.getPackageShortcutForTest(CALLING_PACKAGE_1, USER_10) .getPackageInfo().getBackupSourceVersionCode()); - assertTrue(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, USER_0) + assertTrue(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, USER_10) .getPackageInfo().isBackupSourceBackupAllowed()); - assertEquals(9, mService.getLauncherShortcutForTest(LAUNCHER_1, USER_0) + assertEquals(9, mService.getLauncherShortcutForTest(LAUNCHER_1, USER_10) .getPackageInfo().getBackupSourceVersionCode()); - assertTrue(mService.getLauncherShortcutForTest(LAUNCHER_1, USER_0) + assertTrue(mService.getLauncherShortcutForTest(LAUNCHER_1, USER_10) .getPackageInfo().isBackupSourceBackupAllowed()); } @@ -6664,25 +6665,25 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mService.saveDirtyInfo(); initService(); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1", "s2", "s3"); assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3", "s4"); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1", "s2", "s3"); assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3", "s4", "s5"); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1", "s2", "s3"); assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3", "s4", "s5", "s6"); }); - runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_4, USER_10, () -> { assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()) /* empty */); assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()) @@ -6700,24 +6701,24 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()) /* empty */); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "x1", "x2", "x3"); assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "x4", "x5"); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0), + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_10), "s1"); assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0), + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_10), "s1", "s2"); assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0), + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_10), "s1", "s2", "s3"); assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0) + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_10) /* empty */); assertShortcutIds( mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0), @@ -6728,21 +6729,21 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertExpectException( SecurityException.class, "", () -> { mLauncherApps.getShortcuts( - buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10); + buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_11); }); }); - runWithCaller(LAUNCHER_2, USER_0, () -> { + runWithCaller(LAUNCHER_2, USER_10, () -> { assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0), + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_10), "s2"); assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0), + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_10), "s2", "s3"); assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0), + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_10), "s2", "s3", "s4"); assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0) + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_10) /* empty */); assertShortcutIds( mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0), @@ -6751,18 +6752,18 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0) /* empty */); }); - runWithCaller(LAUNCHER_3, USER_0, () -> { + runWithCaller(LAUNCHER_3, USER_10, () -> { assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0), + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_10), "s3"); assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0), + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_10), "s3", "s4"); assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0), + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_10), "s3", "s4", "s5"); assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0) + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_10) /* empty */); assertShortcutIds( mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0), @@ -6771,18 +6772,18 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0) /* empty */); }); - runWithCaller(LAUNCHER_4, USER_0, () -> { + runWithCaller(LAUNCHER_4, USER_10, () -> { assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0) + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_10) /* empty */); assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0) + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_10) /* empty */); assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0) + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_10) /* empty */); assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0) + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_10) /* empty */); assertShortcutIds( mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0) @@ -6793,13 +6794,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); runWithCaller(LAUNCHER_1, USER_P0, () -> { assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0), + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_10), "s3", "s4"); assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0), + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_10), "s3", "s4", "s5"); assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0), + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_10), "s3", "s4", "s5", "s6"); assertShortcutIds( mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0), @@ -6807,23 +6808,23 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertExpectException( SecurityException.class, "unrelated profile", () -> { mLauncherApps.getShortcuts( - buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10); + buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_11); }); }); - runWithCaller(LAUNCHER_1, USER_10, () -> { + runWithCaller(LAUNCHER_1, USER_11, () -> { assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_10), + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_11), "x4", "x5"); assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_10) + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_11) /* empty */); assertShortcutIds( - mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_10) + mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_11) /* empty */); assertExpectException( SecurityException.class, "unrelated profile", () -> { mLauncherApps.getShortcuts( - buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0); + buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10); }); assertExpectException( SecurityException.class, "unrelated profile", () -> { @@ -6832,11 +6833,11 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); }); // Check the user-IDs. - assertEquals(USER_0, - mService.getUserShortcutsLocked(USER_0).getPackageShortcuts(CALLING_PACKAGE_1) + assertEquals(USER_10, + mService.getUserShortcutsLocked(USER_10).getPackageShortcuts(CALLING_PACKAGE_1) .getOwnerUserId()); - assertEquals(USER_0, - mService.getUserShortcutsLocked(USER_0).getPackageShortcuts(CALLING_PACKAGE_1) + assertEquals(USER_10, + mService.getUserShortcutsLocked(USER_10).getPackageShortcuts(CALLING_PACKAGE_1) .getPackageUserId()); assertEquals(USER_P0, mService.getUserShortcutsLocked(USER_P0).getPackageShortcuts(CALLING_PACKAGE_1) @@ -6845,27 +6846,27 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mService.getUserShortcutsLocked(USER_P0).getPackageShortcuts(CALLING_PACKAGE_1) .getPackageUserId()); - assertEquals(USER_0, - mService.getUserShortcutsLocked(USER_0).getLauncherShortcuts(LAUNCHER_1, USER_0) + assertEquals(USER_10, + mService.getUserShortcutsLocked(USER_10).getLauncherShortcuts(LAUNCHER_1, USER_10) .getOwnerUserId()); - assertEquals(USER_0, - mService.getUserShortcutsLocked(USER_0).getLauncherShortcuts(LAUNCHER_1, USER_0) + assertEquals(USER_10, + mService.getUserShortcutsLocked(USER_10).getLauncherShortcuts(LAUNCHER_1, USER_10) .getPackageUserId()); assertEquals(USER_P0, - mService.getUserShortcutsLocked(USER_P0).getLauncherShortcuts(LAUNCHER_1, USER_0) + mService.getUserShortcutsLocked(USER_P0).getLauncherShortcuts(LAUNCHER_1, USER_10) .getOwnerUserId()); - assertEquals(USER_0, - mService.getUserShortcutsLocked(USER_P0).getLauncherShortcuts(LAUNCHER_1, USER_0) + assertEquals(USER_10, + mService.getUserShortcutsLocked(USER_P0).getLauncherShortcuts(LAUNCHER_1, USER_10) .getPackageUserId()); } public void OnApplicationActive_permission() { assertExpectException(SecurityException.class, "Missing permission", () -> - mManager.onApplicationActive(CALLING_PACKAGE_1, USER_0)); + mManager.onApplicationActive(CALLING_PACKAGE_1, USER_10)); // Has permission, now it should pass. mCallerPermissions.add(permission.RESET_SHORTCUT_MANAGER_THROTTLING); - mManager.onApplicationActive(CALLING_PACKAGE_1, USER_0); + mManager.onApplicationActive(CALLING_PACKAGE_1, USER_10); } public void GetShareTargets_permission() { @@ -6881,7 +6882,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mCallerPermissions.add(permission.MANAGE_APP_PREDICTIONS); mManager.getShareTargets(filter); - runWithCaller(CHOOSER_ACTIVITY_PACKAGE, USER_0, () -> { + runWithCaller(CHOOSER_ACTIVITY_PACKAGE, USER_10, () -> { // Access is allowed when called from the configured system ChooserActivity mManager.getShareTargets(filter); }); @@ -6897,13 +6898,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } public void isSharingShortcut_permission() throws IntentFilter.MalformedMimeTypeException { - setCaller(LAUNCHER_1, USER_0); + setCaller(LAUNCHER_1, USER_10); IntentFilter filter_any = new IntentFilter(); filter_any.addDataType("*/*"); assertExpectException(SecurityException.class, "Missing permission", () -> - mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s1", USER_0, + mInternal.isSharingShortcut(USER_10, LAUNCHER_1, CALLING_PACKAGE_1, "s1", USER_10, filter_any)); // Has permission, now it should pass. @@ -6935,23 +6936,23 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Unlock user-0. mInjectedCurrentTimeMillis += 100; - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1"); assertEmpty(mManager.getPinnedShortcuts()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1", "ms2"); assertEmpty(mManager.getPinnedShortcuts()); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1", "ms2", "ms3", "ms4", "ms5"); @@ -6959,27 +6960,27 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Try on another user, with some packages uninstalled. - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - uninstallPackage(USER_10, CALLING_PACKAGE_1); - uninstallPackage(USER_10, CALLING_PACKAGE_3); + uninstallPackage(USER_11, CALLING_PACKAGE_1); + uninstallPackage(USER_11, CALLING_PACKAGE_3); mInjectedCurrentTimeMillis += 100; - mService.handleUnlockUser(USER_10); + mService.handleUnlockUser(USER_11); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertEmpty(mManager.getManifestShortcuts()); assertEmpty(mManager.getPinnedShortcuts()); }); - runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_11, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1", "ms2"); assertEmpty(mManager.getPinnedShortcuts()); }); - runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_11, () -> { assertEmpty(mManager.getManifestShortcuts()); assertEmpty(mManager.getPinnedShortcuts()); }); @@ -6999,23 +7000,23 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_1); initService(); - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( // FAIL mManager.getManifestShortcuts()))), "ms1"); assertEmpty(mManager.getPinnedShortcuts()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1", "ms2"); assertEmpty(mManager.getPinnedShortcuts()); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1", "ms2", "ms3", "ms4", "ms5"); @@ -7031,23 +7032,23 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { updatePackageLastUpdateTime(CALLING_PACKAGE_3, 1); initService(); - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1", "ms2", "ms3", "ms4", "ms5"); assertEmpty(mManager.getPinnedShortcuts()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1", "ms2"); assertEmpty(mManager.getPinnedShortcuts()); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1"); @@ -7055,12 +7056,12 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Next, try removing all shortcuts, with some of them pinned. - runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms3"), HANDLE_USER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("ms2"), HANDLE_USER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("ms1"), HANDLE_USER_0); + runWithCaller(LAUNCHER_1, USER_10, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms3"), HANDLE_USER_10); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("ms2"), HANDLE_USER_10); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("ms1"), HANDLE_USER_10); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1", "ms2", "ms3", "ms4", "ms5"); @@ -7069,7 +7070,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { "ms3"); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1", "ms2"); @@ -7078,7 +7079,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { "ms2"); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1"); @@ -7106,16 +7107,16 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { updatePackageVersion(CALLING_PACKAGE_3, 1); initService(); - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEmpty(mManager.getManifestShortcuts()); assertShortcutIds(assertAllImmutable(assertAllPinned(assertAllNotManifest( assertAllDisabled(mManager.getPinnedShortcuts())))), "ms3"); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1"); @@ -7124,7 +7125,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { "ms2"); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertEmpty(mManager.getManifestShortcuts()); assertShortcutIds(assertAllImmutable(assertAllPinned(assertAllNotManifest( assertAllDisabled(mManager.getPinnedShortcuts())))), @@ -7132,38 +7133,38 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Make sure we don't have ShortcutPackage for packages that don't have shortcuts. - assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_4, USER_0)); - assertNull(mService.getPackageShortcutForTest(LAUNCHER_1, USER_0)); + assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_4, USER_10)); + assertNull(mService.getPackageShortcutForTest(LAUNCHER_1, USER_10)); } public void ManifestShortcut_publishOnBroadcast() { // First, no packages are installed. - uninstallPackage(USER_0, CALLING_PACKAGE_1); - uninstallPackage(USER_0, CALLING_PACKAGE_2); - uninstallPackage(USER_0, CALLING_PACKAGE_3); - uninstallPackage(USER_0, CALLING_PACKAGE_4); uninstallPackage(USER_10, CALLING_PACKAGE_1); uninstallPackage(USER_10, CALLING_PACKAGE_2); uninstallPackage(USER_10, CALLING_PACKAGE_3); uninstallPackage(USER_10, CALLING_PACKAGE_4); + uninstallPackage(USER_11, CALLING_PACKAGE_1); + uninstallPackage(USER_11, CALLING_PACKAGE_2); + uninstallPackage(USER_11, CALLING_PACKAGE_3); + uninstallPackage(USER_11, CALLING_PACKAGE_4); - mService.handleUnlockUser(USER_0); - - mRunningUsers.put(USER_10, true); mService.handleUnlockUser(USER_10); + mRunningUsers.put(USER_11, true); + mService.handleUnlockUser(USER_11); + // Originally no manifest shortcuts. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEmpty(mManager.getManifestShortcuts()); assertEmpty(mManager.getPinnedShortcuts()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertEmpty(mManager.getManifestShortcuts()); assertEmpty(mManager.getPinnedShortcuts()); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertEmpty(mManager.getManifestShortcuts()); assertEmpty(mManager.getPinnedShortcuts()); }); @@ -7174,16 +7175,16 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1"); assertEmpty(mManager.getPinnedShortcuts()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertEmpty(mManager.getManifestShortcuts()); assertEmpty(mManager.getPinnedShortcuts()); }); @@ -7195,16 +7196,16 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_5_altalt); updatePackageVersion(CALLING_PACKAGE_2, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_2, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_2, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1"); assertEmpty(mManager.getPinnedShortcuts()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1", "ms2", "ms3", "ms4", "ms5"); @@ -7221,8 +7222,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { dumpsysOnLogcat("Before pinning"); // Also pin some. - runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("ms2", "ms3"), HANDLE_USER_0); + runWithCaller(LAUNCHER_1, USER_10, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("ms2", "ms3"), HANDLE_USER_10); }); dumpsysOnLogcat("After pinning"); @@ -7232,18 +7233,18 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_2); updatePackageLastUpdateTime(CALLING_PACKAGE_2, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_2, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_2, USER_10)); dumpsysOnLogcat("After updating package 2"); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1"); assertEmpty(mManager.getPinnedShortcuts()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1", "ms2"); @@ -7267,10 +7268,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Make sure the launcher see the correct disabled reason. - runWithCaller(LAUNCHER_1, USER_0, () -> { - assertWith(getShortcutAsLauncher(USER_0)) + runWithCaller(LAUNCHER_1, USER_10, () -> { + assertWith(getShortcutAsLauncher(USER_10)) .forShortcutWithId("ms3", si -> { - assertEquals("string-com.android.test.2-user:0-res:" + assertEquals("string-com.android.test.2-user:10-res:" + R.string.shortcut_disabled_message3 + "/en", si.getDisabledMessage()); }); @@ -7278,18 +7279,18 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Package 2 on user 10 has no shortcuts yet. - runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_11, () -> { assertEmpty(mManager.getManifestShortcuts()); assertEmpty(mManager.getPinnedShortcuts()); }); // Send add broadcast, but the user is not running, so should be ignored. - mService.handleStopUser(USER_10); - mRunningUsers.put(USER_10, false); - mUnlockedUsers.put(USER_10, false); + mService.handleStopUser(USER_11); + mRunningUsers.put(USER_11, false); + mUnlockedUsers.put(USER_11, false); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_2, USER_10)); - runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { + genPackageAddIntent(CALLING_PACKAGE_2, USER_11)); + runWithCaller(CALLING_PACKAGE_2, USER_11, () -> { // Don't use the mManager APIs to get shortcuts, because they'll trigger the package // update check. // So look the internal data directly using getCallerShortcuts(). @@ -7297,10 +7298,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Try again, but the user is locked, so still ignored. - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_2, USER_10)); - runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { + genPackageAddIntent(CALLING_PACKAGE_2, USER_11)); + runWithCaller(CALLING_PACKAGE_2, USER_11, () -> { // Don't use the mManager APIs to get shortcuts, because they'll trigger the package // update check. // So look the internal data directly using getCallerShortcuts(). @@ -7308,13 +7309,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Unlock the user, now it should work. - mUnlockedUsers.put(USER_10, true); + mUnlockedUsers.put(USER_11, true); // Send PACKAGE_ADD broadcast to have Package 2 on user-10 publish manifest shortcuts. mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_2, USER_10)); + genPackageAddIntent(CALLING_PACKAGE_2, USER_11)); - runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_11, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1", "ms2"); @@ -7326,7 +7327,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // But it shouldn't affect user-0. - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1", "ms2"); @@ -7353,9 +7354,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { updatePackageLastUpdateTime(CALLING_PACKAGE_2, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_2, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_2, USER_10)); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1", "ms2", "ms3", "ms4", "ms5", @@ -7381,10 +7382,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_0); updatePackageLastUpdateTime(CALLING_PACKAGE_2, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_2, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_2, USER_10)); // No manifest shortcuts, and pinned ones are disabled. - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertEmpty(mManager.getManifestShortcuts()); assertShortcutIds(assertAllImmutable(assertAllPinned(assertAllDisabled( mManager.getPinnedShortcuts()))), @@ -7394,15 +7395,15 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { public void ManifestShortcuts_missingMandatoryFields() { // Start with no apps installed. - uninstallPackage(USER_0, CALLING_PACKAGE_1); - uninstallPackage(USER_0, CALLING_PACKAGE_2); - uninstallPackage(USER_0, CALLING_PACKAGE_3); - uninstallPackage(USER_0, CALLING_PACKAGE_4); + uninstallPackage(USER_10, CALLING_PACKAGE_1); + uninstallPackage(USER_10, CALLING_PACKAGE_2); + uninstallPackage(USER_10, CALLING_PACKAGE_3); + uninstallPackage(USER_10, CALLING_PACKAGE_4); - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); // Make sure no manifest shortcuts. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEmpty(mManager.getManifestShortcuts()); }); @@ -7412,10 +7413,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_error_1); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); // Only the valid one is published. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .areAllManifest() .areAllImmutable() @@ -7429,10 +7430,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_error_2); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); // Only the valid one is published. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .areAllManifest() .areAllImmutable() @@ -7446,10 +7447,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_error_3); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); // Only the valid one is published. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .areAllManifest() .areAllImmutable() @@ -7467,9 +7468,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_error_4); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { // Make sure invalid ones are not published. // Note that at this point disabled ones don't show up because they weren't pinned. assertWith(getCallerShortcuts()) @@ -7525,9 +7526,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_5); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { // Make sure 5 manifest shortcuts are published. assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2", "ms3", "ms4", "ms5") @@ -7538,13 +7539,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .areAllEnabled(); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, - list("ms3", "ms4", "ms5"), HANDLE_USER_0); + list("ms3", "ms4", "ms5"), HANDLE_USER_10); }); // Make sure they're pinned. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2", "ms3", "ms4", "ms5") .selectByIds("ms1", "ms2") @@ -7563,10 +7564,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_error_4); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); // Make sure 3, 4 and 5 still exist but disabled. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2", "ms3", "ms4", "ms5") .areAllNotDynamic() @@ -7604,7 +7605,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } public void ManifestShortcuts_checkAllFields() { - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); // Package 1 updated, which has one valid manifest shortcut and one invalid. addManifestShortcutResource( @@ -7612,10 +7613,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_5); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); // Only the valid one is published. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2", "ms3", "ms4", "ms5") .areAllManifest() @@ -7709,7 +7710,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } public void ManifestShortcuts_localeChange() throws InterruptedException { - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); // Package 1 updated, which has one valid manifest shortcut and one invalid. addManifestShortcutResource( @@ -7717,9 +7718,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.setDynamicShortcuts(list(makeShortcutWithTitle("s1", "title"))); assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( @@ -7730,11 +7731,11 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { ShortcutInfo si = getCallerShortcut("ms1"); assertEquals("ms1", si.getId()); - assertEquals("string-com.android.test.1-user:0-res:" + R.string.shortcut_title1 + "/en", + assertEquals("string-com.android.test.1-user:10-res:" + R.string.shortcut_title1 + "/en", si.getTitle()); - assertEquals("string-com.android.test.1-user:0-res:" + R.string.shortcut_text1 + "/en", + assertEquals("string-com.android.test.1-user:10-res:" + R.string.shortcut_text1 + "/en", si.getText()); - assertEquals("string-com.android.test.1-user:0-res:" + assertEquals("string-com.android.test.1-user:10-res:" + R.string.shortcut_disabled_message1 + "/en", si.getDisabledMessage()); assertEquals(START_TIME, si.getLastChangedTimestamp()); @@ -7743,11 +7744,11 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { si = getCallerShortcut("ms2"); assertEquals("ms2", si.getId()); - assertEquals("string-com.android.test.1-user:0-res:" + R.string.shortcut_title2 + "/en", + assertEquals("string-com.android.test.1-user:10-res:" + R.string.shortcut_title2 + "/en", si.getTitle()); - assertEquals("string-com.android.test.1-user:0-res:" + R.string.shortcut_text2 + "/en", + assertEquals("string-com.android.test.1-user:10-res:" + R.string.shortcut_text2 + "/en", si.getText()); - assertEquals("string-com.android.test.1-user:0-res:" + assertEquals("string-com.android.test.1-user:10-res:" + R.string.shortcut_disabled_message2 + "/en", si.getDisabledMessage()); assertEquals(START_TIME, si.getLastChangedTimestamp()); @@ -7767,23 +7768,23 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Change the locale and send the broadcast, make sure the launcher gets a callback too. mInjectedLocale = Locale.JAPANESE; - setCaller(LAUNCHER_1, USER_0); + setCaller(LAUNCHER_1, USER_10); assertForLauncherCallback(mLauncherApps, () -> { mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED)); - }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0) + }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_10) .haveIds("ms1", "ms2", "s1"); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { // check first shortcut. ShortcutInfo si = getCallerShortcut("ms1"); assertEquals("ms1", si.getId()); - assertEquals("string-com.android.test.1-user:0-res:" + R.string.shortcut_title1 + "/ja", + assertEquals("string-com.android.test.1-user:10-res:" + R.string.shortcut_title1 + "/ja", si.getTitle()); - assertEquals("string-com.android.test.1-user:0-res:" + R.string.shortcut_text1 + "/ja", + assertEquals("string-com.android.test.1-user:10-res:" + R.string.shortcut_text1 + "/ja", si.getText()); - assertEquals("string-com.android.test.1-user:0-res:" + assertEquals("string-com.android.test.1-user:10-res:" + R.string.shortcut_disabled_message1 + "/ja", si.getDisabledMessage()); assertEquals(START_TIME + 1, si.getLastChangedTimestamp()); @@ -7792,11 +7793,11 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { si = getCallerShortcut("ms2"); assertEquals("ms2", si.getId()); - assertEquals("string-com.android.test.1-user:0-res:" + R.string.shortcut_title2 + "/ja", + assertEquals("string-com.android.test.1-user:10-res:" + R.string.shortcut_title2 + "/ja", si.getTitle()); - assertEquals("string-com.android.test.1-user:0-res:" + R.string.shortcut_text2 + "/ja", + assertEquals("string-com.android.test.1-user:10-res:" + R.string.shortcut_text2 + "/ja", si.getText()); - assertEquals("string-com.android.test.1-user:0-res:" + assertEquals("string-com.android.test.1-user:10-res:" + R.string.shortcut_disabled_message2 + "/ja", si.getDisabledMessage()); assertEquals(START_TIME + 1, si.getLastChangedTimestamp()); @@ -7813,7 +7814,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } public void ManifestShortcuts_updateAndDisabled_notPinned() { - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); // First, just publish a manifest shortcut. addManifestShortcutResource( @@ -7821,10 +7822,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); // Only the valid one is published. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1"); @@ -7840,10 +7841,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_1_disable); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); // Because shortcut 1 wasn't pinned, it'll just go away. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEmpty(mManager.getManifestShortcuts()); assertEmpty(mManager.getPinnedShortcuts()); @@ -7853,7 +7854,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } public void ManifestShortcuts_updateAndDisabled_pinned() { - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); // First, just publish a manifest shortcut. addManifestShortcutResource( @@ -7861,10 +7862,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); // Only the valid one is published. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1"); @@ -7874,8 +7875,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertShortcutIds(getCallerShortcuts(), "ms1"); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1"), HANDLE_USER_0); + runWithCaller(LAUNCHER_1, USER_10, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1"), HANDLE_USER_10); }); // Now upgrade, the manifest shortcut is disabled now. @@ -7884,10 +7885,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_1_disable); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); // Because shortcut 1 was pinned, it'll still exist as pinned, but disabled. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEmpty(mManager.getManifestShortcuts()); assertShortcutIds(assertAllNotManifest(assertAllImmutable(assertAllDisabled( mManager.getPinnedShortcuts()))), @@ -7909,7 +7910,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } public void ManifestShortcuts_duplicateInSingleActivity() { - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); // The XML has two shortcuts with the same ID. addManifestShortcutResource( @@ -7917,9 +7918,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_2_duplicate); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1"); @@ -7934,7 +7935,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } public void ManifestShortcuts_duplicateInTwoActivities() { - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); // ShortcutActivity has shortcut ms1 addManifestShortcutResource( @@ -7947,9 +7948,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_5); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( mManager.getManifestShortcuts()))), "ms1", "ms2", "ms3", "ms4", "ms5"); @@ -7986,11 +7987,11 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { * Manifest shortcuts cannot override shortcuts that were published via the APIs. */ public void ManifestShortcuts_cannotOverrideNonManifest() { - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); // Create a non-pinned dynamic shortcut and a non-dynamic pinned shortcut. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.setDynamicShortcuts(list( makeShortcut("ms1", "title1", new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), @@ -8000,11 +8001,11 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { /* icon */ null, new Intent("action1"), /* rank */ 0))); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2"), HANDLE_USER_0); + runWithCaller(LAUNCHER_1, USER_10, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2"), HANDLE_USER_10); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.removeDynamicShortcuts(list("ms2")); assertShortcutIds(mManager.getDynamicShortcuts(), "ms1"); @@ -8019,9 +8020,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_5); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllNotManifest(mManager.getDynamicShortcuts()), "ms1"); assertShortcutIds(assertAllNotManifest(mManager.getPinnedShortcuts()), "ms2"); assertShortcutIds(assertAllManifest(mManager.getManifestShortcuts()), @@ -8037,7 +8038,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } protected void checkManifestShortcuts_immutable_verify() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertShortcutIds(assertAllNotManifest(assertAllEnabled( mManager.getDynamicShortcuts())), "s1"); @@ -8059,7 +8060,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { * Make sure the APIs won't work on manifest shortcuts. */ public void ManifestShortcuts_immutable() { - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); // Create a non-pinned manifest shortcut, a pinned shortcut that was originally // a manifest shortcut, as well as a dynamic shortcut. @@ -8069,10 +8070,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); - runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2"), HANDLE_USER_0); + runWithCaller(LAUNCHER_1, USER_10, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2"), HANDLE_USER_10); }); addManifestShortcutResource( @@ -8080,9 +8081,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.addDynamicShortcuts(list(makeShortcutWithTitle("s1", "t1"))); }); @@ -8091,7 +8092,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Note that even though the first argument is not immutable and only the second one // is immutable, the first argument should not be executed either. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertCannotUpdateImmutable(() -> { mManager.setDynamicShortcuts(list(makeShortcut("xx"), makeShortcut("ms1"))); }); @@ -8101,7 +8102,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); checkManifestShortcuts_immutable_verify(); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertCannotUpdateImmutable(() -> { mManager.addDynamicShortcuts(list(makeShortcut("xx"), makeShortcut("ms1"))); }); @@ -8112,7 +8113,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { checkManifestShortcuts_immutable_verify(); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertCannotUpdateImmutable(() -> { mManager.updateShortcuts(list(makeShortcut("s1"), makeShortcut("ms1"))); }); @@ -8122,7 +8123,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); checkManifestShortcuts_immutable_verify(); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertCannotUpdateImmutable(() -> { mManager.removeDynamicShortcuts(list("s1", "ms1")); }); @@ -8132,14 +8133,14 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); checkManifestShortcuts_immutable_verify(); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertCannotUpdateImmutable(() -> { mManager.disableShortcuts(list("s1", "ms1")); }); }); checkManifestShortcuts_immutable_verify(); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertCannotUpdateImmutable(() -> { mManager.enableShortcuts(list("s1", "ms2")); }); @@ -8155,16 +8156,16 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Change the max number of shortcuts. mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=3"); - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); addManifestShortcutResource( new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_5); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { // Only the first 3 should be published. assertShortcutIds(mManager.getManifestShortcuts(), "ms1", "ms2", "ms3"); }); @@ -8174,7 +8175,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Change the max number of shortcuts. mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=3"); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { final ComponentName a1 = new ComponentName(mClientContext, ShortcutActivity.class); final ComponentName a2 = new ComponentName(mClientContext, ShortcutActivity2.class); final ShortcutInfo s1_1 = makeShortcutWithActivity("s11", a1); @@ -8232,7 +8233,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); assertEquals(2, mManager.getManifestShortcuts().size()); // Setting 1 to activity 1 will work. @@ -8255,7 +8256,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Change the max number of shortcuts. mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=3"); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { final ComponentName a1 = new ComponentName(mClientContext, ShortcutActivity.class); final ComponentName a2 = new ComponentName(mClientContext, ShortcutActivity2.class); final ShortcutInfo s1_1 = makeShortcutWithActivity("s11", a1); @@ -8305,9 +8306,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Make sure pinned shortcuts won't affect. // - Pin s11 - s13, and remove all dynamic. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s11", "s12", "s13"), - HANDLE_USER_0); + HANDLE_USER_10); }); mManager.removeAllDynamicShortcuts(); @@ -8358,7 +8359,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); assertEquals(2, mManager.getManifestShortcuts().size()); @@ -8382,7 +8383,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Change the max number of shortcuts. mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=3"); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { final ComponentName a1 = new ComponentName(mClientContext, ShortcutActivity.class); final ComponentName a2 = new ComponentName(mClientContext, ShortcutActivity2.class); final ShortcutInfo s1_1 = makeShortcutWithActivity("s11", a1); @@ -8431,9 +8432,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { "s11", "s12", "s13", "s21", "s22", "s23"); // Pin some to have more shortcuts for a1. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s11", "s12", "s13"), - HANDLE_USER_0); + HANDLE_USER_10); }); mManager.setDynamicShortcuts(list(s1_4, s1_5, s2_1, s2_2, s2_3)); assertShortcutIds(mManager.getDynamicShortcuts(), @@ -8473,7 +8474,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Change the max number of shortcuts. mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=3"); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { final ComponentName a1 = new ComponentName(mClientContext, ShortcutActivity.class); final ComponentName a2 = new ComponentName(mClientContext, ShortcutActivity2.class); final ShortcutInfo s1_1 = makeShortcutWithActivityAndRank("s11", a1, 4); @@ -8489,9 +8490,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Initial state. mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3, s2_1, s2_2, s2_3)); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s11", "s12", "s21", "s22"), - HANDLE_USER_0); + HANDLE_USER_10); }); mManager.setDynamicShortcuts(list(s1_2, s1_3, s1_4, s2_2, s2_3, s2_4)); assertShortcutIds(assertAllEnabled(mManager.getDynamicShortcuts()), @@ -8507,7 +8508,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); assertEquals(1, mManager.getManifestShortcuts().size()); // s12 removed. @@ -8527,7 +8528,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_1_alt); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); assertEquals(3, mManager.getManifestShortcuts().size()); // Note the ones with the highest rank values (== least important) will be removed. @@ -8547,7 +8548,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_5_alt); // manifest has 5, but max is 3, so a2 will have 3. updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); assertEquals(5, mManager.getManifestShortcuts().size()); assertShortcutIds(assertAllEnabled(mManager.getDynamicShortcuts()), @@ -8566,7 +8567,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_0); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); assertEquals(0, mManager.getManifestShortcuts().size()); assertShortcutIds(assertAllEnabled(mManager.getDynamicShortcuts()), @@ -8584,9 +8585,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(mManager.getManifestShortcuts()) .haveIds("ms1") .forAllShortcuts(si -> assertTrue(si.isReturnedByServer())); @@ -8599,21 +8600,21 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Pin them. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1", "s1"), getCallingUser()); - assertWith(getShortcutAsLauncher(USER_0)) + assertWith(getShortcutAsLauncher(USER_10)) .haveIds("ms1", "s1") .forAllShortcuts(si -> assertTrue(si.isReturnedByServer())); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(mManager.getPinnedShortcuts()) .haveIds("ms1", "s1") .forAllShortcuts(si -> assertTrue(si.isReturnedByServer())); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { // This shows a warning log, but should still work. assertTrue(mManager.setDynamicShortcuts(mManager.getDynamicShortcuts())); @@ -8624,9 +8625,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } public void IsForegroundDefaultLauncher_true() { - final int uid = 1024; + // random uid in the USER_10 range. + final int uid = 1000024; - setDefaultLauncher(UserHandle.USER_SYSTEM, "default"); + setDefaultLauncher(USER_10, "default"); makeUidForeground(uid); assertTrue(mInternal.isForegroundDefaultLauncher("default", uid)); @@ -8634,18 +8636,20 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { public void IsForegroundDefaultLauncher_defaultButNotForeground() { - final int uid = 1024; + // random uid in the USER_10 range. + final int uid = 1000024; - setDefaultLauncher(UserHandle.USER_SYSTEM, "default"); + setDefaultLauncher(USER_10, "default"); makeUidBackground(uid); assertFalse(mInternal.isForegroundDefaultLauncher("default", uid)); } public void IsForegroundDefaultLauncher_foregroundButNotDefault() { - final int uid = 1024; + // random uid in the USER_10 range. + final int uid = 1000024; - setDefaultLauncher(UserHandle.USER_SYSTEM, "default"); + setDefaultLauncher(USER_10, "default"); makeUidForeground(uid); assertFalse(mInternal.isForegroundDefaultLauncher("another", uid)); @@ -8670,7 +8674,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_share_targets); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); List<ShareTargetInfo> shareTargets = getCallerShareTargets(); @@ -8775,9 +8779,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_share_targets); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); final ShortcutInfo s1 = makeShortcutWithCategory("s1", set("com.test.category.CATEGORY1", "com.test.category.CATEGORY2")); @@ -8796,26 +8800,26 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { IntentFilter filter_any = new IntentFilter(); filter_any.addDataType("*/*"); - setCaller(LAUNCHER_1, USER_0); + setCaller(LAUNCHER_1, USER_10); mCallerPermissions.add(permission.MANAGE_APP_PREDICTIONS); - assertTrue(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s1", USER_0, + assertTrue(mInternal.isSharingShortcut(USER_10, LAUNCHER_1, CALLING_PACKAGE_1, "s1", USER_10, filter_cat1)); - assertFalse(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s1", USER_0, + assertFalse(mInternal.isSharingShortcut(USER_10, LAUNCHER_1, CALLING_PACKAGE_1, "s1", USER_10, filter_cat5)); - assertTrue(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s1", USER_0, + assertTrue(mInternal.isSharingShortcut(USER_10, LAUNCHER_1, CALLING_PACKAGE_1, "s1", USER_10, filter_any)); - assertFalse(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s2", USER_0, + assertFalse(mInternal.isSharingShortcut(USER_10, LAUNCHER_1, CALLING_PACKAGE_1, "s2", USER_10, filter_cat1)); - assertTrue(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s2", USER_0, + assertTrue(mInternal.isSharingShortcut(USER_10, LAUNCHER_1, CALLING_PACKAGE_1, "s2", USER_10, filter_cat5)); - assertTrue(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s2", USER_0, + assertTrue(mInternal.isSharingShortcut(USER_10, LAUNCHER_1, CALLING_PACKAGE_1, "s2", USER_10, filter_any)); - assertFalse(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s3", USER_0, + assertFalse(mInternal.isSharingShortcut(USER_10, LAUNCHER_1, CALLING_PACKAGE_1, "s3", USER_10, filter_any)); - assertFalse(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s4", USER_0, + assertFalse(mInternal.isSharingShortcut(USER_10, LAUNCHER_1, CALLING_PACKAGE_1, "s4", USER_10, filter_any)); } @@ -8826,7 +8830,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_share_targets); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); final ShortcutInfo s1 = makeShortcutWithCategory("s1", set("com.test.category.CATEGORY1", "com.test.category.CATEGORY2")); @@ -8837,7 +8841,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { s1.setLongLived(); s2.setLongLived(); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list(s1, s2, s3))); assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()), "s1", "s2", "s3"); @@ -8846,33 +8850,33 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { IntentFilter filter_any = new IntentFilter(); filter_any.addDataType("*/*"); - setCaller(LAUNCHER_1, USER_0); + setCaller(LAUNCHER_1, USER_10); mCallerPermissions.add(permission.MANAGE_APP_PREDICTIONS); // Assert all are sharing shortcuts - assertTrue(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s1", USER_0, + assertTrue(mInternal.isSharingShortcut(USER_10, LAUNCHER_1, CALLING_PACKAGE_1, "s1", USER_10, filter_any)); - assertTrue(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s2", USER_0, + assertTrue(mInternal.isSharingShortcut(USER_10, LAUNCHER_1, CALLING_PACKAGE_1, "s2", USER_10, filter_any)); - assertTrue(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s3", USER_0, + assertTrue(mInternal.isSharingShortcut(USER_10, LAUNCHER_1, CALLING_PACKAGE_1, "s3", USER_10, filter_any)); mInjectCheckAccessShortcutsPermission = true; - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), HANDLE_USER_0, + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), HANDLE_USER_10, CACHE_OWNER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_10); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { // Remove one cached shortcut, and leave one cached-only and pinned-only shortcuts. mManager.removeLongLivedShortcuts(list("s1")); mManager.removeDynamicShortcuts(list("s2, s3")); }); - assertFalse(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s1", USER_0, + assertFalse(mInternal.isSharingShortcut(USER_10, LAUNCHER_1, CALLING_PACKAGE_1, "s1", USER_10, filter_any)); - assertTrue(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s2", USER_0, + assertTrue(mInternal.isSharingShortcut(USER_10, LAUNCHER_1, CALLING_PACKAGE_1, "s2", USER_10, filter_any)); - assertTrue(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s3", USER_0, + assertTrue(mInternal.isSharingShortcut(USER_10, LAUNCHER_1, CALLING_PACKAGE_1, "s3", USER_10, filter_any)); } @@ -8881,17 +8885,17 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { final ShortcutInfo s2 = makeShortcutExcludedFromLauncher("s2"); final ShortcutInfo s3 = makeShortcutExcludedFromLauncher("s3"); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list(s1, s2, s3))); assertEmpty(mManager.getDynamicShortcuts()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.addDynamicShortcuts(list(s1, s2, s3))); assertEmpty(mManager.getDynamicShortcuts()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.pushDynamicShortcut(s1); assertEmpty(mManager.getDynamicShortcuts()); }); @@ -8902,7 +8906,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { final ShortcutInfo s2 = makeShortcut("s2"); final ShortcutInfo s3 = makeShortcut("s3"); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list(s1, s2, s3))); assertThrown(IllegalArgumentException.class, () -> { mManager.updateShortcuts(list(makeShortcutExcludedFromLauncher("s1"))); @@ -8911,7 +8915,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } public void PinHiddenShortcuts_ThrowsException() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertThrown(IllegalArgumentException.class, () -> { mManager.requestPinShortcut(makeShortcutExcludedFromLauncher("s1"), null); }); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest10.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest10.java index 57ada9b9c499..748f0a5dc949 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest10.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest10.java @@ -28,7 +28,6 @@ import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps.PinItemRequest; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; -import android.os.Process; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; @@ -56,7 +55,7 @@ public class ShortcutManagerTest10 extends BaseShortcutManagerTest { } public void testCreateShortcutResult_validResult() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { ShortcutInfo s1 = makeShortcut("s1"); @@ -64,20 +63,20 @@ public class ShortcutManagerTest10 extends BaseShortcutManagerTest { mRequest = verifyAndGetCreateShortcutResult(intent); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { assertTrue(mRequest.isValid()); assertTrue(mRequest.accept()); }); } public void testCreateShortcutResult_alreadyPinned() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1")))); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_P0); }); @@ -87,7 +86,7 @@ public class ShortcutManagerTest10 extends BaseShortcutManagerTest { mRequest = verifyAndGetCreateShortcutResult(intent); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { assertTrue(mRequest.isValid()); assertTrue(mRequest.getShortcutInfo().isPinned()); assertTrue(mRequest.accept()); @@ -100,18 +99,18 @@ public class ShortcutManagerTest10 extends BaseShortcutManagerTest { }); // Initially all launchers have the shortcut permission, until we call setDefaultLauncher(). - runWithCaller(LAUNCHER_2, USER_0, () -> { + runWithCaller(LAUNCHER_2, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_P0); }); - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { ShortcutInfo s1 = makeShortcut("s1"); Intent intent = mManager.createShortcutResultIntent(s1); mRequest = verifyAndGetCreateShortcutResult(intent); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { assertTrue(mRequest.isValid()); assertFalse(mRequest.getShortcutInfo().isPinned()); assertTrue(mRequest.accept()); @@ -119,7 +118,7 @@ public class ShortcutManagerTest10 extends BaseShortcutManagerTest { } public void testCreateShortcutResult_defaultLauncherChanges() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { ShortcutInfo s1 = makeShortcut("s1"); @@ -127,15 +126,15 @@ public class ShortcutManagerTest10 extends BaseShortcutManagerTest { mRequest = verifyAndGetCreateShortcutResult(intent); }); - setDefaultLauncher(USER_0, LAUNCHER_2); + setDefaultLauncher(USER_10, LAUNCHER_2); // Verify that other launcher can't use this request - runWithCaller(LAUNCHER_2, USER_0, () -> { + runWithCaller(LAUNCHER_2, USER_10, () -> { assertFalse(mRequest.isValid()); assertExpectException(SecurityException.class, "Calling uid mismatch", mRequest::accept); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Set some random caller UID. mInjectedCallingUid = 12345; @@ -144,7 +143,7 @@ public class ShortcutManagerTest10 extends BaseShortcutManagerTest { mRequest::accept); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { assertTrue(mRequest.isValid()); assertTrue(mRequest.accept()); }); @@ -157,23 +156,23 @@ public class ShortcutManagerTest10 extends BaseShortcutManagerTest { LauncherActivityInfo info = mock(LauncherActivityInfo.class); when(info.getComponentName()).thenReturn( new ComponentName(getTestContext(), "a.ShortcutConfigActivity")); - when(info.getUser()).thenReturn(Process.myUserHandle()); + when(info.getUser()).thenReturn(HANDLE_USER_10); return info; } public void testStartConfigActivity_defaultLauncher() { LauncherActivityInfo info = setupMockActivityInfo(); prepareIntentActivities(info.getComponentName()); - setDefaultLauncher(USER_0, LAUNCHER_1); - runWithCaller(LAUNCHER_1, USER_0, () -> + setDefaultLauncher(USER_10, LAUNCHER_1); + runWithCaller(LAUNCHER_1, USER_10, () -> assertNotNull(mLauncherApps.getShortcutConfigActivityIntent(info)) ); } public void testStartConfigActivity_nonDefaultLauncher() { LauncherActivityInfo info = setupMockActivityInfo(); - setDefaultLauncher(USER_0, LAUNCHER_1); - runWithCaller(LAUNCHER_2, USER_0, () -> + setDefaultLauncher(USER_10, LAUNCHER_1); + runWithCaller(LAUNCHER_2, USER_10, () -> assertExpectException(SecurityException.class, null, () -> mLauncherApps.getShortcutConfigActivityIntent(info)) ); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest11.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest11.java index 98fa2d68fb73..676558ddcf6c 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest11.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest11.java @@ -56,12 +56,12 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { public void testShortcutChangeCallback_setDynamicShortcuts() { ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(makeShortcuts("s1", "s2"))); }); @@ -69,7 +69,7 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_10)); verify(callback, times(0)).onShortcutsRemoved(any(), any(), any()); assertWith(shortcuts.getValue()) @@ -78,17 +78,17 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { } public void testShortcutChangeCallback_setDynamicShortcuts_replaceSameId() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(makeShortcuts("s1", "s2"))); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(makeShortcuts("s2", "s3"))); }); @@ -96,11 +96,11 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> changedShortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_10)); ArgumentCaptor<List> removedShortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsRemoved( - eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_10)); assertWith(changedShortcuts.getValue()) .areAllWithKeyFieldsOnly() @@ -112,25 +112,25 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { } public void testShortcutChangeCallback_setDynamicShortcuts_pinnedAndCached() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts( list(makeShortcut("s1"), makeLongLivedShortcut("s2")))); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0); + runWithCaller(LAUNCHER_1, USER_10, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_10); mInjectCheckAccessShortcutsPermission = true; - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0, + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_10, CACHE_OWNER_0); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(makeShortcuts("s3", "s4"))); }); @@ -138,7 +138,7 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> changedShortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_10)); verify(callback, times(0)).onShortcutsRemoved(any(), any(), any()); assertWith(changedShortcuts.getValue()) @@ -147,22 +147,22 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { } public void testShortcutChangeCallback_pinShortcuts() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(makeShortcuts("s1", "s2"))); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_10); }); mTestLooper.dispatchAll(); ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_10)); verify(callback, times(0)).onShortcutsRemoved(any(), any(), any()); assertWith(shortcuts.getValue()) @@ -171,34 +171,34 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { } public void testShortcutChangeCallback_pinShortcuts_unpinOthers() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(makeShortcuts("s1", "s2", "s3"))); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), HANDLE_USER_0); + runWithCaller(LAUNCHER_1, USER_10, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), HANDLE_USER_10); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.removeDynamicShortcuts(list("s1", "s2")); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s3"), HANDLE_USER_0); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s3"), HANDLE_USER_10); }); mTestLooper.dispatchAll(); ArgumentCaptor<List> changedShortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_10)); ArgumentCaptor<List> removedShortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsRemoved( - eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_10)); assertWith(changedShortcuts.getValue()) .areAllWithKeyFieldsOnly() @@ -210,19 +210,19 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { } public void testShortcutChangeCallback_cacheShortcuts() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list(makeLongLivedShortcut("s1"), makeLongLivedShortcut("s2"), makeLongLivedShortcut("s3")))); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); mInjectCheckAccessShortcutsPermission = true; - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_0, + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_10, CACHE_OWNER_0); - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_0, + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_10, CACHE_OWNER_1); }); @@ -230,7 +230,7 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(2)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_10)); verify(callback, times(0)).onShortcutsRemoved(any(), any(), any()); assertWith(shortcuts.getValue()) @@ -239,23 +239,23 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { } public void testShortcutChangeCallback_cacheShortcuts_alreadyCached() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list(makeLongLivedShortcut("s1"), makeLongLivedShortcut("s2"), makeLongLivedShortcut("s3")))); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mInjectCheckAccessShortcutsPermission = true; - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_0, + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_10, CACHE_OWNER_0); mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); // Should not cause any callback events - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_0, + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_10, CACHE_OWNER_0); // Should cause a change event - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_0, + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_10, CACHE_OWNER_1); }); @@ -263,7 +263,7 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_10)); verify(callback, times(0)).onShortcutsRemoved(any(), any(), any()); assertWith(shortcuts.getValue()) @@ -272,19 +272,19 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { } public void testShortcutChangeCallback_uncacheShortcuts() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list(makeLongLivedShortcut("s1"), makeLongLivedShortcut("s2"), makeLongLivedShortcut("s3")))); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mInjectCheckAccessShortcutsPermission = true; - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), HANDLE_USER_0, + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), HANDLE_USER_10, CACHE_OWNER_0); mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); - mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0, + mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_10, CACHE_OWNER_0); }); @@ -292,7 +292,7 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_10)); verify(callback, times(0)).onShortcutsRemoved(any(), any(), any()); assertWith(shortcuts.getValue()) @@ -301,41 +301,41 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { } public void testShortcutChangeCallback_uncacheShortcuts_causeDeletion() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list(makeLongLivedShortcut("s1"), makeLongLivedShortcut("s2"), makeLongLivedShortcut("s3")))); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mInjectCheckAccessShortcutsPermission = true; - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3"), HANDLE_USER_0, + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3"), HANDLE_USER_10, CACHE_OWNER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0); - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0, + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_10); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_10, CACHE_OWNER_1); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.removeDynamicShortcuts(list("s2", "s3")); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); - mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3"), HANDLE_USER_0, - CACHE_OWNER_0); + mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3"), + HANDLE_USER_10, CACHE_OWNER_0); }); mTestLooper.dispatchAll(); ArgumentCaptor<List> changedShortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_10)); ArgumentCaptor<List> removedShortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsRemoved( - eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_10)); // s1 is still cached for owner1, s2 is pinned. assertWith(changedShortcuts.getValue()) @@ -348,19 +348,19 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { } public void testShortcutChangeCallback_updateShortcuts() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"), makeShortcutWithActivity("s2", new ComponentName(CALLING_PACKAGE_1, "test"))))); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); }); final ComponentName updatedCn = new ComponentName(CALLING_PACKAGE_1, "updated activity"); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.updateShortcuts(list(makeShortcutWithActivity("s2", updatedCn)))); }); @@ -368,7 +368,7 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_10)); verify(callback, times(0)).onShortcutsRemoved(any(), any(), any()); assertWith(shortcuts.getValue()) @@ -378,17 +378,17 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { } public void testShortcutChangeCallback_addDynamicShortcuts() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(makeShortcuts("s1"))); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.addDynamicShortcuts(makeShortcuts("s1", "s2"))); }); @@ -396,7 +396,7 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_10)); verify(callback, times(0)).onShortcutsRemoved(any(), any(), any()); assertWith(shortcuts.getValue()) @@ -406,12 +406,12 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { public void testShortcutChangeCallback_pushDynamicShortcut() { ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.pushDynamicShortcut(makeShortcut("s1")); }); @@ -419,7 +419,7 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_10)); verify(callback, times(0)).onShortcutsRemoved(any(), any(), any()); assertWith(shortcuts.getValue()) @@ -431,17 +431,17 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { // Change the max number of shortcuts. mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=3"); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts((makeShortcuts("s1", "s2", "s3")))); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.pushDynamicShortcut(makeShortcut("s2")); }); @@ -449,7 +449,7 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_10)); verify(callback, times(0)).onShortcutsRemoved(any(), any(), any()); assertWith(shortcuts.getValue()) @@ -461,17 +461,17 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { // Change the max number of shortcuts. mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=3"); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts((makeShortcuts("s1", "s2", "s3")))); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.pushDynamicShortcut(makeShortcut("s4")); }); @@ -479,11 +479,11 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> changedShortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_10)); ArgumentCaptor<List> removedShortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsRemoved( - eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_10)); assertWith(changedShortcuts.getValue()) .areAllWithKeyFieldsOnly() @@ -498,7 +498,7 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { // Change the max number of shortcuts. mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=3"); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts((makeShortcuts("s1", "s2")))); ShortcutInfo s3 = makeLongLivedShortcut("s3"); s3.setRank(3); @@ -506,15 +506,15 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mInjectCheckAccessShortcutsPermission = true; - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0, + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_10, CACHE_OWNER_0); mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.pushDynamicShortcut(makeShortcut("s4")); }); @@ -522,7 +522,7 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_10)); verify(callback, times(0)).onShortcutsRemoved(any(), any(), any()); assertWith(shortcuts.getValue()) @@ -532,17 +532,17 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { public void testShortcutChangeCallback_disableShortcuts() { updatePackageVersion(CALLING_PACKAGE_1, 1); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(makeShortcuts("s1", "s2"))); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.disableShortcuts(list("s2")); }); @@ -552,7 +552,7 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsRemoved( - eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_10)); assertWith(shortcuts.getValue()) .areAllWithKeyFieldsOnly() @@ -560,22 +560,22 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { } public void testShortcutChangeCallback_disableShortcuts_pinnedAndCached() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts( list(makeShortcut("s1"), makeLongLivedShortcut("s2"), makeShortcut("s3")))); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mInjectCheckAccessShortcutsPermission = true; - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0, + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_10, CACHE_OWNER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_10); mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.disableShortcuts(list("s1", "s2", "s3")); }); @@ -583,11 +583,11 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> changedShortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_10)); ArgumentCaptor<List> removedShortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsRemoved( - eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_10)); assertWith(changedShortcuts.getValue()) .areAllWithKeyFieldsOnly() @@ -599,29 +599,29 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { } public void testShortcutChangeCallback_enableShortcuts() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts( list(makeShortcut("s1"), makeLongLivedShortcut("s2"), makeShortcut("s3")))); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mInjectCheckAccessShortcutsPermission = true; - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0, + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_10, CACHE_OWNER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_10); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.disableShortcuts(list("s1", "s2", "s3")); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.enableShortcuts(list("s1", "s2", "s3")); }); @@ -629,7 +629,7 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_10)); verify(callback, times(0)).onShortcutsRemoved(any(), any(), any()); assertWith(shortcuts.getValue()) @@ -639,17 +639,17 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { public void testShortcutChangeCallback_removeDynamicShortcuts() { updatePackageVersion(CALLING_PACKAGE_1, 1); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(makeShortcuts("s1", "s2"))); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.removeDynamicShortcuts(list("s2")); }); @@ -659,7 +659,7 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsRemoved( - eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_10)); assertWith(shortcuts.getValue()) .areAllWithKeyFieldsOnly() @@ -667,22 +667,22 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { } public void testShortcutChangeCallback_removeDynamicShortcuts_pinnedAndCached() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"), makeLongLivedShortcut("s2"), makeShortcut("s3"), makeShortcut("s4")))); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mInjectCheckAccessShortcutsPermission = true; - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0, + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_10, CACHE_OWNER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_10); mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.removeDynamicShortcuts(list("s1", "s2", "s3")); }); @@ -690,11 +690,11 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> changedShortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_10)); ArgumentCaptor<List> removedShortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsRemoved( - eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_10)); assertWith(changedShortcuts.getValue()) .areAllWithKeyFieldsOnly() @@ -707,17 +707,17 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { public void testShortcutChangeCallback_removeAllDynamicShortcuts() { updatePackageVersion(CALLING_PACKAGE_1, 1); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(makeShortcuts("s1", "s2"))); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.removeAllDynamicShortcuts(); }); @@ -727,7 +727,7 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsRemoved( - eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_10)); assertWith(shortcuts.getValue()) .areAllWithKeyFieldsOnly() @@ -735,22 +735,22 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { } public void testShortcutChangeCallback_removeAllDynamicShortcuts_pinnedAndCached() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts( list(makeShortcut("s1"), makeLongLivedShortcut("s2"), makeShortcut("s3")))); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mInjectCheckAccessShortcutsPermission = true; - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0, + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_10, CACHE_OWNER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_10); mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.removeAllDynamicShortcuts(); }); @@ -758,11 +758,11 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> changedShortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_10)); ArgumentCaptor<List> removedShortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsRemoved( - eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_10)); assertWith(changedShortcuts.getValue()) .areAllWithKeyFieldsOnly() @@ -775,18 +775,18 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { public void testShortcutChangeCallback_removeLongLivedShortcuts_notCached() { updatePackageVersion(CALLING_PACKAGE_1, 1); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"), makeLongLivedShortcut("s2"), makeShortcut("s3")))); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.removeLongLivedShortcuts(list("s1", "s2")); }); @@ -796,7 +796,7 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsRemoved( - eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_10)); assertWith(shortcuts.getValue()) .areAllWithKeyFieldsOnly() @@ -804,22 +804,22 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { } public void testShortcutChangeCallback_removeLongLivedShortcuts_pinnedAndCached() { - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"), makeLongLivedShortcut("s2"), makeShortcut("s3"), makeShortcut("s4")))); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mInjectCheckAccessShortcutsPermission = true; - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0, + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_10, CACHE_OWNER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_10); mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); }); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.removeLongLivedShortcuts(list("s1", "s2", "s3")); }); @@ -827,11 +827,11 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ArgumentCaptor<List> changedShortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsAddedOrUpdated( - eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_10)); ArgumentCaptor<List> removedShortcuts = ArgumentCaptor.forClass(List.class); verify(callback, times(1)).onShortcutsRemoved( - eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_0)); + eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_10)); assertWith(changedShortcuts.getValue()) .areAllWithKeyFieldsOnly() diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java index 78bcf0c692b8..10e8bf039627 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java @@ -50,21 +50,21 @@ public class ShortcutManagerTest12 extends BaseShortcutManagerTest { @Override protected void tearDown() throws Exception { if (mService.isAppSearchEnabled()) { - setCaller(CALLING_PACKAGE_1, USER_0); - mService.getPackageShortcutForTest(CALLING_PACKAGE_1, USER_0) + setCaller(CALLING_PACKAGE_1, USER_10); + mService.getPackageShortcutForTest(CALLING_PACKAGE_1, USER_10) .removeAllShortcutsAsync(); } super.tearDown(); } public void testGetShortcutIntents_ReturnsMutablePendingIntents() throws RemoteException { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1")))) ); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { final PendingIntent intent = mLauncherApps.getShortcutIntent( CALLING_PACKAGE_1, "s1", null, UserHandle.SYSTEM); assertNotNull(intent); @@ -75,7 +75,7 @@ public class ShortcutManagerTest12 extends BaseShortcutManagerTest { if (!mService.isAppSearchEnabled()) { return; } - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); // Verifies setDynamicShortcuts persists shortcuts into AppSearch mManager.setDynamicShortcuts(list( makeShortcut("s1"), @@ -102,7 +102,7 @@ public class ShortcutManagerTest12 extends BaseShortcutManagerTest { if (!mService.isAppSearchEnabled()) { return; } - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), @@ -126,7 +126,7 @@ public class ShortcutManagerTest12 extends BaseShortcutManagerTest { if (!mService.isAppSearchEnabled()) { return; } - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), @@ -168,7 +168,7 @@ public class ShortcutManagerTest12 extends BaseShortcutManagerTest { if (!mService.isAppSearchEnabled()) { return; } - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), @@ -194,7 +194,7 @@ public class ShortcutManagerTest12 extends BaseShortcutManagerTest { if (!mService.isAppSearchEnabled()) { return; } - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), @@ -218,7 +218,7 @@ public class ShortcutManagerTest12 extends BaseShortcutManagerTest { if (!mService.isAppSearchEnabled()) { return; } - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), @@ -243,7 +243,7 @@ public class ShortcutManagerTest12 extends BaseShortcutManagerTest { if (!mService.isAppSearchEnabled()) { return; } - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); mManager.setDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2"), @@ -266,7 +266,7 @@ public class ShortcutManagerTest12 extends BaseShortcutManagerTest { if (!mService.isAppSearchEnabled()) { return; } - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); mManager.setDynamicShortcuts(list( makeShortcutExcludedFromLauncher("s1"), makeShortcutExcludedFromLauncher("s2"), diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java index 1cfaf7c83584..9528467f7ad1 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java @@ -238,15 +238,15 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { } public void testShortcutInfoParcel() { - setCaller(CALLING_PACKAGE_1, USER_10); + setCaller(CALLING_PACKAGE_1, USER_11); ShortcutInfo si = parceled(new ShortcutInfo.Builder(mClientContext) .setId("id") .setTitle("title") .setIntent(makeIntent("action", ShortcutActivity.class)) .build()); assertEquals(mClientContext.getPackageName(), si.getPackage()); - assertEquals(USER_10, si.getUserId()); - assertEquals(HANDLE_USER_10, si.getUserHandle()); + assertEquals(USER_11, si.getUserId()); + assertEquals(HANDLE_USER_11, si.getUserHandle()); assertEquals("id", si.getId()); assertEquals("title", si.getTitle()); assertEquals("action", si.getIntent().getAction()); @@ -325,7 +325,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { } public void testShortcutInfoParcel_resId() { - setCaller(CALLING_PACKAGE_1, USER_10); + setCaller(CALLING_PACKAGE_1, USER_11); ShortcutInfo si; PersistableBundle pb = new PersistableBundle(); @@ -379,7 +379,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { } public void testShortcutInfoClone() { - setCaller(CALLING_PACKAGE_1, USER_11); + setCaller(CALLING_PACKAGE_1, USER_12); PersistableBundle pb = new PersistableBundle(); pb.putInt("k", 1); @@ -406,8 +406,8 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { ShortcutInfo si = sorig.clone(/* clone flags*/ 0); - assertEquals(USER_11, si.getUserId()); - assertEquals(HANDLE_USER_11, si.getUserHandle()); + assertEquals(USER_12, si.getUserId()); + assertEquals(HANDLE_USER_12, si.getUserHandle()); assertEquals(mClientContext.getPackageName(), si.getPackage()); assertEquals("id", si.getId()); assertEquals(new ComponentName("a", "b"), si.getActivity()); @@ -527,7 +527,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { } public void testShortcutInfoClone_resId() { - setCaller(CALLING_PACKAGE_1, USER_11); + setCaller(CALLING_PACKAGE_1, USER_12); PersistableBundle pb = new PersistableBundle(); pb.putInt("k", 1); @@ -552,8 +552,8 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { ShortcutInfo si = sorig.clone(/* clone flags*/ 0); - assertEquals(USER_11, si.getUserId()); - assertEquals(HANDLE_USER_11, si.getUserHandle()); + assertEquals(USER_12, si.getUserId()); + assertEquals(HANDLE_USER_12, si.getUserHandle()); assertEquals(mClientContext.getPackageName(), si.getPackage()); assertEquals("id", si.getId()); assertEquals(new ComponentName("a", "b"), si.getActivity()); @@ -953,9 +953,9 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { } public void testShortcutInfoSaveAndLoad() throws InterruptedException { - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - setCaller(CALLING_PACKAGE_1, USER_10); + setCaller(CALLING_PACKAGE_1, USER_11); final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.black_32x32)); @@ -1010,16 +1010,16 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { // Save and load. mService.saveDirtyInfo(); initService(); - mService.handleUnlockUser(USER_10); + mService.handleUnlockUser(USER_11); - dumpUserFile(USER_10); + dumpUserFile(USER_11); dumpsysOnLogcat("after load"); ShortcutInfo si; - si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10); + si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_11); - assertEquals(USER_10, si.getUserId()); - assertEquals(HANDLE_USER_10, si.getUserHandle()); + assertEquals(USER_11, si.getUserId()); + assertEquals(HANDLE_USER_11, si.getUserHandle()); assertEquals(CALLING_PACKAGE_1, si.getPackage()); assertEquals("id", si.getId()); assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName()); @@ -1056,19 +1056,19 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { // Make sure ranks are saved too. Because of the auto-adjusting, we need two shortcuts // to test it. - si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_10); + si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_11); assertEquals(1, si.getRank()); assertEquals(2, si.getPersons().length); assertEquals("personUri2", si.getPersons()[1].getUri()); assertEquals("6.7.8.9", si.getLocusId().getId()); - dumpUserFile(USER_10); + dumpUserFile(USER_11); } public void testShortcutInfoSaveAndLoad_maskableBitmap() throws InterruptedException { - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - setCaller(CALLING_PACKAGE_1, USER_10); + setCaller(CALLING_PACKAGE_1, USER_11); final Icon bmp32x32 = Icon.createWithAdaptiveBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.black_32x32)); @@ -1100,16 +1100,16 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { // Save and load. mService.saveDirtyInfo(); initService(); - mService.handleUnlockUser(USER_10); + mService.handleUnlockUser(USER_11); - dumpUserFile(USER_10); + dumpUserFile(USER_11); dumpsysOnLogcat("after load"); ShortcutInfo si; - si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10); + si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_11); - assertEquals(USER_10, si.getUserId()); - assertEquals(HANDLE_USER_10, si.getUserHandle()); + assertEquals(USER_11, si.getUserId()); + assertEquals(HANDLE_USER_11, si.getUserHandle()); assertEquals(CALLING_PACKAGE_1, si.getPackage()); assertEquals("id", si.getId()); assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName()); @@ -1131,13 +1131,13 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertNull(si.getIconUri()); assertTrue(si.getLastChangedTimestamp() < now); - dumpUserFile(USER_10); + dumpUserFile(USER_11); } public void testShortcutInfoSaveAndLoad_resId() throws InterruptedException { - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - setCaller(CALLING_PACKAGE_1, USER_10); + setCaller(CALLING_PACKAGE_1, USER_11); final Icon res32x32 = Icon.createWithResource(mClientContext, R.drawable.black_32x32); @@ -1175,13 +1175,13 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { // Save and load. mService.saveDirtyInfo(); initService(); - mService.handleUnlockUser(USER_10); + mService.handleUnlockUser(USER_11); ShortcutInfo si; - si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10); + si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_11); - assertEquals(USER_10, si.getUserId()); - assertEquals(HANDLE_USER_10, si.getUserHandle()); + assertEquals(USER_11, si.getUserId()); + assertEquals(HANDLE_USER_11, si.getUserHandle()); assertEquals(CALLING_PACKAGE_1, si.getPackage()); assertEquals("id", si.getId()); assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName()); @@ -1207,14 +1207,14 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { // Make sure ranks are saved too. Because of the auto-adjusting, we need two shortcuts // to test it. - si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_10); + si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_11); assertEquals(1, si.getRank()); } public void testShortcutInfoSaveAndLoad_uri() throws InterruptedException { - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - setCaller(CALLING_PACKAGE_1, USER_10); + setCaller(CALLING_PACKAGE_1, USER_11); final Icon uriIcon = Icon.createWithContentUri("test_uri"); @@ -1255,13 +1255,13 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { // Save and load. mService.saveDirtyInfo(); initService(); - mService.handleUnlockUser(USER_10); + mService.handleUnlockUser(USER_11); ShortcutInfo si; - si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10); + si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_11); - assertEquals(USER_10, si.getUserId()); - assertEquals(HANDLE_USER_10, si.getUserHandle()); + assertEquals(USER_11, si.getUserId()); + assertEquals(HANDLE_USER_11, si.getUserHandle()); assertEquals(CALLING_PACKAGE_1, si.getPackage()); assertEquals("id", si.getId()); assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName()); @@ -1288,7 +1288,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { // Make sure ranks are saved too. Because of the auto-adjusting, we need two shortcuts // to test it. - si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_10); + si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_11); assertEquals(1, si.getRank()); assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_URI | ShortcutInfo.FLAG_STRINGS_RESOLVED | ShortcutInfo.FLAG_ADAPTIVE_BITMAP, @@ -1300,7 +1300,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { } public void testShortcutInfoSaveAndLoad_forBackup() { - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.black_32x32)); @@ -1332,16 +1332,16 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { mManager.addDynamicShortcuts(list(sorig, sorig2)); // Dynamic shortcuts won't be backed up, so we need to pin it. - setCaller(LAUNCHER_1, USER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id", "id2"), HANDLE_USER_0); + setCaller(LAUNCHER_1, USER_10); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id", "id2"), HANDLE_USER_10); // Do backup & restore. backupAndRestore(); - mService.handleUnlockUser(USER_0); // Load user-0. + mService.handleUnlockUser(USER_10); // Load user-0. ShortcutInfo si; - si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0); + si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10); assertEquals(CALLING_PACKAGE_1, si.getPackage()); assertEquals("id", si.getId()); @@ -1364,12 +1364,12 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertNull(si.getIconUri()); // Note when restored from backup, it's no longer dynamic, so shouldn't have a rank. - si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_0); + si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_10); assertEquals(0, si.getRank()); } public void testShortcutInfoSaveAndLoad_forBackup_resId() { - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); final Icon res32x32 = Icon.createWithResource(mClientContext, R.drawable.black_32x32); @@ -1399,16 +1399,16 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { mManager.addDynamicShortcuts(list(sorig, sorig2)); // Dynamic shortcuts won't be backed up, so we need to pin it. - setCaller(LAUNCHER_1, USER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id", "id2"), HANDLE_USER_0); + setCaller(LAUNCHER_1, USER_10); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id", "id2"), HANDLE_USER_10); // Do backup & restore. backupAndRestore(); - mService.handleUnlockUser(USER_0); // Load user-0. + mService.handleUnlockUser(USER_10); // Load user-0. ShortcutInfo si; - si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0); + si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10); assertEquals(CALLING_PACKAGE_1, si.getPackage()); assertEquals("id", si.getId()); @@ -1434,12 +1434,12 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertNull(si.getIconUri()); // Note when restored from backup, it's no longer dynamic, so shouldn't have a rank. - si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_0); + si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_10); assertEquals(0, si.getRank()); } public void testShortcutInfoSaveAndLoad_forBackup_uri() { - setCaller(CALLING_PACKAGE_1, USER_0); + setCaller(CALLING_PACKAGE_1, USER_10); final Icon uriIcon = Icon.createWithContentUri("test_uri"); @@ -1469,16 +1469,16 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { mManager.addDynamicShortcuts(list(sorig, sorig2)); // Dynamic shortcuts won't be backed up, so we need to pin it. - setCaller(LAUNCHER_1, USER_0); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id", "id2"), HANDLE_USER_0); + setCaller(LAUNCHER_1, USER_10); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id", "id2"), HANDLE_USER_10); // Do backup & restore. backupAndRestore(); - mService.handleUnlockUser(USER_0); // Load user-0. + mService.handleUnlockUser(USER_10); // Load user-0. ShortcutInfo si; - si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0); + si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10); assertEquals(CALLING_PACKAGE_1, si.getPackage()); assertEquals("id", si.getId()); @@ -1504,7 +1504,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertNull(si.getIconUri()); // Note when restored from backup, it's no longer dynamic, so shouldn't have a rank. - si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_0); + si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_10); assertEquals(0, si.getRank()); } @@ -1512,7 +1512,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertTrue(mManager.setDynamicShortcuts(list( makeShortcutWithIntent("s1", intent)))); initService(); - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); assertWith(getCallerShortcuts()) .haveIds("s1") @@ -1528,7 +1528,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertTrue(mManager.setDynamicShortcuts(list( makeShortcutWithIntents("s1", intents)))); initService(); - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); assertWith(getCallerShortcuts()) .haveIds("s1") @@ -1804,35 +1804,35 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { // but it will work for other users too because we check the locale change at any // API entry point. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_4, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); // Make sure even if we receive ACTION_LOCALE_CHANGED, if the locale hasn't actually // changed, we don't reset throttling. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { mManager.updateShortcuts(list()); assertEquals(2, mManager.getRemainingCallCount()); }); mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(2, mManager.getRemainingCallCount()); // Still 2. }); @@ -1842,7 +1842,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { // The locale should be persisted, so it still shouldn't reset throttling. mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(2, mManager.getRemainingCallCount()); // Still 2. }); } @@ -1861,22 +1861,22 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { // First, all packages have less than 3 (== initial value) remaining calls. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_4, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); @@ -1886,22 +1886,22 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { mService.mUidObserver.onUidStateChanged( CALLING_UID_1, ActivityManager.PROCESS_STATE_TOP_SLEEPING, 0, ActivityManager.PROCESS_CAPABILITY_NONE); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_4, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); @@ -1911,22 +1911,22 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { mService.mUidObserver.onUidStateChanged( CALLING_UID_1, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, ActivityManager.PROCESS_CAPABILITY_NONE); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_4, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); mService.mUidObserver.onUidStateChanged( @@ -1944,22 +1944,22 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { CALLING_UID_2, ActivityManager.PROCESS_STATE_TOP_SLEEPING, 0, ActivityManager.PROCESS_CAPABILITY_NONE); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_4, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); @@ -1967,7 +1967,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { // Do the same thing one more time. This would catch the bug with mixuing up // the current time and the elapsed time. - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { mManager.updateShortcuts(list(makeShortcut("s"))); MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); @@ -1979,22 +1979,22 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { CALLING_UID_2, ActivityManager.PROCESS_STATE_TOP_SLEEPING, 0, ActivityManager.PROCESS_CAPABILITY_NONE); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_4, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); @@ -2003,10 +2003,10 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { // Package 1 on user-10 comes to foreground. // Now, also try calling some APIs and make sure foreground apps don't get throttled. mService.mUidObserver.onUidStateChanged( - UserHandle.getUid(USER_10, CALLING_UID_1), + UserHandle.getUid(USER_11, CALLING_UID_1), ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, ActivityManager.PROCESS_CAPABILITY_NONE); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); assertFalse(mManager.isRateLimitingActive()); @@ -2025,7 +2025,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(0, mManager.getRemainingCallCount()); assertTrue(mManager.isRateLimitingActive()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); mManager.setDynamicShortcuts(list(makeShortcut("s"))); @@ -2035,7 +2035,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(0, mManager.getRemainingCallCount()); assertTrue(mManager.isRateLimitingActive()); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); mManager.setDynamicShortcuts(list(makeShortcut("s"))); @@ -2045,7 +2045,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(0, mManager.getRemainingCallCount()); assertTrue(mManager.isRateLimitingActive()); }); - runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_4, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); mManager.setDynamicShortcuts(list(makeShortcut("s"))); @@ -2065,7 +2065,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(0, mManager.getRemainingCallCount()); assertTrue(mManager.isRateLimitingActive()); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertEquals(3, mManager.getRemainingCallCount()); mManager.setDynamicShortcuts(list(makeShortcut("s"))); @@ -2088,95 +2088,95 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { // First, all packages have less than 3 (== initial value) remaining calls. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_4, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); // Simulate a call from sys UI. mCallerPermissions.add(permission.RESET_SHORTCUT_MANAGER_THROTTLING); - mManager.onApplicationActive(CALLING_PACKAGE_1, USER_0); + mManager.onApplicationActive(CALLING_PACKAGE_1, USER_10); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_4, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - mManager.onApplicationActive(CALLING_PACKAGE_3, USER_0); + mManager.onApplicationActive(CALLING_PACKAGE_3, USER_10); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_4, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - mManager.onApplicationActive(CALLING_PACKAGE_1, USER_10); + mManager.onApplicationActive(CALLING_PACKAGE_1, USER_11); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_3, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_4, USER_10, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); } public void testReportShortcutUsed() { - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { reset(mMockUsageStatsManagerInternal); // Report with an nonexistent shortcut. @@ -2192,9 +2192,9 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { mManager.reportShortcutUsed("s2"); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( - eq(CALLING_PACKAGE_1), eq("s2"), eq(USER_10)); + eq(CALLING_PACKAGE_1), eq("s2"), eq(USER_11)); }); - runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_11, () -> { // Try with a different package. reset(mMockUsageStatsManagerInternal); @@ -2211,7 +2211,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { mManager.reportShortcutUsed("s3"); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( - eq(CALLING_PACKAGE_2), eq("s3"), eq(USER_10)); + eq(CALLING_PACKAGE_2), eq("s3"), eq(USER_11)); }); } @@ -2333,7 +2333,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { final Icon bmp64x64 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.black_64x64)); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcutWithIcon("res32x32", res32x32), makeShortcutWithIcon("res64x64", res64x64), @@ -2342,9 +2342,9 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { }); // We can't predict the compressed bitmap sizes, so get the real sizes here. - final long bitmapTotal = - new File(getBitmapAbsPath(USER_0, CALLING_PACKAGE_2, "bmp32x32")).length() + - new File(getBitmapAbsPath(USER_0, CALLING_PACKAGE_2, "bmp64x64")).length(); + final long bitmapTotal = new File(getBitmapAbsPath( + USER_10, CALLING_PACKAGE_2, "bmp32x32")).length() + new File( + getBitmapAbsPath(USER_10, CALLING_PACKAGE_2, "bmp64x64")).length(); // Read the expected output and inject the bitmap size. final String expected = readTestAsset("shortcut/dumpsys_expected.txt") @@ -2358,15 +2358,15 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { * can still be read. */ public void testLoadLegacySavedFile() throws Exception { - final File path = mService.getUserFile(USER_0).getBaseFile(); + final File path = mService.getUserFile(USER_10).getBaseFile(); path.getParentFile().mkdirs(); try (Writer w = new FileWriter(path)) { w.write(readTestAsset("shortcut/shortcut_legacy_file.xml")); }; initService(); - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("manifest-shortcut-storage") .forShortcutWithId("manifest-shortcut-storage", si -> { @@ -2381,58 +2381,58 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { mRunningUsers.clear(); mUnlockedUsers.clear(); - assertFalse(mService.isUserUnlockedL(USER_0)); assertFalse(mService.isUserUnlockedL(USER_10)); + assertFalse(mService.isUserUnlockedL(USER_11)); // Start user 0, still locked. - mRunningUsers.put(USER_0, true); - assertFalse(mService.isUserUnlockedL(USER_0)); + mRunningUsers.put(USER_10, true); assertFalse(mService.isUserUnlockedL(USER_10)); + assertFalse(mService.isUserUnlockedL(USER_11)); // Unlock user. - mUnlockedUsers.put(USER_0, true); - assertTrue(mService.isUserUnlockedL(USER_0)); - assertFalse(mService.isUserUnlockedL(USER_10)); + mUnlockedUsers.put(USER_10, true); + assertTrue(mService.isUserUnlockedL(USER_10)); + assertFalse(mService.isUserUnlockedL(USER_11)); // Clear again. mRunningUsers.clear(); mUnlockedUsers.clear(); // Directly call the lifecycle event. Now also locked. - mService.handleUnlockUser(USER_0); - assertTrue(mService.isUserUnlockedL(USER_0)); - assertFalse(mService.isUserUnlockedL(USER_10)); + mService.handleUnlockUser(USER_10); + assertTrue(mService.isUserUnlockedL(USER_10)); + assertFalse(mService.isUserUnlockedL(USER_11)); // Directly call the stop lifecycle event. Goes back to the initial state. - mService.handleStopUser(USER_0); - assertFalse(mService.isUserUnlockedL(USER_0)); + mService.handleStopUser(USER_10); assertFalse(mService.isUserUnlockedL(USER_10)); + assertFalse(mService.isUserUnlockedL(USER_11)); } public void testEphemeralApp() { - mRunningUsers.put(USER_10, true); // this test needs user 10. + mRunningUsers.put(USER_11, true); // this test needs user 10. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(mManager.getDynamicShortcuts()).isEmpty(); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertWith(mManager.getDynamicShortcuts()).isEmpty(); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertWith(mManager.getDynamicShortcuts()).isEmpty(); }); // Make package 1 ephemeral. - mEphemeralPackages.add(UserPackage.of(USER_0, CALLING_PACKAGE_1)); + mEphemeralPackages.add(UserPackage.of(USER_10, CALLING_PACKAGE_1)); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertExpectException(IllegalStateException.class, "Ephemeral apps", () -> { mManager.getDynamicShortcuts(); }); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertWith(mManager.getDynamicShortcuts()).isEmpty(); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertWith(mManager.getDynamicShortcuts()).isEmpty(); }); } diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java index 43e527c3d706..aad06c6d6c0e 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java @@ -70,14 +70,14 @@ public class ShortcutManagerTest3 extends BaseShortcutManagerTest { + ConfigConstants.KEY_MAX_SHORTCUTS + "=99999999" ); - setCaller(CALLING_PACKAGE, USER_0); + setCaller(CALLING_PACKAGE, USER_10); } private void publishManifestShortcuts(ComponentName activity, int resId) { addManifestShortcutResource(activity, resId); updatePackageVersion(CALLING_PACKAGE, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE, USER_0)); + genPackageAddIntent(CALLING_PACKAGE, USER_10)); } public void testSetDynamicShortcuts_noManifestShortcuts() { @@ -299,8 +299,8 @@ public class ShortcutManagerTest3 extends BaseShortcutManagerTest { .isEmpty(); - runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE, list("s2", "s4", "x2"), HANDLE_USER_0); + runWithCaller(LAUNCHER_1, USER_10, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE, list("s2", "s4", "x2"), HANDLE_USER_10); }); // Still same order. assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1) @@ -408,9 +408,9 @@ public class ShortcutManagerTest3 extends BaseShortcutManagerTest { assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime) .isEmpty(); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts( - CALLING_PACKAGE, list("s2", "s4", "x1", "x2"), HANDLE_USER_0); + CALLING_PACKAGE, list("s2", "s4", "x1", "x2"), HANDLE_USER_10); }); // Still same order. @@ -483,8 +483,8 @@ public class ShortcutManagerTest3 extends BaseShortcutManagerTest { assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime) .haveIds("s2", "s4"); - runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE, list("s2", "s4", "x2"), HANDLE_USER_0); + runWithCaller(LAUNCHER_1, USER_10, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE, list("s2", "s4", "x2"), HANDLE_USER_10); }); // Still same order. assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1) @@ -518,7 +518,7 @@ public class ShortcutManagerTest3 extends BaseShortcutManagerTest { R.xml.shortcut_share_targets); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); // There are two valid <share-target> definitions in the test manifest with two different // categories: {"com.test.category.CATEGORY1", "com.test.category.CATEGORY2"} and diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java index 11a2a8a39a46..42c1767023f1 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java @@ -116,7 +116,7 @@ public class ShortcutManagerTest4 extends BaseShortcutManagerTest { final Intent intent = new Intent(Intent.ACTION_MAIN) .putExtras(sIntentExtras); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.setDynamicShortcuts(list( makeShortcutWithExtras("s1", intent, sShortcutExtras), makeShortcut("s{\u0000}{\u0001}{\uD800\uDC00}x[\uD801][\uDC01]") @@ -125,9 +125,9 @@ public class ShortcutManagerTest4 extends BaseShortcutManagerTest { // Make sure save & load works fine. (i.e. shouldn't crash even with invalid characters.) initService(); - mService.handleUnlockUser(USER_0); + mService.handleUnlockUser(USER_10); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertWith(getCallerShortcuts()) .haveIds("s1", "s{\u0000}{\u0001}{\uD800\uDC00}x[?][?]") .forShortcutWithId("s1", si -> { diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java index 6c10bfd274da..7f7a4ae13245 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java @@ -28,59 +28,59 @@ import androidx.test.filters.SmallTest; public class ShortcutManagerTest6 extends BaseShortcutManagerTest { public void testHasShortcutHostPermissionInner_with3pLauncher_complicated() { // Set the default launcher. - prepareGetRoleHoldersAsUser(CALLING_PACKAGE_2, USER_0); - assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0)); - assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_0)); - assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0)); - assertTrue(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_0)); + prepareGetRoleHoldersAsUser(CALLING_PACKAGE_2, USER_10); + assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_10)); + assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_10)); + assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_10)); + assertTrue(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_10)); // Last known launcher should be set. assertEquals(CALLING_PACKAGE_2, - mService.getUserShortcutsLocked(USER_0).getCachedLauncher()); + mService.getUserShortcutsLocked(USER_10).getCachedLauncher()); // Now the default launcher has changed. - prepareGetRoleHoldersAsUser(CALLING_PACKAGE_1, USER_0); + prepareGetRoleHoldersAsUser(CALLING_PACKAGE_1, USER_10); - assertTrue(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0)); + assertTrue(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_10)); // Last known launcher should be set. assertEquals(CALLING_PACKAGE_1, - mService.getUserShortcutsLocked(USER_0).getCachedLauncher()); + mService.getUserShortcutsLocked(USER_10).getCachedLauncher()); // Change the default launcher again. prepareGetRoleHoldersAsUser( - getSystemLauncher().activityInfo.getComponentName().getPackageName(), USER_0); + getSystemLauncher().activityInfo.getComponentName().getPackageName(), USER_10); - assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0)); - assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0)); + assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_10)); + assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_10)); // Last known launcher should be set to default. assertEquals(PACKAGE_SYSTEM_LAUNCHER, - mService.getUserShortcutsLocked(USER_0).getCachedLauncher()); + mService.getUserShortcutsLocked(USER_10).getCachedLauncher()); } public void testHasShortcutHostPermissionInner_multiUser() { - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - prepareGetRoleHoldersAsUser(PACKAGE_FALLBACK_LAUNCHER, USER_0); - prepareGetRoleHoldersAsUser(CALLING_PACKAGE_2, USER_10); + prepareGetRoleHoldersAsUser(PACKAGE_FALLBACK_LAUNCHER, USER_10); + prepareGetRoleHoldersAsUser(CALLING_PACKAGE_2, USER_11); - assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0)); - assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_0)); - assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0)); - assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_0)); + assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_10)); + assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_10)); + assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_10)); + assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_10)); // Last known launcher should be set. assertEquals(PACKAGE_FALLBACK_LAUNCHER, - mService.getUserShortcutsLocked(USER_0).getCachedLauncher()); + mService.getUserShortcutsLocked(USER_10).getCachedLauncher()); - assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_10)); - assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_10)); - assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_10)); - assertTrue(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_10)); + assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_11)); + assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_11)); + assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_11)); + assertTrue(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_11)); // Last known launcher should be set. assertEquals(CALLING_PACKAGE_2, - mService.getUserShortcutsLocked(USER_10).getCachedLauncher()); + mService.getUserShortcutsLocked(USER_11).getCachedLauncher()); } } diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java index 161b18c80e77..86bde837bfe1 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java @@ -131,20 +131,20 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { public void testResetThrottling() throws Exception { prepareCrossProfileDataSet(); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); mInjectedCallingUid = Process.SHELL_UID; - assertSuccess(callShellCommand("reset-throttling")); + assertSuccess(callShellCommand("reset-throttling", "--user", "10")); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); } @@ -152,27 +152,27 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { public void testResetThrottling_user_not_running() throws Exception { prepareCrossProfileDataSet(); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); mInjectedCallingUid = Process.SHELL_UID; - mRunningUsers.put(USER_10, false); + mRunningUsers.put(USER_11, false); assertTrue(resultContains( - callShellCommand("reset-throttling", "--user", "10"), - "User (with userId=10) is not running or locked")); + callShellCommand("reset-throttling", "--user", "11"), + "User (with userId=11) is not running or locked")); - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); } @@ -180,23 +180,23 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { public void testResetThrottling_user_running() throws Exception { prepareCrossProfileDataSet(); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); - mRunningUsers.put(USER_10, true); - mUnlockedUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); + mUnlockedUsers.put(USER_11, true); mInjectedCallingUid = Process.SHELL_UID; - assertSuccess(callShellCommand("reset-throttling", "--user", "10")); + assertSuccess(callShellCommand("reset-throttling", "--user", "11")); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); } @@ -204,81 +204,81 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { public void testResetAllThrottling() throws Exception { prepareCrossProfileDataSet(); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.getRemainingCallCount() < 3); }); mInjectedCallingUid = Process.SHELL_UID; assertSuccess(callShellCommand("reset-all-throttling")); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertEquals(3, mManager.getRemainingCallCount()); }); } // This command is deprecated. Will remove the test later. public void testLauncherCommands() throws Exception { - prepareGetRoleHoldersAsUser(getSystemLauncher().activityInfo.packageName, USER_0); + prepareGetRoleHoldersAsUser(getSystemLauncher().activityInfo.packageName, USER_10); prepareGetHomeActivitiesAsUser( /* preferred */ getSystemLauncher().activityInfo.getComponentName(), list(getSystemLauncher(), getFallbackLauncher()), - USER_0); + USER_10); - prepareGetRoleHoldersAsUser(CALLING_PACKAGE_2, USER_10); + prepareGetRoleHoldersAsUser(CALLING_PACKAGE_2, USER_11); prepareGetHomeActivitiesAsUser( /* preferred */ cn(CALLING_PACKAGE_2, "name"), list(getSystemLauncher(), getFallbackLauncher(), ri(CALLING_PACKAGE_1, "name", false, 0), ri(CALLING_PACKAGE_2, "name", false, 0) ), - USER_10); + USER_11); // First, test "get". - mRunningUsers.put(USER_10, true); - mUnlockedUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); + mUnlockedUsers.put(USER_11, true); mInjectedCallingUid = Process.SHELL_UID; assertContains( - assertSuccess(callShellCommand("get-default-launcher")), + assertSuccess(callShellCommand("get-default-launcher", "--user", "10")), "Launcher: ComponentInfo{com.android.systemlauncher/systemlauncher_name}"); assertContains( - assertSuccess(callShellCommand("get-default-launcher", "--user", "10")), + assertSuccess(callShellCommand("get-default-launcher", "--user", "11")), "Launcher: ComponentInfo{com.android.test.2/name}"); // Change user-0's launcher. - prepareGetRoleHoldersAsUser(CALLING_PACKAGE_1, USER_0); + prepareGetRoleHoldersAsUser(CALLING_PACKAGE_1, USER_10); prepareGetHomeActivitiesAsUser( /* preferred */ cn(CALLING_PACKAGE_1, "name"), list(ri(CALLING_PACKAGE_1, "name", false, 0)), - USER_0); + USER_10); assertContains( - assertSuccess(callShellCommand("get-default-launcher")), + assertSuccess(callShellCommand("get-default-launcher", "--user", "10")), "Launcher: ComponentInfo{com.android.test.1/name}"); } public void testUnloadUser() throws Exception { prepareCrossProfileDataSet(); - assertNotNull(mService.getShortcutsForTest().get(USER_10)); + assertNotNull(mService.getShortcutsForTest().get(USER_11)); - mRunningUsers.put(USER_10, true); - mUnlockedUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); + mUnlockedUsers.put(USER_11, true); mInjectedCallingUid = Process.SHELL_UID; - assertSuccess(callShellCommand("unload-user", "--user", "10")); + assertSuccess(callShellCommand("unload-user", "--user", "11")); - assertNull(mService.getShortcutsForTest().get(USER_10)); + assertNull(mService.getShortcutsForTest().get(USER_11)); } public void testClearShortcuts() throws Exception { - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); // Add two manifests and two dynamics. addManifestShortcutResource( @@ -286,17 +286,17 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_11)); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.addDynamicShortcuts(list( makeShortcut("s1"), makeShortcut("s2")))); }); - runWithCaller(LAUNCHER_1, USER_10, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "s2"), HANDLE_USER_10); + runWithCaller(LAUNCHER_1, USER_11, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "s2"), HANDLE_USER_11); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2", "s1", "s2") .areAllEnabled() @@ -307,14 +307,14 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { // First, call for a different package. - mRunningUsers.put(USER_10, true); - mUnlockedUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); + mUnlockedUsers.put(USER_11, true); mInjectedCallingUid = Process.SHELL_UID; - assertSuccess(callShellCommand("clear-shortcuts", "--user", "10", CALLING_PACKAGE_2)); + assertSuccess(callShellCommand("clear-shortcuts", "--user", "11", CALLING_PACKAGE_2)); // Shouldn't be cleared yet. - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2", "s1", "s2") .areAllEnabled() @@ -324,10 +324,10 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { }); mInjectedCallingUid = Process.SHELL_UID; - assertSuccess(callShellCommand("clear-shortcuts", "--user", "10", CALLING_PACKAGE_1)); + assertSuccess(callShellCommand("clear-shortcuts", "--user", "11", CALLING_PACKAGE_1)); // Only manifest shortcuts will remain, and are no longer pinned. - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2") .areAllEnabled() @@ -337,7 +337,7 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { public void testGetShortcuts() throws Exception { - mRunningUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); // Add two manifests and two dynamics. addManifestShortcutResource( @@ -345,20 +345,20 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); mService.mPackageMonitor.onReceive(getTestContext(), - genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); + genPackageAddIntent(CALLING_PACKAGE_1, USER_11)); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.addDynamicShortcuts(list( makeLongLivedShortcut("s1"), makeShortcut("s2")))); }); - runWithCaller(LAUNCHER_1, USER_10, () -> { + runWithCaller(LAUNCHER_1, USER_11, () -> { mInjectCheckAccessShortcutsPermission = true; - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_10, + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_11, CACHE_OWNER); - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "s2"), HANDLE_USER_10); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "s2"), HANDLE_USER_11); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1", "ms2", "s1", "s2") .areAllEnabled() @@ -368,33 +368,33 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { }); - mRunningUsers.put(USER_10, true); - mUnlockedUsers.put(USER_10, true); + mRunningUsers.put(USER_11, true); + mUnlockedUsers.put(USER_11, true); mInjectedCallingUid = Process.SHELL_UID; - assertHaveIds(callShellCommand("get-shortcuts", "--user", "10", "--flags", + assertHaveIds(callShellCommand("get-shortcuts", "--user", "11", "--flags", Integer.toString(ShortcutManager.FLAG_MATCH_CACHED), CALLING_PACKAGE_1), "s1"); - assertHaveIds(callShellCommand("get-shortcuts", "--user", "10", "--flags", + assertHaveIds(callShellCommand("get-shortcuts", "--user", "11", "--flags", Integer.toString(ShortcutManager.FLAG_MATCH_DYNAMIC), CALLING_PACKAGE_1), "s1", "s2"); - assertHaveIds(callShellCommand("get-shortcuts", "--user", "10", "--flags", + assertHaveIds(callShellCommand("get-shortcuts", "--user", "11", "--flags", Integer.toString(ShortcutManager.FLAG_MATCH_MANIFEST), CALLING_PACKAGE_1), "ms1", "ms2"); - assertHaveIds(callShellCommand("get-shortcuts", "--user", "10", "--flags", + assertHaveIds(callShellCommand("get-shortcuts", "--user", "11", "--flags", Integer.toString(ShortcutManager.FLAG_MATCH_PINNED), CALLING_PACKAGE_1), "ms2", "s2"); - assertHaveIds(callShellCommand("get-shortcuts", "--user", "10", "--flags", + assertHaveIds(callShellCommand("get-shortcuts", "--user", "11", "--flags", Integer.toString(ShortcutManager.FLAG_MATCH_DYNAMIC | ShortcutManager.FLAG_MATCH_PINNED), CALLING_PACKAGE_1), "ms2", "s1", "s2"); - assertHaveIds(callShellCommand("get-shortcuts", "--user", "10", "--flags", + assertHaveIds(callShellCommand("get-shortcuts", "--user", "11", "--flags", Integer.toString(ShortcutManager.FLAG_MATCH_MANIFEST | ShortcutManager.FLAG_MATCH_CACHED), CALLING_PACKAGE_1), "ms1", "ms2", "s1"); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java index a85c7227b954..9b02a3abf14b 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java @@ -85,32 +85,32 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { } public void testGetParentOrSelfUserId() { - assertEquals(USER_0, mService.getParentOrSelfUserId(USER_0)); assertEquals(USER_10, mService.getParentOrSelfUserId(USER_10)); assertEquals(USER_11, mService.getParentOrSelfUserId(USER_11)); - assertEquals(USER_0, mService.getParentOrSelfUserId(USER_P0)); + assertEquals(USER_12, mService.getParentOrSelfUserId(USER_12)); + assertEquals(USER_10, mService.getParentOrSelfUserId(USER_P0)); } public void testIsRequestPinShortcutSupported() { - setDefaultLauncher(USER_0, LAUNCHER_1); - setDefaultLauncher(USER_10, LAUNCHER_2); + setDefaultLauncher(USER_10, LAUNCHER_1); + setDefaultLauncher(USER_11, LAUNCHER_2); Pair<ComponentName, Integer> actual; // User 0 - actual = mProcessor.getRequestPinConfirmationActivity(USER_0, + actual = mProcessor.getRequestPinConfirmationActivity(USER_10, PinItemRequest.REQUEST_TYPE_SHORTCUT); assertEquals(LAUNCHER_1, actual.first.getPackageName()); assertEquals(PIN_CONFIRM_ACTIVITY_CLASS, actual.first.getClassName()); - assertEquals(USER_0, (int) actual.second); + assertEquals(USER_10, (int) actual.second); // User 10 - actual = mProcessor.getRequestPinConfirmationActivity(USER_10, + actual = mProcessor.getRequestPinConfirmationActivity(USER_11, PinItemRequest.REQUEST_TYPE_SHORTCUT); assertEquals(LAUNCHER_2, actual.first.getPackageName()); assertEquals(PIN_CONFIRM_ACTIVITY_CLASS, actual.first.getClassName()); - assertEquals(USER_10, (int) actual.second); + assertEquals(USER_11, (int) actual.second); // User P0 -> managed profile, return user-0's launcher. actual = mProcessor.getRequestPinConfirmationActivity(USER_P0, @@ -118,16 +118,16 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { assertEquals(LAUNCHER_1, actual.first.getPackageName()); assertEquals(PIN_CONFIRM_ACTIVITY_CLASS, actual.first.getClassName()); - assertEquals(USER_0, (int) actual.second); + assertEquals(USER_10, (int) actual.second); // Check from the public API. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertTrue(mManager.isRequestPinShortcutSupported()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertTrue(mManager.isRequestPinShortcutSupported()); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.isRequestPinShortcutSupported()); }); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { @@ -140,27 +140,27 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { ? null : new ComponentName(packageName, PIN_CONFIRM_ACTIVITY_CLASS); // User 10 -- still has confirm activity. - actual = mProcessor.getRequestPinConfirmationActivity(USER_10, + actual = mProcessor.getRequestPinConfirmationActivity(USER_11, PinItemRequest.REQUEST_TYPE_SHORTCUT); assertEquals(LAUNCHER_2, actual.first.getPackageName()); assertEquals(PIN_CONFIRM_ACTIVITY_CLASS, actual.first.getClassName()); - assertEquals(USER_10, (int) actual.second); + assertEquals(USER_11, (int) actual.second); // But user-0 and user p0 no longer has a confirmation activity. - assertNull(mProcessor.getRequestPinConfirmationActivity(USER_0, + assertNull(mProcessor.getRequestPinConfirmationActivity(USER_10, PinItemRequest.REQUEST_TYPE_SHORTCUT)); assertNull(mProcessor.getRequestPinConfirmationActivity(USER_P0, PinItemRequest.REQUEST_TYPE_SHORTCUT)); // Check from the public API. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { assertFalse(mManager.isRequestPinShortcutSupported()); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { assertFalse(mManager.isRequestPinShortcutSupported()); }); - runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_11, () -> { assertTrue(mManager.isRequestPinShortcutSupported()); }); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { @@ -170,13 +170,13 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { public void testRequestPinShortcut_notSupported() { // User-0's launcher has no confirmation activity. - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); mPinConfirmActivityFetcher = (packageName, userId) -> !LAUNCHER_2.equals(packageName) ? null : new ComponentName(packageName, PIN_CONFIRM_ACTIVITY_CLASS); - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { ShortcutInfo s1 = makeShortcut("s1"); assertFalse(mManager.requestPinShortcut(s1, @@ -188,7 +188,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { .sendIntentSender(any(IntentSender.class)); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { + runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { ShortcutInfo s1 = makeShortcut("s1"); assertFalse(mManager.requestPinShortcut(s1, @@ -223,7 +223,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { } public void testNotForeground() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { makeCallerBackground(); @@ -252,8 +252,8 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { * - Shortcut doesn't pre-exist. */ private void checkRequestPinShortcut(@Nullable IntentSender resultIntent) { - setDefaultLauncher(USER_0, LAUNCHER_1); - setDefaultLauncher(USER_10, LAUNCHER_2); + setDefaultLauncher(USER_10, LAUNCHER_1); + setDefaultLauncher(USER_11, LAUNCHER_2); final Icon res32x32 = Icon.createWithResource(getTestContext(), R.drawable.black_32x32); @@ -276,11 +276,11 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { .isEmpty(); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Check the intent passed to startActivityAsUser(). final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage); @@ -337,8 +337,8 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { } public void testRequestPinShortcut_explicitTargetActivity() { - setDefaultLauncher(USER_0, LAUNCHER_1); - setDefaultLauncher(USER_10, LAUNCHER_2); + setDefaultLauncher(USER_10, LAUNCHER_1); + setDefaultLauncher(USER_11, LAUNCHER_2); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { ShortcutInfo s1 = makeShortcutWithActivity("s1", @@ -353,11 +353,11 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { .isEmpty(); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Check the intent passed to startActivityAsUser(). final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage); @@ -393,7 +393,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { } public void testRequestPinShortcut_wrongTargetActivity() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { // Create dynamic shortcut @@ -411,8 +411,8 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { } public void testRequestPinShortcut_noTargetActivity_noMainActivity() { - setDefaultLauncher(USER_0, LAUNCHER_1); - setDefaultLauncher(USER_10, LAUNCHER_2); + setDefaultLauncher(USER_10, LAUNCHER_1); + setDefaultLauncher(USER_11, LAUNCHER_2); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { /// Create a shortcut with no target activity. @@ -435,11 +435,11 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { .isEmpty(); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Check the intent passed to startActivityAsUser(). final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage); @@ -476,7 +476,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { } public void testRequestPinShortcut_dynamicExists() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); final Icon res32x32 = Icon.createWithResource(getTestContext(), R.drawable.black_32x32); @@ -497,11 +497,11 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { .areAllNotPinned(); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Check the intent passed to startActivityAsUser(). final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage); @@ -534,7 +534,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { } public void testRequestPinShortcut_manifestExists() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { publishManifestShortcutsAsCaller(R.xml.shortcut_1); @@ -552,11 +552,11 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { .areAllNotPinned(); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Check the intent passed to startActivityAsUser(). final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage); @@ -591,7 +591,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { } public void testRequestPinShortcut_dynamicExists_alreadyPinned() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); final Icon res32x32 = Icon.createWithResource(getTestContext(), R.drawable.black_32x32); @@ -604,7 +604,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { assertTrue(mManager.setDynamicShortcuts(list(s))); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_P0); }); @@ -633,11 +633,11 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { }); // ... But the launcher will still receive the request. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Check the intent passed to startActivityAsUser(). final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage); @@ -676,13 +676,13 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { } public void testRequestPinShortcut_manifestExists_alreadyPinned() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { publishManifestShortcutsAsCaller(R.xml.shortcut_1); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1"), HANDLE_USER_P0); }); @@ -713,11 +713,11 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { }); // ... But the launcher will still receive the request. - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Check the intent passed to startActivityAsUser(). final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage); @@ -758,13 +758,13 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { } public void testRequestPinShortcut_wasDynamic_alreadyPinned() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1")))); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_P0); }); @@ -786,13 +786,13 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { } public void testRequestPinShortcut_wasDynamic_disabled_alreadyPinned() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1")))); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_P0); }); @@ -817,13 +817,13 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { } public void testRequestPinShortcut_wasManifest_alreadyPinned() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { publishManifestShortcutsAsCaller(R.xml.shortcut_1); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1"), HANDLE_USER_P0); }); @@ -855,11 +855,11 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1")))); }); - runWithCaller(LAUNCHER_2, USER_0, () -> { + runWithCaller(LAUNCHER_2, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_P0); }); - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { assertWith(getCallerShortcuts()) @@ -876,11 +876,11 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class)); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Check the intent passed to startActivityAsUser(). final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage); @@ -917,11 +917,11 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { publishManifestShortcutsAsCaller(R.xml.shortcut_1); }); - runWithCaller(LAUNCHER_2, USER_0, () -> { + runWithCaller(LAUNCHER_2, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1"), HANDLE_USER_P0); }); - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { assertWith(getCallerShortcuts()) @@ -939,11 +939,11 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class)); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Check the intent passed to startActivityAsUser(). final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage); @@ -980,13 +980,13 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { * the existing one. */ public void testRequestPinShortcut_launcherAlreadyHasPinned() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"), makeShortcut("s2")))); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_P0); }); @@ -997,11 +997,11 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class)); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Check the intent passed to startActivityAsUser(). final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage); @@ -1042,7 +1042,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { * When trying to pin an existing shortcut, the new fields shouldn't override existing fields. */ public void testRequestPinShortcut_dynamicExists_titleWontChange() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); final Icon res32x32 = Icon.createWithResource(getTestContext(), R.drawable.black_32x32); @@ -1063,11 +1063,11 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { .areAllNotPinned(); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Check the intent passed to startActivityAsUser(). final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage); @@ -1107,7 +1107,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { * When trying to pin an existing shortcut, the new fields shouldn't override existing fields. */ public void testRequestPinShortcut_manifestExists_titleWontChange() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { publishManifestShortcutsAsCaller(R.xml.shortcut_1); @@ -1125,11 +1125,11 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { .areAllNotPinned(); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Check the intent passed to startActivityAsUser(). final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage); @@ -1174,7 +1174,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { * has a partial shortcut, accept() should fail. */ public void testRequestPinShortcut_dynamicExists_thenRemoved_error() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { // Create dynamic shortcut @@ -1192,11 +1192,11 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { .isEmpty(); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Check the intent passed to startActivityAsUser(). final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage); @@ -1232,7 +1232,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { * has all the mandatory fields, we can go ahead and still publish it. */ public void testRequestPinShortcut_dynamicExists_thenRemoved_okay() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { // Create dynamic shortcut @@ -1250,11 +1250,11 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { .isEmpty(); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Check the intent passed to startActivityAsUser(). final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage); @@ -1288,7 +1288,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { * has a partial shortcut, accept() should fail. */ public void testRequestPinShortcut_manifestExists_thenRemoved_error() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { publishManifestShortcutsAsCaller(R.xml.shortcut_1); @@ -1304,11 +1304,11 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { .isEmpty(); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Check the intent passed to startActivityAsUser(). final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage); @@ -1345,7 +1345,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { * has all the mandatory fields, we can go ahead and still publish it. */ public void testRequestPinShortcut_manifestExists_thenRemoved_okay() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { publishManifestShortcutsAsCaller(R.xml.shortcut_1); @@ -1361,11 +1361,11 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { .isEmpty(); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Check the intent passed to startActivityAsUser(). final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage); @@ -1405,7 +1405,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { * has a partial shortcut, accept() should fail. */ public void testRequestPinShortcut_dynamicExists_thenDisabled_error() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { ShortcutInfo s1 = makeShortcut("s1"); @@ -1419,8 +1419,8 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { // Then, pin by another launcher and disable it. // We have to pin it here so that disable() won't remove it. - setDefaultLauncher(USER_0, LAUNCHER_2); - runWithCaller(LAUNCHER_2, USER_0, () -> { + setDefaultLauncher(USER_10, LAUNCHER_2); + runWithCaller(LAUNCHER_2, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_P0); }); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { @@ -1431,12 +1431,12 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { .areAllDisabled(); }); - setDefaultLauncher(USER_0, LAUNCHER_1); - runWithCaller(LAUNCHER_1, USER_0, () -> { + setDefaultLauncher(USER_10, LAUNCHER_1); + runWithCaller(LAUNCHER_1, USER_10, () -> { // Check the intent passed to startActivityAsUser(). final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage); @@ -1479,7 +1479,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { * has a partial shortcut, accept() should fail. */ public void testRequestPinShortcut_manifestExists_thenDisabled_error() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { publishManifestShortcutsAsCaller(R.xml.shortcut_1); @@ -1492,8 +1492,8 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { // Then, pin by another launcher and disable it. // We have to pin it here so that disable() won't remove it. - setDefaultLauncher(USER_0, LAUNCHER_2); - runWithCaller(LAUNCHER_2, USER_0, () -> { + setDefaultLauncher(USER_10, LAUNCHER_2); + runWithCaller(LAUNCHER_2, USER_10, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1"), HANDLE_USER_P0); }); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { @@ -1505,12 +1505,12 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { .areAllDisabled(); }); - setDefaultLauncher(USER_0, LAUNCHER_1); - runWithCaller(LAUNCHER_1, USER_0, () -> { + setDefaultLauncher(USER_10, LAUNCHER_1); + runWithCaller(LAUNCHER_1, USER_10, () -> { // Check the intent passed to startActivityAsUser(). final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage); @@ -1551,7 +1551,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { } public void testRequestPinShortcut_wrongLauncherCannotAccept() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { ShortcutInfo s1 = makeShortcut("s1"); @@ -1560,11 +1560,11 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { }); final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue()); // Verify that other launcher can't use this request - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Set some random caller UID. mInjectedCallingUid = 12345; @@ -1573,7 +1573,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { }); // The default launcher can still use this request - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { assertTrue(request.isValid()); assertTrue(request.accept()); }); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java index 2fca3d07149e..ee1bf38a6b24 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java @@ -91,7 +91,7 @@ public class ShortcutManagerTest9 extends BaseShortcutManagerTest { } public void testNotForeground() { - setDefaultLauncher(USER_0, LAUNCHER_1); + setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { makeCallerBackground(); @@ -108,8 +108,8 @@ public class ShortcutManagerTest9 extends BaseShortcutManagerTest { } private void checkRequestPinAppWidget(@Nullable PendingIntent resultIntent) { - setDefaultLauncher(USER_0, LAUNCHER_1); - setDefaultLauncher(USER_10, LAUNCHER_2); + setDefaultLauncher(USER_10, LAUNCHER_1); + setDefaultLauncher(USER_11, LAUNCHER_2); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { AppWidgetProviderInfo info = makeProviderInfo("c1"); @@ -120,11 +120,11 @@ public class ShortcutManagerTest9 extends BaseShortcutManagerTest { verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class)); }); - runWithCaller(LAUNCHER_1, USER_0, () -> { + runWithCaller(LAUNCHER_1, USER_10, () -> { // Check the intent passed to startActivityAsUser(). final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); - verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_10)); assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java index ffe38936bcc1..b1cad513ad83 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java @@ -516,6 +516,12 @@ public class DisplayWindowSettingsTests extends WindowTestsBase { // Verify that newly created displays are created with correct rotation settings assertFalse(dcDontIgnoreOrientation.getIgnoreOrientationRequest()); assertTrue(dcIgnoreOrientation.getIgnoreOrientationRequest()); + + // Verify that once ignore-orientation-request has been set, it can be turned off by + // applying default value, e.g. the same display switches from large size to small size. + settingsEntry2.mIgnoreOrientationRequest = null; + mDisplayWindowSettings.applyRotationSettingsToDisplayLocked(dcIgnoreOrientation); + assertFalse(dcIgnoreOrientation.getIgnoreOrientationRequest()); } @Test |