diff options
756 files changed, 17309 insertions, 12342 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 2d0560635201..96d6f32fc1df 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -307,6 +307,11 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } +cc_aconfig_library { + name: "android_security_flags_aconfig_c_lib", + aconfig_declarations: "android.security.flags-aconfig", +} + // UsageStats aconfig_declarations { name: "android.app.usage.flags-aconfig", diff --git a/DREAM_MANAGER_OWNERS b/DREAM_MANAGER_OWNERS deleted file mode 100644 index 48bde6024cba..000000000000 --- a/DREAM_MANAGER_OWNERS +++ /dev/null @@ -1 +0,0 @@ -brycelee@google.com diff --git a/apct-tests/perftests/OWNERS b/apct-tests/perftests/OWNERS index 8ff3f9bc6620..f4346b150ca2 100644 --- a/apct-tests/perftests/OWNERS +++ b/apct-tests/perftests/OWNERS @@ -8,4 +8,3 @@ philipcuadra@google.com shayba@google.com shombert@google.com timmurray@google.com -wessam@google.com diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/generate_java.py b/apct-tests/perftests/core/src/android/libcore/varhandles/generate_java.py index 01abdb6c4be1..cfcb1d2a02d4 100755 --- a/apct-tests/perftests/core/src/android/libcore/varhandles/generate_java.py +++ b/apct-tests/perftests/core/src/android/libcore/varhandles/generate_java.py @@ -21,7 +21,7 @@ Adapted to use CrystalBall from art/test/2239-varhandle-perf/util-src/generate_j To run use: python generate_java.py <destination_directory> And then to correct lint errors (from frameworks/base): -../../tools/repohooks/tools/google-java-format.py --fix --sort-imports --google-java-format-diff ../../external/google-java-format/scripts/google-java-format-diff.py +../../tools/repohooks/tools/google-java-format.py --fix --google-java-format-diff ../../external/google-java-format/scripts/google-java-format-diff.py """ diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 5adcd930e341..7eb9d0f3ea91 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -1335,7 +1335,8 @@ bool BootAnimation::preloadZip(Animation& animation) { if (path.string() == animation.parts[j].path.c_str()) { uint16_t method; // supports only stored png files - if (zip->getEntryInfo(entry, &method, nullptr, nullptr, nullptr, nullptr, nullptr)) { + if (zip->getEntryInfo(entry, &method, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr)) { if (method == ZipFileRO::kCompressStored) { FileMap* map = zip->createEntryFileMap(entry); if (map) { diff --git a/core/api/current.txt b/core/api/current.txt index c0bc6d96f7ef..a819b6e27152 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -9801,6 +9801,7 @@ package android.companion { method @NonNull public java.util.List<android.companion.AssociationInfo> getMyAssociations(); method @Deprecated public boolean hasNotificationAccess(android.content.ComponentName); method @FlaggedApi("android.companion.perm_sync_user_consent") public boolean isPermissionTransferUserConsented(int); + method @FlaggedApi("android.companion.unpair_associated_device") @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean removeBond(int); method public void requestNotificationAccess(android.content.ComponentName); method @FlaggedApi("android.companion.association_tag") public void setAssociationTag(int, @NonNull String); method @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void startObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException; diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 65628d32e583..fd9600c1f87f 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -16,7 +16,6 @@ package android.accessibilityservice; -import static android.accessibilityservice.AccessibilityServiceInfo.CAPABILITY_CAN_CONTROL_MAGNIFICATION; import static android.accessibilityservice.MagnificationConfig.MAGNIFICATION_MODE_FULLSCREEN; import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; @@ -70,8 +69,6 @@ import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.view.accessibility.AccessibilityWindowInfo; import android.view.inputmethod.EditorInfo; -import androidx.annotation.GuardedBy; - import com.android.internal.annotations.VisibleForTesting; import com.android.internal.inputmethod.CancellationGroup; import com.android.internal.inputmethod.IAccessibilityInputMethodSession; @@ -643,8 +640,6 @@ public abstract class AccessibilityService extends Service { /** The detected gesture information for different displays */ boolean onGesture(AccessibilityGestureEvent gestureInfo); boolean onKeyEvent(KeyEvent event); - /** Magnification SystemUI connection changed callbacks */ - void onMagnificationSystemUIConnectionChanged(boolean connected); /** Magnification changed callbacks for different displays */ void onMagnificationChanged(int displayId, @NonNull Region region, MagnificationConfig config); @@ -795,6 +790,7 @@ public abstract class AccessibilityService extends Service { public static final String KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP = "screenshot_timestamp"; + /** * Annotations for result codes of attaching accessibility overlays. * @@ -841,13 +837,6 @@ public abstract class AccessibilityService extends Service { private WindowManager mWindowManager; - @GuardedBy("mLock") - private boolean mServiceConnected; - @GuardedBy("mLock") - private boolean mMagnificationSystemUIConnected; - @GuardedBy("mLock") - private boolean mServiceConnectedNotified; - /** List of magnification controllers, mapping from displayId -> MagnificationController. */ private final SparseArray<MagnificationController> mMagnificationControllers = new SparseArray<>(0); @@ -897,14 +886,11 @@ public abstract class AccessibilityService extends Service { for (int i = 0; i < mMagnificationControllers.size(); i++) { mMagnificationControllers.valueAt(i).onServiceConnectedLocked(); } - checkIsMagnificationSystemUIConnectedAlready(); final AccessibilityServiceInfo info = getServiceInfo(); if (info != null) { updateInputMethod(info); mMotionEventSources = info.getMotionEventSources(); } - mServiceConnected = true; - mServiceConnectedNotified = false; } if (mSoftKeyboardController != null) { mSoftKeyboardController.onServiceConnected(); @@ -912,57 +898,7 @@ public abstract class AccessibilityService extends Service { // The client gets to handle service connection last, after we've set // up any state upon which their code may rely. - if (android.view.accessibility.Flags - .waitMagnificationSystemUiConnectionToNotifyServiceConnected()) { - notifyOnServiceConnectedIfReady(); - } else { - onServiceConnected(); - } - } - - private void notifyOnServiceConnectedIfReady() { - synchronized (mLock) { - if (mServiceConnectedNotified) { - return; - } - boolean canControlMagnification; - final AccessibilityServiceInfo info = getServiceInfo(); - if (info != null) { - int flagMask = CAPABILITY_CAN_CONTROL_MAGNIFICATION; - canControlMagnification = (info.getCapabilities() & flagMask) == flagMask; - } else { - canControlMagnification = false; - } - boolean ready = canControlMagnification - ? (mServiceConnected && mMagnificationSystemUIConnected) - : mServiceConnected; - if (ready) { - getMainExecutor().execute(() -> onServiceConnected()); - mServiceConnectedNotified = true; - } - } - } - - @GuardedBy("mLock") - private void checkIsMagnificationSystemUIConnectedAlready() { - if (!android.view.accessibility.Flags - .waitMagnificationSystemUiConnectionToNotifyServiceConnected()) { - return; - } - if (mMagnificationSystemUIConnected) { - return; - } - final IAccessibilityServiceConnection connection = - AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); - if (connection != null) { - try { - boolean connected = connection.isMagnificationSystemUIConnected(); - mMagnificationSystemUIConnected = connected; - } catch (RemoteException re) { - Log.w(LOG_TAG, "Failed to check magnification system ui connection", re); - re.rethrowFromSystemServer(); - } - } + onServiceConnected(); } private void updateInputMethod(AccessibilityServiceInfo info) { @@ -1424,22 +1360,6 @@ public abstract class AccessibilityService extends Service { } } - private void onMagnificationSystemUIConnectionChanged(boolean connected) { - if (!android.view.accessibility.Flags - .waitMagnificationSystemUiConnectionToNotifyServiceConnected()) { - return; - } - - synchronized (mLock) { - boolean changed = (mMagnificationSystemUIConnected != connected); - mMagnificationSystemUIConnected = connected; - - if (changed) { - notifyOnServiceConnectedIfReady(); - } - } - } - private void onMagnificationChanged(int displayId, @NonNull Region region, MagnificationConfig config) { MagnificationController controller; @@ -2903,11 +2823,6 @@ public abstract class AccessibilityService extends Service { } @Override - public void onMagnificationSystemUIConnectionChanged(boolean connected) { - AccessibilityService.this.onMagnificationSystemUIConnectionChanged(connected); - } - - @Override public void onMagnificationChanged(int displayId, @NonNull Region region, MagnificationConfig config) { AccessibilityService.this.onMagnificationChanged(displayId, region, config); @@ -3117,16 +3032,6 @@ public abstract class AccessibilityService extends Service { }); } - @Override - public void onMagnificationSystemUIConnectionChanged(boolean connected) { - mExecutor.execute(() -> { - if (mConnectionId != AccessibilityInteractionClient.NO_ID) { - mCallback.onMagnificationSystemUIConnectionChanged(connected); - } - return; - }); - } - /** Magnification changed callbacks for different displays */ public void onMagnificationChanged(int displayId, @NonNull Region region, MagnificationConfig config) { diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl index f1479ef79dd9..3bc61e560d8c 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl @@ -48,8 +48,6 @@ import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection; void onKeyEvent(in KeyEvent event, int sequence); - void onMagnificationSystemUIConnectionChanged(boolean connected); - void onMagnificationChanged(int displayId, in Region region, in MagnificationConfig config); void onMotionEvent(in MotionEvent event); diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl index 149e7194a43b..713d8e5dd12f 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl @@ -130,9 +130,6 @@ interface IAccessibilityServiceConnection { void setMagnificationCallbackEnabled(int displayId, boolean enabled); @RequiresNoPermission - boolean isMagnificationSystemUIConnected(); - - @RequiresNoPermission boolean setSoftKeyboardShowMode(int showMode); @RequiresNoPermission diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 8e99e46be6ac..97852528d014 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -1101,19 +1101,9 @@ public abstract class ActivityManagerInternal { public abstract ArraySet<String> getClientPackages(String servicePackageName); /** - * Retrieve an IUnsafeIntentStrictModeCallback matching the given callingUid. - * Returns null no match is found. - * @param callingPid The PID mapped with the callback. - * @return The callback, if it exists. + * Trigger an unsafe intent usage strict mode violation. */ - public abstract IUnsafeIntentStrictModeCallback getRegisteredStrictModeCallback( - int callingPid); - - /** - * Unregisters an IUnsafeIntentStrictModeCallback matching the given callingUid. - * @param callingPid The PID mapped with the callback. - */ - public abstract void unregisterStrictModeCallback(int callingPid); + public abstract void triggerUnsafeIntentStrictMode(int callingPid, int type, Intent intent); /** * Start a foreground service delegate. diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 76c1ed619510..b384326201fc 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -7500,7 +7500,7 @@ public final class ActivityThread extends ClientTransactionHandler + data.instrumentationName + ": " + e.toString(), e); } try { - timestampApplicationOnCreateNs = SystemClock.elapsedRealtimeNanos(); + timestampApplicationOnCreateNs = SystemClock.uptimeNanos(); mInstrumentation.callApplicationOnCreate(app); } catch (Exception e) { timestampApplicationOnCreateNs = 0; diff --git a/core/java/android/app/ApplicationStartInfo.java b/core/java/android/app/ApplicationStartInfo.java index 3715c6e633dc..f77c50a271be 100644 --- a/core/java/android/app/ApplicationStartInfo.java +++ b/core/java/android/app/ApplicationStartInfo.java @@ -416,11 +416,34 @@ public final class ApplicationStartInfo implements Parcelable { /** * @see #getStartIntent + * + * <p class="note"> Note: This method will clone the provided intent and ensure that the cloned + * intent doesn't contain any large objects like bitmaps in its extras by stripping it in the + * least aggressive acceptable way for the individual intent.</p> + * * @hide */ public void setIntent(Intent startIntent) { if (startIntent != null) { - mStartIntent = startIntent.maybeStripForHistory(); + if (startIntent.canStripForHistory()) { + // If maybeStripForHistory will return a lightened version, do that. + mStartIntent = startIntent.maybeStripForHistory(); + } else if (startIntent.getExtras() != null) { + // If maybeStripForHistory would not return a lightened version and extras is + // non-null then extras contains un-parcelled data. Use cloneFilter to strip data + // more aggressively. + mStartIntent = startIntent.cloneFilter(); + } else { + // Finally, if maybeStripForHistory would not return a lightened version and extras + // is null then do a regular clone so we don't leak the intent. + mStartIntent = new Intent(startIntent); + } + + // If the newly cloned intent has an original intent, clear that as we don't need it and + // can't guarantee it doesn't need to be stripped as well. + if (mStartIntent.getOriginalIntent() != null) { + mStartIntent.setOriginalIntent(null); + } } } diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 15b13dc97554..ffb920b907ab 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -757,6 +757,15 @@ interface IActivityManager { void addStartInfoTimestamp(int key, long timestampNs, int userId); /** + * Reports view related timestamps to be added to the calling apps most + * recent {@link ApplicationStartInfo}. + * + * @param renderThreadDrawStartTimeNs Clock monotonic time in nanoseconds of RenderThread draw start + * @param framePresentedTimeNs Clock monotonic time in nanoseconds of frame presented + */ + oneway void reportStartInfoViewTimestamps(long renderThreadDrawStartTimeNs, long framePresentedTimeNs); + + /** * Return a list of {@link ApplicationExitInfo} records. * * <p class="note"> Note: System stores these historical information in a ring buffer, older diff --git a/core/java/android/app/IUnsafeIntentStrictModeCallback.aidl b/core/java/android/app/IUnsafeIntentStrictModeCallback.aidl index e2b3bb194e02..69e99a3adde7 100644 --- a/core/java/android/app/IUnsafeIntentStrictModeCallback.aidl +++ b/core/java/android/app/IUnsafeIntentStrictModeCallback.aidl @@ -24,5 +24,5 @@ import android.content.Intent; */ oneway interface IUnsafeIntentStrictModeCallback { - void onImplicitIntentMatchedInternalComponent(in Intent intent); + void onUnsafeIntent(int type, in Intent intent); } diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS index 2e38c06a7479..0fad979e27cf 100644 --- a/core/java/android/app/OWNERS +++ b/core/java/android/app/OWNERS @@ -61,7 +61,7 @@ per-file ReceiverInfo* = file:/BROADCASTS_OWNERS per-file ComponentCaller.java = file:COMPONENT_CALLER_OWNERS # DreamManager -per-file DreamManager.java = file:/DREAM_MANAGER_OWNERS +per-file DreamManager.java = file:/core/java/android/service/dreams/OWNERS # GrammaticalInflectionManager per-file *GrammaticalInflection* = file:/services/core/java/com/android/server/grammaticalinflection/OWNERS diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index 273a79efb591..348d4d8fd809 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -1969,11 +1969,6 @@ public final class UiAutomation { } @Override - public void onMagnificationSystemUIConnectionChanged(boolean connected) { - /* do nothing */ - } - - @Override public void onMagnificationChanged(int displayId, @NonNull Region region, MagnificationConfig config) { /* do nothing */ diff --git a/core/java/android/app/pinner/OWNERS b/core/java/android/app/pinner/OWNERS index 3e3fa66ca916..fe5da9f7f0e3 100644 --- a/core/java/android/app/pinner/OWNERS +++ b/core/java/android/app/pinner/OWNERS @@ -5,6 +5,5 @@ kevinjeon@google.com philipcuadra@google.com shombert@google.com timmurray@google.com -wessam@google.com jdduke@google.com -shayba@google.com
\ No newline at end of file +shayba@google.com diff --git a/core/java/android/app/wearable/WearableSensingManager.java b/core/java/android/app/wearable/WearableSensingManager.java index 4b77c74bb174..b2b14ceab8c2 100644 --- a/core/java/android/app/wearable/WearableSensingManager.java +++ b/core/java/android/app/wearable/WearableSensingManager.java @@ -436,18 +436,18 @@ public class WearableSensingManager { /** * Requests the wearable to start hotword recognition. * - * <p>When this method is called, the system will attempt to provide a {@link - * android.service.wearable.WearableHotwordAudioConsumer} to {@link WearableSensingService}. - * After first-stage hotword is detected on a wearable, {@link WearableSensingService} should - * send the hotword audio to the {@link android.service.wearable.WearableHotwordAudioConsumer}, - * which will forward the data to the {@link android.service.voice.HotwordDetectionService} for + * <p>When this method is called, the system will attempt to provide a {@code + * Consumer<android.service.voice.HotwordAudioStream>} to {@link WearableSensingService}. After + * first-stage hotword is detected on a wearable, {@link WearableSensingService} should send the + * hotword audio to the {@code Consumer<android.service.voice.HotwordAudioStream>}, which will + * forward the data to the {@link android.service.voice.HotwordDetectionService} for * second-stage hotword validation. If hotword is detected there, the audio data will be * forwarded to the {@link android.service.voice.VoiceInteractionService}. * * <p>If the {@code targetVisComponentName} provided here is not null, when {@link - * WearableSensingService} sends hotword audio to the {@link - * android.service.wearable.WearableHotwordAudioConsumer}, the system will check whether the - * {@link android.service.voice.VoiceInteractionService} at that time is {@code + * WearableSensingService} sends hotword audio to the {@code + * Consumer<android.service.voice.HotwordAudioStream>}, the system will check whether the {@link + * android.service.voice.VoiceInteractionService} at that time is {@code * targetVisComponentName}. If not, the system will call {@link * WearableSensingService#onActiveHotwordAudioStopRequested()} and will not forward the audio * data to the current {@link android.service.voice.HotwordDetectionService} nor {@link @@ -457,8 +457,8 @@ public class WearableSensingManager { * android.service.voice.VoiceInteractionService} is the same as {@code targetVisComponentName}. * The check here is just a protection against race conditions. * - * <p>Calling this method again will send a new {@link - * android.service.wearable.WearableHotwordAudioConsumer} to {@link WearableSensingService}. For + * <p>Calling this method again will send a new {@code + * Consumer<android.service.voice.HotwordAudioStream>} to {@link WearableSensingService}. For * audio data sent to the new consumer, the system will perform the above check using the newly * provided {@code targetVisComponentName}. The {@link WearableSensingService} should not * continue to use the previous consumers after receiving a new one. diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java index 8fe5ae09a36d..b4ad1c8fff12 100644 --- a/core/java/android/companion/CompanionDeviceManager.java +++ b/core/java/android/companion/CompanionDeviceManager.java @@ -1149,6 +1149,32 @@ public final class CompanionDeviceManager { } } + /** + * Remove bonding between this device and an associated companion device. + * + * <p>This is an asynchronous call, it will return immediately. Register for {@link + * BluetoothDevice#ACTION_BOND_STATE_CHANGED} intents to be notified when the bond removal + * process completes, and its result. + * + * @param associationId an already-associated companion device to remove bond from + * @return false on immediate error, true if bond removal process will begin + */ + @FlaggedApi(Flags.FLAG_UNPAIR_ASSOCIATED_DEVICE) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + public boolean removeBond(int associationId) { + if (mService == null) { + Log.w(TAG, "CompanionDeviceManager service is not available."); + return false; + } + + try { + return mService.removeBond(associationId, mContext.getOpPackageName(), + mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + // TODO(b/315163162) Add @Deprecated keyword after 24Q2 cut. /** * Register to receive callbacks whenever the associated device comes in and out of range. diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl index 1b00f90e1fb3..de3ddec05d27 100644 --- a/core/java/android/companion/ICompanionDeviceManager.aidl +++ b/core/java/android/companion/ICompanionDeviceManager.aidl @@ -141,4 +141,7 @@ interface ICompanionDeviceManager { byte[] getBackupPayload(int userId); void applyRestoredPayload(in byte[] payload, int userId); + + @EnforcePermission("BLUETOOTH_CONNECT") + boolean removeBond(int associationId, in String packageName, int userId); } diff --git a/core/java/android/companion/flags.aconfig b/core/java/android/companion/flags.aconfig index 36d0e081af2a..fd4ba83b02e3 100644 --- a/core/java/android/companion/flags.aconfig +++ b/core/java/android/companion/flags.aconfig @@ -46,4 +46,11 @@ flag { namespace: "companion" description: "Enable ongoing perm sync" bug: "338469649" +} + +flag { + name: "unpair_associated_device" + namespace: "companion" + description: "Unpair with an associated bluetooth device" + bug: "322237619" }
\ No newline at end of file diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl index 30a1135d6be4..24f18cc257f8 100644 --- a/core/java/android/companion/virtual/IVirtualDevice.aidl +++ b/core/java/android/companion/virtual/IVirtualDevice.aidl @@ -281,5 +281,5 @@ interface IVirtualDevice { * Returns the id of the virtual camera with given config. */ @EnforcePermission("CREATE_VIRTUAL_DEVICE") - int getVirtualCameraId(in VirtualCameraConfig camera); + String getVirtualCameraId(in VirtualCameraConfig camera); } diff --git a/core/java/android/companion/virtual/VirtualDeviceInternal.java b/core/java/android/companion/virtual/VirtualDeviceInternal.java index 00d534370fa1..60448bad8e69 100644 --- a/core/java/android/companion/virtual/VirtualDeviceInternal.java +++ b/core/java/android/companion/virtual/VirtualDeviceInternal.java @@ -378,8 +378,8 @@ public class VirtualDeviceInternal { VirtualCamera createVirtualCamera(@NonNull VirtualCameraConfig config) { try { mVirtualDevice.registerVirtualCamera(config); - return new VirtualCamera(mVirtualDevice, - Integer.toString(mVirtualDevice.getVirtualCameraId(config)), config); + return new VirtualCamera(mVirtualDevice, mVirtualDevice.getVirtualCameraId(config), + config); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index bad73fc68f3a..4fcf6b66895c 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -7188,9 +7188,10 @@ public abstract class Context { * as the package remains in the foreground, or has any active manifest components (e.g. when * another app is accessing a content provider in the package). * <p> - * If you want to revoke the permissions right away, you could call {@code System.exit()}, but - * this could affect other apps that are accessing your app at the moment. For example, apps - * accessing a content provider in your app will all crash. + * If you want to revoke the permissions right away, you could call {@code System.exit()} in + * {@code Handler.postDelayed} with a delay to allow completion of async IPC, But + * {@code System.exit()} could affect other apps that are accessing your app at the moment. + * For example, apps accessing a content provider in your app will all crash. * <p> * Note that the settings UI shows a permission group as granted as long as at least one * permission in the group is granted. If you want the user to observe the revocation in the diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 1f6730b9e3f9..4b579e7db9f8 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -2628,15 +2628,6 @@ public class PackageParser { return Build.VERSION_CODES.CUR_DEVELOPMENT; } - // STOPSHIP: hack for the pre-release SDK - if (platformSdkCodenames.length == 0 - && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals( - targetCode)) { - Slog.w(TAG, "Package requires development platform " + targetCode - + ", returning current version " + Build.VERSION.SDK_INT); - return Build.VERSION.SDK_INT; - } - // Otherwise, we're looking at an incompatible pre-release SDK. if (platformSdkCodenames.length > 0) { outError[0] = "Requires development platform " + targetCode @@ -2708,15 +2699,6 @@ public class PackageParser { return Build.VERSION_CODES.CUR_DEVELOPMENT; } - // STOPSHIP: hack for the pre-release SDK - if (platformSdkCodenames.length == 0 - && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals( - minCode)) { - Slog.w(TAG, "Package requires min development platform " + minCode - + ", returning current version " + Build.VERSION.SDK_INT); - return Build.VERSION.SDK_INT; - } - // Otherwise, we're looking at an incompatible pre-release SDK. if (platformSdkCodenames.length > 0) { outError[0] = "Requires development platform " + minCode diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig index 5668c540f5bc..a9c07d174767 100644 --- a/core/java/android/content/pm/multiuser.aconfig +++ b/core/java/android/content/pm/multiuser.aconfig @@ -267,3 +267,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "use_private_space_icon_in_biometric_prompt" + namespace: "profile_experiences" + description: "Update the biometric prompt from generic Settings icon to private space icon" + bug: "333528540" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java index c7403c0ea98c..153dd9a93490 100644 --- a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java @@ -316,15 +316,6 @@ public class FrameworkParsingPackageUtils { return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT); } - // STOPSHIP: hack for the pre-release SDK - if (platformSdkCodenames.length == 0 - && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals( - minCode)) { - Slog.w(TAG, "Parsed package requires min development platform " + minCode - + ", returning current version " + Build.VERSION.SDK_INT); - return input.success(Build.VERSION.SDK_INT); - } - // Otherwise, we're looking at an incompatible pre-release SDK. if (platformSdkCodenames.length > 0) { return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, @@ -377,27 +368,19 @@ public class FrameworkParsingPackageUtils { return input.success(targetVers); } - // If it's a pre-release SDK and the codename matches this platform, it - // definitely targets this SDK. - if (matchTargetCode(platformSdkCodenames, targetCode)) { - return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT); - } - - // STOPSHIP: hack for the pre-release SDK - if (platformSdkCodenames.length == 0 - && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals( - targetCode)) { - Slog.w(TAG, "Parsed package requires development platform " + targetCode - + ", returning current version " + Build.VERSION.SDK_INT); - return input.success(Build.VERSION.SDK_INT); - } - try { if (allowUnknownCodenames && UnboundedSdkLevel.isAtMost(targetCode)) { return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT); } } catch (IllegalArgumentException e) { - return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, "Bad package SDK"); + // isAtMost() throws it when encountering an older SDK codename + return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, e.getMessage()); + } + + // If it's a pre-release SDK and the codename matches this platform, it + // definitely targets this SDK. + if (matchTargetCode(platformSdkCodenames, targetCode)) { + return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT); } // Otherwise, we're looking at an incompatible pre-release SDK. diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java index 481ff2e5d3b7..f0f691d339ee 100644 --- a/core/java/android/credentials/CredentialManager.java +++ b/core/java/android/credentials/CredentialManager.java @@ -470,8 +470,8 @@ public final class CredentialManager { * Returns {@code true} if the calling application provides a CredentialProviderService that is * enabled for the current user, or {@code false} otherwise. CredentialProviderServices are * enabled on a per-service basis so the individual component name of the service should be - * passed in here. <strong>Usage of this API is discouraged as it is not fully functional, and - * may throw a NullPointerException on certain devices and/or API versions.</strong> + * passed in here. <strong>Usage of this API is encouraged in API level 35 and above. It + * may throw a NullPointerException on certain devices running other API versions.</strong> * * @throws IllegalArgumentException if the componentName package does not match the calling * package name this call will throw an exception diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 3cc87ea9d359..6fffb822c9ca 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -1472,9 +1472,9 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri new Key<Integer>("android.flash.info.strengthDefaultLevel", int.class); /** - * <p>Maximum flash brightness level for manual flash control in SINGLE mode.</p> + * <p>Maximum flash brightness level for manual flash control in <code>SINGLE</code> mode.</p> * <p>Maximum flash brightness level in camera capture mode and - * {@link CaptureRequest#FLASH_MODE android.flash.mode} set to SINGLE. + * {@link CaptureRequest#FLASH_MODE android.flash.mode} set to <code>SINGLE</code>. * Value will be > 1 if the manual flash strength control feature is supported, * otherwise the value will be equal to 1. * Note that this level is just a number of supported levels (the granularity of control). @@ -1490,7 +1490,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri new Key<Integer>("android.flash.singleStrengthMaxLevel", int.class); /** - * <p>Default flash brightness level for manual flash control in SINGLE mode.</p> + * <p>Default flash brightness level for manual flash control in <code>SINGLE</code> mode.</p> * <p>If flash unit is available this will be greater than or equal to 1 and less * or equal to {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel}. * Note for devices that do not support the manual flash strength control @@ -1506,9 +1506,9 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri new Key<Integer>("android.flash.singleStrengthDefaultLevel", int.class); /** - * <p>Maximum flash brightness level for manual flash control in TORCH mode</p> + * <p>Maximum flash brightness level for manual flash control in <code>TORCH</code> mode</p> * <p>Maximum flash brightness level in camera capture mode and - * {@link CaptureRequest#FLASH_MODE android.flash.mode} set to TORCH. + * {@link CaptureRequest#FLASH_MODE android.flash.mode} set to <code>TORCH</code>. * Value will be > 1 if the manual flash strength control feature is supported, * otherwise the value will be equal to 1.</p> * <p>Note that this level is just a number of supported levels(the granularity of control). @@ -1530,7 +1530,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri new Key<Integer>("android.flash.torchStrengthMaxLevel", int.class); /** - * <p>Default flash brightness level for manual flash control in TORCH mode</p> + * <p>Default flash brightness level for manual flash control in <code>TORCH</code> mode</p> * <p>If flash unit is available this will be greater than or equal to 1 and less * or equal to {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel}. * Note for the devices that do not support the manual flash strength control feature, @@ -4152,10 +4152,16 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri /** * <p>Whether the RAW images output from this camera device are subject to * lens shading correction.</p> - * <p>If TRUE, all images produced by the camera device in the RAW image formats will - * have lens shading correction already applied to it. If FALSE, the images will - * not be adjusted for lens shading correction. - * See {@link CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_RAW android.request.maxNumOutputRaw} for a list of RAW image formats.</p> + * <p>If <code>true</code>, all images produced by the camera device in the <code>RAW</code> image formats will have + * at least some lens shading correction already applied to it. If <code>false</code>, the images will + * not be adjusted for lens shading correction. See {@link CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_RAW android.request.maxNumOutputRaw} for a + * list of RAW image formats.</p> + * <p>When <code>true</code>, the <code>lensShadingCorrectionMap</code> key may still have values greater than 1.0, + * and those will need to be applied to any captured RAW frames for them to match the shading + * correction of processed buffers such as <code>YUV</code> or <code>JPEG</code> images. This may occur, for + * example, when some basic fixed lens shading correction is applied by hardware to RAW data, + * and additional correction is done dynamically in the camera processing pipeline after + * demosaicing.</p> * <p>This key will be <code>null</code> for all devices do not report this information. * Devices with RAW capability will always report this information in this key.</p> * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index 938636f7e8e5..6968f279dbc0 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -2683,27 +2683,27 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> /** * <p>Flash strength level to be used when manual flash control is active.</p> * <p>Flash strength level to use in capture mode i.e. when the applications control - * flash with either SINGLE or TORCH mode.</p> + * flash with either <code>SINGLE</code> or <code>TORCH</code> mode.</p> * <p>Use {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel} and * {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel} to check whether the device supports * flash strength control or not. - * If the values of android.flash.info.singleStrengthMaxLevel and + * If the values of {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel} and * {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel} are greater than 1, * then the device supports manual flash strength control.</p> - * <p>If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> TORCH the value must be >= 1 + * <p>If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> <code>TORCH</code> the value must be >= 1 * and <= {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel}. * If the application doesn't set the key and * {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel} > 1, * then the flash will be fired at the default level set by HAL in * {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_DEFAULT_LEVEL android.flash.torchStrengthDefaultLevel}. - * If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> SINGLE, then the value must be >= 1 + * If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> <code>SINGLE</code>, then the value must be >= 1 * and <= {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel}. * If the application does not set this key and * {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel} > 1, * then the flash will be fired at the default level set by HAL * in {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL android.flash.singleStrengthDefaultLevel}. - * If {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is set to any of ON_AUTO_FLASH, ON_ALWAYS_FLASH, - * ON_AUTO_FLASH_REDEYE, ON_EXTERNAL_FLASH values, then the strengthLevel will be ignored.</p> + * If {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is set to any of <code>ON_AUTO_FLASH</code>, <code>ON_ALWAYS_FLASH</code>, + * <code>ON_AUTO_FLASH_REDEYE</code>, <code>ON_EXTERNAL_FLASH</code> values, then the strengthLevel will be ignored.</p> * <p><b>Range of valid values:</b><br> * <code>[1-{@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel}]</code> when the {@link CaptureRequest#FLASH_MODE android.flash.mode} is * set to TORCH; diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index 4406a419c317..ef83f9a1e4c6 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -2976,27 +2976,27 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { /** * <p>Flash strength level to be used when manual flash control is active.</p> * <p>Flash strength level to use in capture mode i.e. when the applications control - * flash with either SINGLE or TORCH mode.</p> + * flash with either <code>SINGLE</code> or <code>TORCH</code> mode.</p> * <p>Use {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel} and * {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel} to check whether the device supports * flash strength control or not. - * If the values of android.flash.info.singleStrengthMaxLevel and + * If the values of {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel} and * {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel} are greater than 1, * then the device supports manual flash strength control.</p> - * <p>If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> TORCH the value must be >= 1 + * <p>If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> <code>TORCH</code> the value must be >= 1 * and <= {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel}. * If the application doesn't set the key and * {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel} > 1, * then the flash will be fired at the default level set by HAL in * {@link CameraCharacteristics#FLASH_TORCH_STRENGTH_DEFAULT_LEVEL android.flash.torchStrengthDefaultLevel}. - * If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> SINGLE, then the value must be >= 1 + * If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> <code>SINGLE</code>, then the value must be >= 1 * and <= {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel}. * If the application does not set this key and * {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_MAX_LEVEL android.flash.singleStrengthMaxLevel} > 1, * then the flash will be fired at the default level set by HAL * in {@link CameraCharacteristics#FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL android.flash.singleStrengthDefaultLevel}. - * If {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is set to any of ON_AUTO_FLASH, ON_ALWAYS_FLASH, - * ON_AUTO_FLASH_REDEYE, ON_EXTERNAL_FLASH values, then the strengthLevel will be ignored.</p> + * If {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is set to any of <code>ON_AUTO_FLASH</code>, <code>ON_ALWAYS_FLASH</code>, + * <code>ON_AUTO_FLASH_REDEYE</code>, <code>ON_EXTERNAL_FLASH</code> values, then the strengthLevel will be ignored.</p> * <p><b>Range of valid values:</b><br> * <code>[1-{@link CameraCharacteristics#FLASH_TORCH_STRENGTH_MAX_LEVEL android.flash.torchStrengthMaxLevel}]</code> when the {@link CaptureRequest#FLASH_MODE android.flash.mode} is * set to TORCH; @@ -4846,6 +4846,9 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * correction map that needs to be applied to get shading * corrected images that match the camera device's output for * non-RAW formats.</p> + * <p>Therefore, whatever the value of lensShadingApplied is, the lens + * shading map should always be applied to RAW images if the goal is to + * match the shading appearance of processed (non-RAW) images.</p> * <p>For a complete shading correction map, the least shaded * section of the image will have a gain factor of 1; all * other sections will have gains above 1.</p> diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java index b41753413baf..7bdd53d00215 100644 --- a/core/java/android/os/BatteryConsumer.java +++ b/core/java/android/os/BatteryConsumer.java @@ -197,6 +197,9 @@ public abstract class BatteryConsumer { POWER_COMPONENT_MOBILE_RADIO, POWER_COMPONENT_WIFI, POWER_COMPONENT_BLUETOOTH, + POWER_COMPONENT_AUDIO, + POWER_COMPONENT_VIDEO, + POWER_COMPONENT_FLASHLIGHT, }; static final int COLUMN_INDEX_BATTERY_CONSUMER_TYPE = 0; diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 8aa2c35b49e4..30d2dec8b4c4 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -1238,6 +1238,18 @@ public class Build { public static final int VANILLA_ICE_CREAM = 35; } + /** + * The vendor API for 2024 Q2 + * + * <p>For Android 14-QPR3 and later, the vendor API level is completely decoupled from the SDK + * API level and the format has switched to YYYYMM (year and month) + * + * @see <a href="https://preview.source.android.com/docs/core/architecture/api-flags">Vendor API + * level</a> + * @hide + */ + public static final int VENDOR_API_2024_Q2 = 202404; + /** The type of build, like "user" or "eng". */ public static final String TYPE = getString("ro.build.type"); diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index 61b52c67dfe2..e6b1c07846f9 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -580,6 +580,8 @@ public final class FileUtils { ", copied:" + progress + ", read:" + (count - countToRead) + ", in pipe: " + countInPipe); + Os.close(pipes[0]); + Os.close(pipes[1]); throw new ErrnoException("splice, pipe --> fdOut", EIO); } else { progress += t; @@ -607,6 +609,8 @@ public final class FileUtils { listener.onProgress(progressSnapshot); }); } + Os.close(pipes[0]); + Os.close(pipes[1]); return progress; } diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index 222c69ceb612..292e6bdba539 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -17,6 +17,10 @@ package android.os; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; +import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH; +import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH; +import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NULL_ACTION_MATCH; + import android.animation.ValueAnimator; import android.annotation.IntDef; import android.annotation.NonNull; @@ -2135,27 +2139,26 @@ public final class StrictMode { } } - private static void registerIntentMatchingRestrictionCallback() { - try { - ActivityManager.getService().registerStrictModeCallback( - new UnsafeIntentStrictModeCallback()); - } catch (RemoteException e) { - /* - If exception is DeadObjectException it means system process is dead, so we can ignore - */ - if (!(e instanceof DeadObjectException)) { - Log.e(TAG, "RemoteException handling StrictMode violation", e); - } - } - } - private static final class UnsafeIntentStrictModeCallback extends IUnsafeIntentStrictModeCallback.Stub { @Override - public void onImplicitIntentMatchedInternalComponent(Intent intent) { + public void onUnsafeIntent(int type, Intent intent) { if (StrictMode.vmUnsafeIntentLaunchEnabled()) { - StrictMode.onUnsafeIntentLaunch(intent, - "Launch of unsafe implicit intent: " + intent); + StrictMode.onUnsafeIntentLaunch(type, intent); + } + } + } + + /** Each process should only have one singleton callback */ + private static volatile UnsafeIntentStrictModeCallback sUnsafeIntentCallback; + + private static void registerIntentMatchingRestrictionCallback() { + if (sUnsafeIntentCallback == null) { + sUnsafeIntentCallback = new UnsafeIntentStrictModeCallback(); + try { + ActivityManager.getService().registerStrictModeCallback(sUnsafeIntentCallback); + } catch (RemoteException e) { + // system_server should not throw } } } @@ -2383,9 +2386,22 @@ public final class StrictMode { onVmPolicyViolation(new UnsafeIntentLaunchViolation(intent)); } - /** @hide */ - public static void onUnsafeIntentLaunch(Intent intent, String message) { - onVmPolicyViolation(new UnsafeIntentLaunchViolation(intent, message)); + private static void onUnsafeIntentLaunch(int type, Intent intent) { + String msg; + switch (type) { + case UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NULL_ACTION_MATCH: + msg = "Launch of intent with null action: "; + break; + case UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH: + msg = "Implicit intent matching internal non-exported component: "; + break; + case UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH: + msg = "Intent mismatch target component intent filter: "; + break; + default: + return; + } + onVmPolicyViolation(new UnsafeIntentLaunchViolation(intent, msg + intent)); } /** Assume locked until we hear otherwise */ diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig index 34fb963924ae..e029e520f1b1 100644 --- a/core/java/android/permission/flags.aconfig +++ b/core/java/android/permission/flags.aconfig @@ -193,7 +193,7 @@ flag { namespace: "permissions" description: "Enable getDeviceId API in OpEventProxyInfo" bug: "337340961" - } +} flag { name: "device_aware_app_op_new_schema_enabled" @@ -201,4 +201,15 @@ flag { namespace: "permissions" description: "Persist device attributed AppOp accesses on the disk" bug: "308201969" -}
\ No newline at end of file +} + +flag { + name: "apex_signature_permission_allowlist_enabled" + is_fixed_read_only: true + namespace: "permissions" + description: "Enable reading signature permission allowlist from APEXes" + bug: "308573169" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 53a30b268da4..05345d88f771 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6147,6 +6147,15 @@ public final class Settings { public static final String TOUCHPAD_RIGHT_CLICK_ZONE = "touchpad_right_click_zone"; /** + * Pointer fill style, specified by + * {@link android.view.PointerIcon.PointerIconVectorStyleFill} constants. + * + * @hide + */ + @Readable + public static final String POINTER_FILL_STYLE = "pointer_fill_style"; + + /** * Whether lock-to-app will be triggered by long-press on recents. * @hide */ @@ -6348,6 +6357,7 @@ public final class Settings { PRIVATE_SETTINGS.add(SIP_ADDRESS_ONLY); PRIVATE_SETTINGS.add(SIP_ASK_ME_EACH_TIME); PRIVATE_SETTINGS.add(POINTER_SPEED); + PRIVATE_SETTINGS.add(POINTER_FILL_STYLE); PRIVATE_SETTINGS.add(LOCK_TO_APP_ENABLED); PRIVATE_SETTINGS.add(EGG_MODE); PRIVATE_SETTINGS.add(SHOW_BATTERY_PERCENT); diff --git a/core/java/android/service/dreams/OWNERS b/core/java/android/service/dreams/OWNERS index 77bcee832250..119ca55f8e49 100644 --- a/core/java/android/service/dreams/OWNERS +++ b/core/java/android/service/dreams/OWNERS @@ -1,10 +1,11 @@ -# Bug component: 78010 +# Bug component: 66910 brycelee@google.com -dsandler@google.com -galinap@google.com -jjaggi@google.com lusilva@google.com -michaelwr@google.com -santoscordon@google.com wxyz@google.com +justinkoh@google.com + +rgl@google.com +santoscordon@google.com + +dsandler@google.com diff --git a/core/java/android/service/ondeviceintelligence/IOnDeviceSandboxedInferenceService.aidl b/core/java/android/service/ondeviceintelligence/IOnDeviceSandboxedInferenceService.aidl index 2aa17c4681bd..1af3b0f374f1 100644 --- a/core/java/android/service/ondeviceintelligence/IOnDeviceSandboxedInferenceService.aidl +++ b/core/java/android/service/ondeviceintelligence/IOnDeviceSandboxedInferenceService.aidl @@ -21,6 +21,7 @@ import android.app.ondeviceintelligence.IResponseCallback; import android.app.ondeviceintelligence.ITokenInfoCallback; import android.app.ondeviceintelligence.IProcessingSignal; import android.app.ondeviceintelligence.Feature; +import android.os.IRemoteCallback; import android.os.ICancellationSignal; import android.os.PersistableBundle; import android.os.Bundle; @@ -34,18 +35,19 @@ import android.service.ondeviceintelligence.IProcessingUpdateStatusCallback; * @hide */ oneway interface IOnDeviceSandboxedInferenceService { - void registerRemoteStorageService(in IRemoteStorageService storageService); + void registerRemoteStorageService(in IRemoteStorageService storageService, + in IRemoteCallback remoteCallback) = 0; void requestTokenInfo(int callerUid, in Feature feature, in Bundle request, in AndroidFuture cancellationSignal, - in ITokenInfoCallback tokenInfoCallback); + in ITokenInfoCallback tokenInfoCallback) = 1; void processRequest(int callerUid, in Feature feature, in Bundle request, in int requestType, in AndroidFuture cancellationSignal, in AndroidFuture processingSignal, - in IResponseCallback callback); + in IResponseCallback callback) = 2; void processRequestStreaming(int callerUid, in Feature feature, in Bundle request, in int requestType, in AndroidFuture cancellationSignal, in AndroidFuture processingSignal, - in IStreamingResponseCallback callback); + in IStreamingResponseCallback callback) = 3; void updateProcessingState(in Bundle processingState, - in IProcessingUpdateStatusCallback callback); + in IProcessingUpdateStatusCallback callback) = 4; }
\ No newline at end of file diff --git a/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java b/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java index d00485cb1ca5..a77e07662d23 100644 --- a/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java +++ b/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java @@ -51,6 +51,7 @@ import android.os.Handler; import android.os.HandlerExecutor; import android.os.IBinder; import android.os.ICancellationSignal; +import android.os.IRemoteCallback; import android.os.Looper; import android.os.OutcomeReceiver; import android.os.ParcelFileDescriptor; @@ -148,9 +149,12 @@ public abstract class OnDeviceSandboxedInferenceService extends Service { if (SERVICE_INTERFACE.equals(intent.getAction())) { return new IOnDeviceSandboxedInferenceService.Stub() { @Override - public void registerRemoteStorageService(IRemoteStorageService storageService) { + public void registerRemoteStorageService(IRemoteStorageService storageService, + IRemoteCallback remoteCallback) throws RemoteException { Objects.requireNonNull(storageService); mRemoteStorageService = storageService; + remoteCallback.sendResult( + Bundle.EMPTY); //to notify caller uid to system-server. } @Override diff --git a/core/java/android/telephony/DropBoxManagerLoggerBackend.java b/core/java/android/telephony/DropBoxManagerLoggerBackend.java new file mode 100644 index 000000000000..25a3b9f13d3b --- /dev/null +++ b/core/java/android/telephony/DropBoxManagerLoggerBackend.java @@ -0,0 +1,261 @@ +/* + * 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.telephony; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.os.DropBoxManager; +import android.os.Handler; +import android.os.HandlerThread; +import android.util.Log; + +import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; + +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Optional; + +/** + * A persistent logger backend that stores logs in Android DropBoxManager + * + * @hide + */ +public class DropBoxManagerLoggerBackend implements PersistentLoggerBackend { + + private static final String TAG = "DropBoxManagerLoggerBackend"; + // Separate tag reference to be explicitly used for dropboxmanager instead of logcat logging + private static final String DROPBOX_TAG = "DropBoxManagerLoggerBackend"; + private static final DateTimeFormatter LOG_TIMESTAMP_FORMATTER = + DateTimeFormatter.ofPattern("MM-dd HH:mm:ss.SSS"); + private static final ZoneId LOCAL_ZONE_ID = ZoneId.systemDefault(); + private static final int BUFFER_SIZE_BYTES = 500 * 1024; // 500 KB + private static final int MIN_BUFFER_BYTES_FOR_FLUSH = 5 * 1024; // 5 KB + + private static DropBoxManagerLoggerBackend sInstance; + + private final DropBoxManager mDropBoxManager; + private final Object mBufferLock = new Object(); + @GuardedBy("mBufferLock") + private final StringBuilder mLogBuffer = new StringBuilder(); + private long mBufferStartTime = -1L; + private final HandlerThread mHandlerThread = new HandlerThread(DROPBOX_TAG); + private final Handler mHandler; + // Flag for determining if logging is enabled as a general feature + private final boolean mDropBoxManagerLoggingEnabled; + // Flag for controlling if logging is enabled at runtime + private boolean mIsLoggingEnabled = false; + + /** + * Returns a singleton instance of {@code DropBoxManagerLoggerBackend} that will log to + * DropBoxManager if the config_dropboxmanager_persistent_logging_enabled resource config is + * enabled. + * @param context Android context + */ + @Nullable + public static synchronized DropBoxManagerLoggerBackend getInstance(@NonNull Context context) { + if (sInstance == null) { + sInstance = new DropBoxManagerLoggerBackend(context); + } + return sInstance; + } + + private DropBoxManagerLoggerBackend(@NonNull Context context) { + mDropBoxManager = context.getSystemService(DropBoxManager.class); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + mDropBoxManagerLoggingEnabled = persistentLoggingEnabled(context); + } + + private boolean persistentLoggingEnabled(@NonNull Context context) { + try { + return context.getResources().getBoolean( + R.bool.config_dropboxmanager_persistent_logging_enabled); + } catch (RuntimeException e) { + Log.w(TAG, "Persistent logging config not found"); + return false; + } + } + + /** + * Enable or disable logging to DropBoxManager + * @param isLoggingEnabled Whether logging should be enabled + */ + public void setLoggingEnabled(boolean isLoggingEnabled) { + Log.i(DROPBOX_TAG, "toggle logging: " + isLoggingEnabled); + mIsLoggingEnabled = isLoggingEnabled; + } + + /** + * Persist a DEBUG log message. + * @param tag Used to identify the source of a log message. + * @param msg The message you would like logged. + */ + public void debug(@NonNull String tag, @NonNull String msg) { + if (!mDropBoxManagerLoggingEnabled) { + return; + } + bufferLog("D", tag, msg, Optional.empty()); + } + + /** + * Persist a INFO log message. + * @param tag Used to identify the source of a log message. + * @param msg The message you would like logged. + */ + public void info(@NonNull String tag, @NonNull String msg) { + if (!mDropBoxManagerLoggingEnabled) { + return; + } + bufferLog("I", tag, msg, Optional.empty()); + } + + /** + * Persist a WARN log message. + * @param tag Used to identify the source of a log message. + * @param msg The message you would like logged. + */ + public void warn(@NonNull String tag, @NonNull String msg) { + if (!mDropBoxManagerLoggingEnabled) { + return; + } + bufferLog("W", tag, msg, Optional.empty()); + } + + /** + * Persist a WARN log message. + * @param tag Used to identify the source of a log message. + * @param msg The message you would like logged. + * @param t An exception to log. + */ + public void warn(@NonNull String tag, @NonNull String msg, @NonNull Throwable t) { + if (!mDropBoxManagerLoggingEnabled) { + return; + } + bufferLog("W", tag, msg, Optional.of(t)); + } + + /** + * Persist a ERROR log message. + * @param tag Used to identify the source of a log message. + * @param msg The message you would like logged. + */ + public void error(@NonNull String tag, @NonNull String msg) { + if (!mDropBoxManagerLoggingEnabled) { + return; + } + bufferLog("E", tag, msg, Optional.empty()); + } + + /** + * Persist a ERROR log message. + * @param tag Used to identify the source of a log message. + * @param msg The message you would like logged. + * @param t An exception to log. + */ + public void error(@NonNull String tag, @NonNull String msg, @NonNull Throwable t) { + if (!mDropBoxManagerLoggingEnabled) { + return; + } + bufferLog("E", tag, msg, Optional.of(t)); + } + + private synchronized void bufferLog( + @NonNull String level, + @NonNull String tag, + @NonNull String msg, + Optional<Throwable> t) { + if (!mIsLoggingEnabled) { + return; + } + + if (mBufferStartTime == -1L) { + mBufferStartTime = System.currentTimeMillis(); + } + + synchronized (mBufferLock) { + mLogBuffer + .append(formatLog(level, tag, msg, t)) + .append("\n"); + + if (mLogBuffer.length() >= BUFFER_SIZE_BYTES) { + flushAsync(); + } + } + } + + private String formatLog( + @NonNull String level, + @NonNull String tag, + @NonNull String msg, + Optional<Throwable> t) { + // Expected format = "$Timestamp $Level $Tag: $Message" + return formatTimestamp(System.currentTimeMillis()) + " " + level + " " + tag + ": " + + t.map(throwable -> msg + ": " + Log.getStackTraceString(throwable)).orElse(msg); + } + + private String formatTimestamp(long currentTimeMillis) { + return Instant.ofEpochMilli(currentTimeMillis) + .atZone(LOCAL_ZONE_ID) + .format(LOG_TIMESTAMP_FORMATTER); + } + + /** + * Flushes all buffered logs into DropBoxManager as a single log record with a tag of + * {@link #DROPBOX_TAG} asynchronously. Should be invoked sparingly as DropBoxManager has + * device-level limitations on the number files that can be stored. + */ + public void flushAsync() { + if (!mDropBoxManagerLoggingEnabled) { + return; + } + + mHandler.post(this::flush); + }; + + /** + * Flushes all buffered logs into DropBoxManager as a single log record with a tag of + * {@link #DROPBOX_TAG}. Should be invoked sparingly as DropBoxManager has device-level + * limitations on the number files that can be stored. + */ + public void flush() { + if (!mDropBoxManagerLoggingEnabled) { + return; + } + + synchronized (mBufferLock) { + if (mLogBuffer.length() < MIN_BUFFER_BYTES_FOR_FLUSH) { + return; + } + + Log.d(DROPBOX_TAG, "Flushing logs from " + + formatTimestamp(mBufferStartTime) + " to " + + formatTimestamp(System.currentTimeMillis())); + + try { + mDropBoxManager.addText(DROPBOX_TAG, mLogBuffer.toString()); + } catch (Exception e) { + Log.w(DROPBOX_TAG, "Failed to flush logs of length " + + mLogBuffer.length() + " to DropBoxManager", e); + } + mLogBuffer.setLength(0); + } + mBufferStartTime = -1L; + } +} diff --git a/core/java/android/telephony/PersistentLogger.java b/core/java/android/telephony/PersistentLogger.java new file mode 100644 index 000000000000..8b12a1cb997e --- /dev/null +++ b/core/java/android/telephony/PersistentLogger.java @@ -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 android.telephony; + +import android.annotation.NonNull; + +/** + * A persistent logging client. Intended for persisting critical debug logs in situations where + * standard Android logcat logs may not be retained long enough. + * + * @hide + */ +public class PersistentLogger { + private final PersistentLoggerBackend mPersistentLoggerBackend; + + public PersistentLogger(@NonNull PersistentLoggerBackend persistentLoggerBackend) { + mPersistentLoggerBackend = persistentLoggerBackend; + } + + /** + * Persist a DEBUG log message. + * @param tag Used to identify the source of a log message. + * @param msg The message you would like logged. + */ + public void debug(@NonNull String tag, @NonNull String msg) { + mPersistentLoggerBackend.debug(tag, msg); + } + + /** + * Persist a INFO log message. + * @param tag Used to identify the source of a log message. + * @param msg The message you would like logged. + */ + public void info(@NonNull String tag, @NonNull String msg) { + mPersistentLoggerBackend.info(tag, msg); + } + + /** + * Persist a WARN log message. + * @param tag Used to identify the source of a log message. + * @param msg The message you would like logged. + */ + public void warn(@NonNull String tag, @NonNull String msg) { + mPersistentLoggerBackend.warn(tag, msg); + } + + /** + * Persist a WARN log message. + * @param tag Used to identify the source of a log message. + * @param msg The message you would like logged. + * @param t An exception to log. + */ + public void warn(@NonNull String tag, @NonNull String msg, @NonNull Throwable t) { + mPersistentLoggerBackend.warn(tag, msg, t); + } + + /** + * Persist a ERROR log message. + * @param tag Used to identify the source of a log message. + * @param msg The message you would like logged. + */ + public void error(@NonNull String tag, @NonNull String msg) { + mPersistentLoggerBackend.error(tag, msg); + } + + /** + * Persist a ERROR log message. + * @param tag Used to identify the source of a log message. + * @param msg The message you would like logged. + * @param t An exception to log. + */ + public void error(@NonNull String tag, @NonNull String msg, @NonNull Throwable t) { + mPersistentLoggerBackend.error(tag, msg, t); + } +} diff --git a/core/java/android/telephony/PersistentLoggerBackend.java b/core/java/android/telephony/PersistentLoggerBackend.java new file mode 100644 index 000000000000..e3e72e19e418 --- /dev/null +++ b/core/java/android/telephony/PersistentLoggerBackend.java @@ -0,0 +1,71 @@ +/* + * 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.telephony; + +import android.annotation.NonNull; + +/** + * Interface for logging backends to provide persistent log storage. + * + * @hide + */ +public interface PersistentLoggerBackend { + + /** + * Persist a DEBUG log message. + * @param tag Used to identify the source of a log message. + * @param msg The message you would like logged. + */ + void debug(@NonNull String tag, @NonNull String msg); + + /** + * Persist a INFO log message. + * @param tag Used to identify the source of a log message. + * @param msg The message you would like logged. + */ + void info(@NonNull String tag, @NonNull String msg); + + /** + * Persist a WARN log message. + * @param tag Used to identify the source of a log message. + * @param msg The message you would like logged. + */ + void warn(@NonNull String tag, @NonNull String msg); + + /** + * Persist a WARN log message. + * @param tag Used to identify the source of a log message. + * @param msg The message you would like logged. + * @param t An exception to log. + */ + void warn(@NonNull String tag, @NonNull String msg, @NonNull Throwable t); + + /** + * Persist a ERROR log message. + * @param tag Used to identify the source of a log message. + * @param msg The message you would like logged. + */ + void error(@NonNull String tag, @NonNull String msg); + + /** + * Persist a ERROR log message. + * @param tag Used to identify the source of a log message. + * @param msg The message you would like logged. + * @param t An exception to log. + */ + void error(@NonNull String tag, @NonNull String msg, @NonNull Throwable t); +} diff --git a/core/java/android/text/flags/flags.aconfig b/core/java/android/text/flags/flags.aconfig index 70dc300e59d0..7023ef7afd2f 100644 --- a/core/java/android/text/flags/flags.aconfig +++ b/core/java/android/text/flags/flags.aconfig @@ -191,3 +191,23 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "disable_handwriting_initiator_for_ime" + namespace: "text" + description: "Don't initiate handwriting for IME views." + bug: "343304685" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "fix_null_typeface_bolding" + namespace: "text" + description: "Use a bold typeface when bolding is enabled and the original typeface is null" + bug: "314811487" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 1626924c0f46..8d884f2d4b11 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -713,11 +713,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation new InsetsState.OnTraverseCallbacks() { private @InsetsType int mTypes; + private InsetsState mFromState; private InsetsState mToState; @Override public void onStart(InsetsState state1, InsetsState state2) { mTypes = 0; + mFromState = null; mToState = null; } @@ -734,9 +736,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation return; } mTypes |= source1.getType(); + if (mFromState == null) { + mFromState = new InsetsState(); + } if (mToState == null) { mToState = new InsetsState(); } + mFromState.addSource(new InsetsSource(source1)); mToState.addSource(new InsetsSource(source2)); } @@ -747,7 +753,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } cancelExistingControllers(mTypes); final InsetsAnimationControlRunner runner = new InsetsResizeAnimationRunner( - mFrame, state1, mToState, RESIZE_INTERPOLATOR, + mFrame, mFromState, mToState, RESIZE_INTERPOLATOR, ANIMATION_DURATION_RESIZE, mTypes, InsetsController.this); if (mRunningAnimations.isEmpty()) { mHost.notifyAnimationRunningStateChanged(true); diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java index 71199e9c3619..7c2577fdf8e1 100644 --- a/core/java/android/view/PointerIcon.java +++ b/core/java/android/view/PointerIcon.java @@ -17,6 +17,7 @@ package android.view; import android.annotation.FlaggedApi; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; @@ -43,8 +44,13 @@ import android.util.Log; import android.util.SparseArray; import android.view.flags.Flags; +import androidx.annotation.VisibleForTesting; + import com.android.internal.util.XmlUtils; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Represents an icon that can be used as a mouse pointer. * <p> @@ -164,6 +170,29 @@ public final class PointerIcon implements Parcelable { // every time we need to resolve the icon (i.e. on each input event). private static final SparseArray<PointerIcon> SYSTEM_ICONS = new SparseArray<>(); + /** @hide */ + @IntDef(prefix = {"POINTER_ICON_VECTOR_STYLE_FILL_"}, value = { + POINTER_ICON_VECTOR_STYLE_FILL_BLACK, + POINTER_ICON_VECTOR_STYLE_FILL_GREEN, + POINTER_ICON_VECTOR_STYLE_FILL_YELLOW, + POINTER_ICON_VECTOR_STYLE_FILL_PINK, + POINTER_ICON_VECTOR_STYLE_FILL_BLUE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface PointerIconVectorStyleFill {} + + /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_BLACK = 0; + /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_GREEN = 1; + /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_YELLOW = 2; + /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_PINK = 3; + /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_BLUE = 4; + + // If adding a PointerIconVectorStyleFill, update END value for {@link SystemSettingsValidators} + /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_BEGIN = + POINTER_ICON_VECTOR_STYLE_FILL_BLACK; + /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_END = + POINTER_ICON_VECTOR_STYLE_FILL_BLUE; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final int mType; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @@ -261,7 +290,7 @@ public final class PointerIcon implements Parcelable { } final PointerIcon icon = new PointerIcon(type); - icon.loadResource(context.getResources(), resourceId); + icon.loadResource(context.getResources(), resourceId, context.getTheme()); return icon; } @@ -324,7 +353,7 @@ public final class PointerIcon implements Parcelable { } PointerIcon icon = new PointerIcon(TYPE_CUSTOM); - icon.loadResource(resources, resourceId); + icon.loadResource(resources, resourceId, null); return icon; } @@ -443,7 +472,8 @@ public final class PointerIcon implements Parcelable { return new BitmapDrawable(resources, bitmap); } - private void loadResource(@NonNull Resources resources, @XmlRes int resourceId) { + private void loadResource(@NonNull Resources resources, @XmlRes int resourceId, + @Nullable Resources.Theme theme) { final XmlResourceParser parser = resources.getXml(resourceId); final int bitmapRes; final float hotSpotX; @@ -467,7 +497,7 @@ public final class PointerIcon implements Parcelable { throw new IllegalArgumentException("<pointer-icon> is missing bitmap attribute."); } - Drawable drawable = resources.getDrawable(bitmapRes); + Drawable drawable = resources.getDrawable(bitmapRes, theme); if (drawable instanceof AnimationDrawable) { // Extract animation frame bitmaps. final AnimationDrawable animationDrawable = (AnimationDrawable) drawable; @@ -649,6 +679,27 @@ public final class PointerIcon implements Parcelable { } /** + * Convert fill style constant to resource ID. + * + * @hide + */ + public static int vectorFillStyleToResource(@PointerIconVectorStyleFill int fillStyle) { + return switch (fillStyle) { + case POINTER_ICON_VECTOR_STYLE_FILL_BLACK -> + com.android.internal.R.style.PointerIconVectorStyleFillBlack; + case POINTER_ICON_VECTOR_STYLE_FILL_GREEN -> + com.android.internal.R.style.PointerIconVectorStyleFillGreen; + case POINTER_ICON_VECTOR_STYLE_FILL_YELLOW -> + com.android.internal.R.style.PointerIconVectorStyleFillYellow; + case POINTER_ICON_VECTOR_STYLE_FILL_PINK -> + com.android.internal.R.style.PointerIconVectorStyleFillPink; + case POINTER_ICON_VECTOR_STYLE_FILL_BLUE -> + com.android.internal.R.style.PointerIconVectorStyleFillBlue; + default -> com.android.internal.R.style.PointerIconVectorStyleFillBlack; + }; + } + + /** * Sets whether drop shadow will draw in the native code. * * @hide @@ -658,4 +709,14 @@ public final class PointerIcon implements Parcelable { public void setDrawNativeDropShadow(boolean drawNativeDropShadow) { mDrawNativeDropShadow = drawNativeDropShadow; } + + /** + * Gets the PointerIcon's bitmap. + * + * @hide + */ + @VisibleForTesting + public Bitmap getBitmap() { + return mBitmap; + } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index de81828fe7e2..14bb6812d06a 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -33899,8 +33899,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, int category; switch (getViewRootImpl().intermittentUpdateState()) { case ViewRootImpl.INTERMITTENT_STATE_INTERMITTENT -> category = - (sToolkitFrameRateBySizeReadOnlyFlagValue ? FRAME_RATE_CATEGORY_LOW - : FRAME_RATE_CATEGORY_NORMAL) | FRAME_RATE_CATEGORY_REASON_INTERMITTENT; + FRAME_RATE_CATEGORY_NORMAL | FRAME_RATE_CATEGORY_REASON_INTERMITTENT; case ViewRootImpl.INTERMITTENT_STATE_NOT_INTERMITTENT -> category = mSizeBasedFrameRateCategoryAndReason; default -> category = mLastFrameRateCategory; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 088d55176e70..cb82278ca577 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -127,6 +127,7 @@ import static com.android.window.flags.Flags.activityWindowInfoFlag; import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay; import static com.android.window.flags.Flags.setScPropertiesInClient; import static com.android.window.flags.Flags.windowSessionRelayoutInfo; +import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme; import android.Manifest; import android.accessibilityservice.AccessibilityService; @@ -176,6 +177,7 @@ import android.graphics.Region; import android.graphics.RenderNode; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; +import android.hardware.SyncFence; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.hardware.display.DisplayManagerGlobal; @@ -217,6 +219,7 @@ import android.util.proto.ProtoOutputStream; import android.view.InputDevice.InputSourceClass; import android.view.Surface.OutOfResourcesException; import android.view.SurfaceControl.Transaction; +import android.view.SurfaceControl.TransactionStats; import android.view.View.AttachInfo; import android.view.View.FocusDirection; import android.view.View.MeasureSpec; @@ -291,6 +294,7 @@ import java.util.OptionalInt; import java.util.Queue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; +import java.util.function.Consumer; import java.util.function.Predicate; /** * The top of a view hierarchy, implementing the needed protocol between View @@ -1187,6 +1191,13 @@ public final class ViewRootImpl implements ViewParent, private String mFpsTraceName; private String mLargestViewTraceName; + private final boolean mAppStartInfoTimestampsFlagValue; + @GuardedBy("this") + private boolean mAppStartTimestampsSent = false; + private boolean mAppStartTrackingStarted = false; + private long mRenderThreadDrawStartTimeNs = -1; + private long mFirstFramePresentedTimeNs = -1; + private static boolean sToolkitSetFrameRateReadOnlyFlagValue; private static boolean sToolkitFrameRateFunctionEnablingReadOnlyFlagValue; private static boolean sToolkitMetricsForFrameRateDecisionFlagValue; @@ -1303,6 +1314,8 @@ public final class ViewRootImpl implements ViewParent, } else { mSensitiveContentProtectionService = null; } + + mAppStartInfoTimestampsFlagValue = android.app.Flags.appStartInfoTimestamps(); } public static void addFirstDrawHandler(Runnable callback) { @@ -2575,6 +2588,12 @@ public final class ViewRootImpl implements ViewParent, notifySurfaceDestroyed(); } destroySurface(); + + // Reset so they can be sent again for warm starts. + mAppStartTimestampsSent = false; + mAppStartTrackingStarted = false; + mRenderThreadDrawStartTimeNs = -1; + mFirstFramePresentedTimeNs = -1; } } } @@ -4373,6 +4392,30 @@ public final class ViewRootImpl implements ViewParent, reportDrawFinished(t, seqId); } }); + + // Only trigger once per {@link ViewRootImpl} instance, so don't add listener if + // {link mTransactionCompletedTimeNs} has already been set. + if (mAppStartInfoTimestampsFlagValue && !mAppStartTrackingStarted) { + mAppStartTrackingStarted = true; + Transaction transaction = new Transaction(); + transaction.addTransactionCompletedListener(mExecutor, + new Consumer<TransactionStats>() { + @Override + public void accept(TransactionStats transactionStats) { + SyncFence presentFence = transactionStats.getPresentFence(); + if (presentFence.awaitForever()) { + if (mFirstFramePresentedTimeNs == -1) { + // Only trigger once per {@link ViewRootImpl} instance. + mFirstFramePresentedTimeNs = presentFence.getSignalTime(); + maybeSendAppStartTimes(); + } + } + presentFence.close(); + } + }); + applyTransactionOnDraw(transaction); + } + if (DEBUG_BLAST) { Log.d(mTag, "Setup new sync=" + mWmsRequestSyncGroup.getName()); } @@ -4380,6 +4423,45 @@ public final class ViewRootImpl implements ViewParent, mWmsRequestSyncGroup.add(this, null /* runnable */); } + private void maybeSendAppStartTimes() { + synchronized (this) { + if (mAppStartTimestampsSent) { + // Don't send timestamps more than once. + return; + } + + // If we already have {@link mRenderThreadDrawStartTimeNs} then pass it through, if not + // post to main thread and check if we have it there. + if (mRenderThreadDrawStartTimeNs != -1) { + sendAppStartTimesLocked(); + } else { + mHandler.post(new Runnable() { + @Override + public void run() { + synchronized (ViewRootImpl.this) { + if (mRenderThreadDrawStartTimeNs == -1) { + return; + } + sendAppStartTimesLocked(); + } + } + }); + } + } + } + + @GuardedBy("this") + private void sendAppStartTimesLocked() { + try { + ActivityManager.getService().reportStartInfoViewTimestamps( + mRenderThreadDrawStartTimeNs, mFirstFramePresentedTimeNs); + mAppStartTimestampsSent = true; + } catch (RemoteException e) { + // Ignore, timestamps may be lost. + if (DBG) Log.d(TAG, "Exception attempting to report start timestamps.", e); + } + } + /** * Helper used to notify the service to block projection when a sensitive * view (the view displays sensitive content) is attached to the window. @@ -5566,7 +5648,13 @@ public final class ViewRootImpl implements ViewParent, registerCallbackForPendingTransactions(); } + long timeNs = SystemClock.uptimeNanos(); mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this); + + // Only trigger once per {@link ViewRootImpl} instance. + if (mAppStartInfoTimestampsFlagValue && mRenderThreadDrawStartTimeNs == -1) { + mRenderThreadDrawStartTimeNs = timeNs; + } } else { // If we get here with a disabled & requested hardware renderer, something went // wrong (an invalidate posted right before we destroyed the hardware surface @@ -7416,6 +7504,8 @@ public final class ViewRootImpl implements ViewParent, final KeyEvent event = (KeyEvent)q.mEvent; if (mView.dispatchKeyEventPreIme(event)) { return FINISH_HANDLED; + } else if (q.forPreImeOnly()) { + return FINISH_NOT_HANDLED; } return FORWARD; } @@ -7835,7 +7925,11 @@ public final class ViewRootImpl implements ViewParent, private int processPointerEvent(QueuedInputEvent q) { final MotionEvent event = (MotionEvent)q.mEvent; final int action = event.getAction(); - boolean handled = mHandwritingInitiator.onTouchEvent(event); + boolean handled = false; + if (!disableHandwritingInitiatorForIme() + || mWindowAttributes.type != TYPE_INPUT_METHOD) { + handled = mHandwritingInitiator.onTouchEvent(event); + } if (handled) { // If handwriting is started, toolkit doesn't receive ACTION_UP. mLastClickToolType = event.getToolType(event.getActionIndex()); @@ -7987,7 +8081,9 @@ public final class ViewRootImpl implements ViewParent, } PointerIcon pointerIcon = null; - if (event.isStylusPointer() && mIsStylusPointerIconEnabled) { + if (event.isStylusPointer() && mIsStylusPointerIconEnabled + && (!disableHandwritingInitiatorForIme() + || mWindowAttributes.type != TYPE_INPUT_METHOD)) { pointerIcon = mHandwritingInitiator.onResolvePointerIcon(mContext, event); } if (pointerIcon == null) { @@ -9906,6 +10002,7 @@ public final class ViewRootImpl implements ViewParent, public static final int FLAG_RESYNTHESIZED = 1 << 4; public static final int FLAG_UNHANDLED = 1 << 5; public static final int FLAG_MODIFIED_FOR_COMPATIBILITY = 1 << 6; + public static final int FLAG_PRE_IME_ONLY = 1 << 7; public QueuedInputEvent mNext; @@ -9913,6 +10010,13 @@ public final class ViewRootImpl implements ViewParent, public InputEventReceiver mReceiver; public int mFlags; + public boolean forPreImeOnly() { + if ((mFlags & FLAG_PRE_IME_ONLY) != 0) { + return true; + } + return false; + } + public boolean shouldSkipIme() { if ((mFlags & FLAG_DELIVER_POST_IME) != 0) { return true; @@ -9939,6 +10043,7 @@ public final class ViewRootImpl implements ViewParent, hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb); hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb); hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb); + hasPrevious = flagToString("FLAG_PRE_IME_ONLY", FLAG_PRE_IME_ONLY, hasPrevious, sb); if (!hasPrevious) { sb.append("0"); } @@ -9995,7 +10100,7 @@ public final class ViewRootImpl implements ViewParent, } @UnsupportedAppUsage - void enqueueInputEvent(InputEvent event, + QueuedInputEvent enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately) { QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags); @@ -10034,6 +10139,7 @@ public final class ViewRootImpl implements ViewParent, } else { scheduleProcessInputEvents(); } + return q; } private void scheduleProcessInputEvents() { @@ -12355,29 +12461,45 @@ public final class ViewRootImpl implements ViewParent, + "IWindow:%s Session:%s", mOnBackInvokedDispatcher, mBasePackageName, mWindow, mWindowSession)); } - mOnBackInvokedDispatcher.attachToWindow(mWindowSession, mWindow, + mOnBackInvokedDispatcher.attachToWindow(mWindowSession, mWindow, this, mImeBackAnimationController); } - private void sendBackKeyEvent(int action) { + /** + * Sends {@link KeyEvent#ACTION_DOWN ACTION_DOWN} and {@link KeyEvent#ACTION_UP ACTION_UP} + * back key events + * + * @param preImeOnly whether the back events should be sent to the pre-ime stage only + * @return whether the event was handled (i.e. onKeyPreIme consumed it if preImeOnly=true) + */ + public boolean injectBackKeyEvents(boolean preImeOnly) { + boolean consumed; + try { + processingBackKey(true); + sendBackKeyEvent(KeyEvent.ACTION_DOWN, preImeOnly); + consumed = sendBackKeyEvent(KeyEvent.ACTION_UP, preImeOnly); + } finally { + processingBackKey(false); + } + return consumed; + } + + private boolean sendBackKeyEvent(int action, boolean preImeOnly) { long when = SystemClock.uptimeMillis(); final KeyEvent ev = new KeyEvent(when, when, action, KeyEvent.KEYCODE_BACK, 0 /* repeat */, 0 /* metaState */, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */, KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, InputDevice.SOURCE_KEYBOARD); - enqueueInputEvent(ev, null /* receiver */, 0 /* flags */, true /* processImmediately */); + int flags = preImeOnly ? QueuedInputEvent.FLAG_PRE_IME_ONLY : 0; + QueuedInputEvent q = enqueueInputEvent(ev, null /* receiver */, flags, + true /* processImmediately */); + return (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0; } private void registerCompatOnBackInvokedCallback() { mCompatOnBackInvokedCallback = () -> { - try { - processingBackKey(true); - sendBackKeyEvent(KeyEvent.ACTION_DOWN); - sendBackKeyEvent(KeyEvent.ACTION_UP); - } finally { - processingBackKey(false); - } + injectBackKeyEvents(/* preImeOnly */ false); }; if (mOnBackInvokedDispatcher.hasImeOnBackInvokedDispatcher()) { Log.d(TAG, "Skip registering CompatOnBackInvokedCallback on IME dispatcher"); @@ -12809,8 +12931,13 @@ public final class ViewRootImpl implements ViewParent, + mFrameRateCompatibility); } if (sToolkitFrameRateFunctionEnablingReadOnlyFlagValue) { - mFrameRateTransaction.setFrameRate(mSurfaceControl, preferredFrameRate, - mFrameRateCompatibility).applyAsyncUnsafe(); + if (preferredFrameRate > 0) { + mFrameRateTransaction.setFrameRate(mSurfaceControl, preferredFrameRate, + mFrameRateCompatibility); + } else { + mFrameRateTransaction.clearFrameRate(mSurfaceControl); + } + mFrameRateTransaction.applyAsyncUnsafe(); } mLastPreferredFrameRate = preferredFrameRate; } diff --git a/core/java/android/view/accessibility/AccessibilityDisplayProxy.java b/core/java/android/view/accessibility/AccessibilityDisplayProxy.java index 1fe8180aa7b2..12e08148a651 100644 --- a/core/java/android/view/accessibility/AccessibilityDisplayProxy.java +++ b/core/java/android/view/accessibility/AccessibilityDisplayProxy.java @@ -302,10 +302,6 @@ public abstract class AccessibilityDisplayProxy { } @Override - public void onMagnificationSystemUIConnectionChanged(boolean connected) { - } - - @Override public void onMagnificationChanged(int displayId, @NonNull Region region, MagnificationConfig config) { } diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig index edf33875b765..ab7b2261dc17 100644 --- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig +++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig @@ -169,13 +169,3 @@ flag { description: "Feature flag for declaring system pinch zoom opt-out apis" bug: "315089687" } - -flag { - name: "wait_magnification_system_ui_connection_to_notify_service_connected" - namespace: "accessibility" - description: "Decide whether AccessibilityService needs to wait until magnification system ui connection is ready to trigger onServiceConnected" - bug: "337800504" - metadata { - purpose: PURPOSE_BUGFIX - } -} diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig index c0d31fae4b8f..4d4e4afb621c 100644 --- a/core/java/android/view/flags/view_flags.aconfig +++ b/core/java/android/view/flags/view_flags.aconfig @@ -28,6 +28,14 @@ flag { } flag { + name: "enable_vector_cursor_a11y_settings" + namespace: "systemui" + description: "Feature flag to enable accessibility settings for vector cursors." + bug: "302275042" + is_fixed_read_only: true +} + +flag { name: "sensitive_content_app_protection_api" is_exported: true namespace: "permissions" diff --git a/core/java/android/view/textclassifier/intent/OWNERS b/core/java/android/view/textclassifier/intent/OWNERS index ac80d9f4cdd0..3465fe62784f 100644 --- a/core/java/android/view/textclassifier/intent/OWNERS +++ b/core/java/android/view/textclassifier/intent/OWNERS @@ -4,5 +4,4 @@ mns@google.com toki@google.com svetoslavganov@android.com svetoslavganov@google.com -augale@google.com joannechung@google.com diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 4099e88f1c17..15f9cff87458 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -1424,6 +1424,10 @@ public class RemoteViews implements Parcelable, Filter { context.unbindService(this); } + if (items == null) { + items = new RemoteCollectionItems.Builder().build(); + } + result.complete(items); } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 78dd3b18c2a6..fd3837f3fe12 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -4817,7 +4817,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mFontWeightAdjustment != 0 && mFontWeightAdjustment != Configuration.FONT_WEIGHT_ADJUSTMENT_UNDEFINED) { if (tf == null) { - tf = Typeface.DEFAULT; + if (Flags.fixNullTypefaceBolding()) { + tf = Typeface.DEFAULT_BOLD; + } else { + tf = Typeface.DEFAULT; + } } else { int newWeight = Math.min( Math.max(tf.getWeight() + mFontWeightAdjustment, FontStyle.FONT_WEIGHT_MIN), diff --git a/core/java/android/window/BackProgressAnimator.java b/core/java/android/window/BackProgressAnimator.java index 94d7811677ae..d28500c0a1ea 100644 --- a/core/java/android/window/BackProgressAnimator.java +++ b/core/java/android/window/BackProgressAnimator.java @@ -19,8 +19,12 @@ package android.window; import android.annotation.NonNull; import android.annotation.Nullable; import android.util.FloatProperty; +import android.util.TimeUtils; +import android.view.Choreographer; import com.android.internal.dynamicanimation.animation.DynamicAnimation; +import com.android.internal.dynamicanimation.animation.FlingAnimation; +import com.android.internal.dynamicanimation.animation.FloatValueHolder; import com.android.internal.dynamicanimation.animation.SpringAnimation; import com.android.internal.dynamicanimation.animation.SpringForce; @@ -40,6 +44,7 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL * always receive progress values in [0, 1]. */ private static final float SCALE_FACTOR = 100f; + private static final float FLING_FRICTION = 8f; private final SpringAnimation mSpring; private ProgressCallback mCallback; private float mProgress = 0; @@ -48,11 +53,17 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL private boolean mBackAnimationInProgress = false; @Nullable private Runnable mBackCancelledFinishRunnable; + @Nullable + private Runnable mBackInvokedFinishRunnable; + private FlingAnimation mBackInvokedFlingAnim; private final DynamicAnimation.OnAnimationEndListener mOnAnimationEndListener = (animation, canceled, value, velocity) -> { - invokeBackCancelledRunnable(); + if (mBackCancelledFinishRunnable != null) invokeBackCancelledRunnable(); + if (mBackInvokedFinishRunnable != null) invokeBackInvokedRunnable(); reset(); }; + private final DynamicAnimation.OnAnimationUpdateListener mOnBackInvokedFlingUpdateListener = + (animation, progress, velocity) -> updateProgressValue(progress, velocity); private void setProgress(float progress) { @@ -78,7 +89,7 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL @Override public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) { - updateProgressValue(value, velocity); + if (mBackInvokedFinishRunnable == null) updateProgressValue(value, velocity); } @@ -134,6 +145,12 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL // Ensure that last progress value that apps see is 0 updateProgressValue(0, 0); invokeBackCancelledRunnable(); + } else if (mBackInvokedFinishRunnable != null) { + invokeBackInvokedRunnable(); + } + if (mBackInvokedFlingAnim != null) { + mBackInvokedFlingAnim.cancel(); + mBackInvokedFlingAnim = null; } mSpring.animateToFinalPosition(0); if (mSpring.canSkipToEnd()) { @@ -149,6 +166,30 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL } /** + * Animate the back progress animation a bit further with a high friction considering the + * current progress and velocity. + * + * @param finishCallback the callback to be invoked when the final destination is reached + */ + public void onBackInvoked(@NonNull Runnable finishCallback) { + mBackInvokedFinishRunnable = finishCallback; + mSpring.animateToFinalPosition(0); + + mBackInvokedFlingAnim = new FlingAnimation(new FloatValueHolder()) + .setStartValue(mProgress) + .setFriction(FLING_FRICTION) + .setStartVelocity(mVelocity) + .setMinValue(0) + .setMaxValue(SCALE_FACTOR); + mBackInvokedFlingAnim.addUpdateListener(mOnBackInvokedFlingUpdateListener); + mBackInvokedFlingAnim.addEndListener(mOnAnimationEndListener); + mBackInvokedFlingAnim.start(); + // do an animation-frame immediately to prevent idle frame + mBackInvokedFlingAnim.doAnimationFrame( + Choreographer.getInstance().getLastFrameTimeNanos() / TimeUtils.NANOS_PER_MS); + } + + /** * Animate the back progress animation from current progress to start position. * This should be called when back is cancelled. * @@ -196,4 +237,11 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL mBackCancelledFinishRunnable = null; } + private void invokeBackInvokedRunnable() { + mBackInvokedFlingAnim.removeUpdateListener(mOnBackInvokedFlingUpdateListener); + mBackInvokedFlingAnim.removeEndListener(mOnAnimationEndListener); + mBackInvokedFinishRunnable.run(); + mBackInvokedFinishRunnable = null; + } + }
\ No newline at end of file diff --git a/core/java/android/window/ImeOnBackInvokedDispatcher.java b/core/java/android/window/ImeOnBackInvokedDispatcher.java index 2a12507679f5..ce1f9869b690 100644 --- a/core/java/android/window/ImeOnBackInvokedDispatcher.java +++ b/core/java/android/window/ImeOnBackInvokedDispatcher.java @@ -55,6 +55,9 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc static final int RESULT_CODE_UNREGISTER = 1; @NonNull private final ResultReceiver mResultReceiver; + // The handler to run callbacks on. This should be on the same thread + // the ViewRootImpl holding IME's WindowOnBackInvokedDispatcher is created on. + private Handler mHandler; public ImeOnBackInvokedDispatcher(Handler handler) { mResultReceiver = new ResultReceiver(handler) { @@ -68,6 +71,10 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc }; } + void setHandler(@NonNull Handler handler) { + mHandler = handler; + } + /** * Override this method to return the {@link WindowOnBackInvokedDispatcher} of the window * that should receive the forwarded callback. @@ -326,7 +333,7 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc @Override public void onBackInvoked() { - mCallback.onBackInvoked(); + mHandler.post(mCallback::onBackInvoked); } @Override @@ -336,7 +343,7 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc private void maybeRunOnAnimationCallback(Consumer<OnBackAnimationCallback> block) { if (mCallback instanceof OnBackAnimationCallback) { - block.accept((OnBackAnimationCallback) mCallback); + mHandler.post(() -> block.accept((OnBackAnimationCallback) mCallback)); } } } diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java index 1d42c93b94a2..8bd39fbe3a52 100644 --- a/core/java/android/window/TransitionInfo.java +++ b/core/java/android/window/TransitionInfo.java @@ -1114,7 +1114,7 @@ public final class TransitionInfo implements Parcelable { private final Rect mTransitionBounds = new Rect(); private HardwareBuffer mThumbnail; private int mAnimations; - // TODO(b/295805497): Extract it from AnimationOptions + // TODO(b/295805497): Extract mBackgroundColor from AnimationOptions private @ColorInt int mBackgroundColor; // Customize activity transition animation private CustomActivityTransition mCustomActivityOpenTransition; diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 5e88d97c805e..f4f6c8aa3636 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -375,7 +375,23 @@ public final class WindowContainerTransaction implements Parcelable { */ @NonNull public WindowContainerTransaction reorder(@NonNull WindowContainerToken child, boolean onTop) { - mHierarchyOps.add(HierarchyOp.createForReorder(child.asBinder(), onTop)); + return reorder(child, onTop, false /* includingParents */); + } + + /** + * Reorders a container within its parent with an option to reorder all the parents in the + * hierarchy above among their respective siblings. + * + * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to + * the bottom. + * @param includingParents When {@code true}, all the parents in the hierarchy above are also + * reordered among their respective siblings. + * @hide + */ + @NonNull + public WindowContainerTransaction reorder(@NonNull WindowContainerToken child, boolean onTop, + boolean includingParents) { + mHierarchyOps.add(HierarchyOp.createForReorder(child.asBinder(), onTop, includingParents)); return this; } @@ -1451,6 +1467,8 @@ public final class WindowContainerTransaction implements Parcelable { @Nullable private Rect mBounds; + private boolean mIncludingParents; + private boolean mAlwaysOnTop; private boolean mReparentLeafTaskIfRelaunch; @@ -1464,11 +1482,22 @@ public final class WindowContainerTransaction implements Parcelable { .build(); } - public static HierarchyOp createForReorder(@NonNull IBinder container, boolean toTop) { + /** + * Creates the {@link HierarchyOp} for the reorder operation. + * + * @param container which needs to be reordered + * @param toTop if true, the container reorders + * @param includingParents if true, all the parents in the hierarchy above are also + * reoredered among their respective siblings + * @return + */ + public static HierarchyOp createForReorder(@NonNull IBinder container, boolean toTop, + boolean includingParents) { return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REORDER) .setContainer(container) .setReparentContainer(container) .setToTop(toTop) + .setIncludingParents(includingParents) .build(); } @@ -1555,6 +1584,7 @@ public final class WindowContainerTransaction implements Parcelable { mType = copy.mType; mContainer = copy.mContainer; mBounds = copy.mBounds; + mIncludingParents = copy.mIncludingParents; mReparent = copy.mReparent; mInsetsFrameProvider = copy.mInsetsFrameProvider; mInsetsFrameOwner = copy.mInsetsFrameOwner; @@ -1575,6 +1605,7 @@ public final class WindowContainerTransaction implements Parcelable { mType = in.readInt(); mContainer = in.readStrongBinder(); mBounds = in.readTypedObject(Rect.CREATOR); + mIncludingParents = in.readBoolean(); mReparent = in.readStrongBinder(); mInsetsFrameProvider = in.readTypedObject(InsetsFrameProvider.CREATOR); mInsetsFrameOwner = in.readStrongBinder(); @@ -1678,6 +1709,12 @@ public final class WindowContainerTransaction implements Parcelable { return mBounds; } + /** Denotes whether the parents should also be included in the op. */ + @NonNull + public boolean includingParents() { + return mIncludingParents; + } + /** Gets a string representation of a hierarchy-op type. */ public static String hopToString(int type) { switch (type) { @@ -1789,6 +1826,7 @@ public final class WindowContainerTransaction implements Parcelable { dest.writeInt(mType); dest.writeStrongBinder(mContainer); dest.writeTypedObject(mBounds, flags); + dest.writeBoolean(mIncludingParents); dest.writeStrongBinder(mReparent); dest.writeTypedObject(mInsetsFrameProvider, flags); dest.writeStrongBinder(mInsetsFrameOwner); @@ -1866,6 +1904,8 @@ public final class WindowContainerTransaction implements Parcelable { @Nullable private Rect mBounds; + private boolean mIncludingParents; + private boolean mAlwaysOnTop; private boolean mReparentLeafTaskIfRelaunch; @@ -1955,6 +1995,11 @@ public final class WindowContainerTransaction implements Parcelable { return this; } + Builder setIncludingParents(boolean value) { + mIncludingParents = value; + return this; + } + HierarchyOp build() { final HierarchyOp hierarchyOp = new HierarchyOp(mType); hierarchyOp.mContainer = mContainer; @@ -1976,6 +2021,7 @@ public final class WindowContainerTransaction implements Parcelable { hierarchyOp.mTaskFragmentOperation = mTaskFragmentOperation; hierarchyOp.mShortcutInfo = mShortcutInfo; hierarchyOp.mBounds = mBounds; + hierarchyOp.mIncludingParents = mIncludingParents; hierarchyOp.mReparentLeafTaskIfRelaunch = mReparentLeafTaskIfRelaunch; return hierarchyOp; diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java index 0ff52f13222d..4c993c2544ce 100644 --- a/core/java/android/window/WindowOnBackInvokedDispatcher.java +++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java @@ -37,6 +37,7 @@ import android.view.IWindow; import android.view.IWindowSession; import android.view.ImeBackAnimationController; import android.view.MotionEvent; +import android.view.ViewRootImpl; import androidx.annotation.VisibleForTesting; @@ -49,6 +50,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Objects; import java.util.TreeMap; +import java.util.function.BooleanSupplier; import java.util.function.Supplier; /** @@ -68,6 +70,7 @@ import java.util.function.Supplier; public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { private IWindowSession mWindowSession; private IWindow mWindow; + private ViewRootImpl mViewRoot; @VisibleForTesting public final BackTouchTracker mTouchTracker = new BackTouchTracker(); @VisibleForTesting @@ -134,10 +137,12 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { * is attached a window. */ public void attachToWindow(@NonNull IWindowSession windowSession, @NonNull IWindow window, + @Nullable ViewRootImpl viewRoot, @Nullable ImeBackAnimationController imeBackAnimationController) { synchronized (mLock) { mWindowSession = windowSession; mWindow = window; + mViewRoot = viewRoot; mImeBackAnimationController = imeBackAnimationController; if (!mAllCallbacks.isEmpty()) { setTopOnBackInvokedCallback(getTopCallback()); @@ -151,6 +156,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { clear(); mWindow = null; mWindowSession = null; + mViewRoot = null; mImeBackAnimationController = null; } } @@ -176,8 +182,6 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { return; } if (callback instanceof ImeOnBackInvokedDispatcher.ImeOnBackInvokedCallback) { - // Fall back to compat back key injection if legacy back behaviour should be used. - if (!isOnBackInvokedCallbackEnabled()) return; if (callback instanceof ImeOnBackInvokedDispatcher.DefaultImeOnBackAnimationCallback && mImeBackAnimationController != null) { // register ImeBackAnimationController instead to play predictive back animation @@ -300,6 +304,14 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { } } + private boolean callOnKeyPreIme() { + if (mViewRoot != null && !isOnBackInvokedCallbackEnabled(mViewRoot.mContext)) { + return mViewRoot.injectBackKeyEvents(/*preImeOnly*/ true); + } else { + return false; + } + } + private void setTopOnBackInvokedCallback(@Nullable OnBackInvokedCallback callback) { if (mWindowSession == null || mWindow == null) { return; @@ -308,8 +320,8 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { OnBackInvokedCallbackInfo callbackInfo = null; if (callback != null) { int priority = mAllCallbacks.get(callback); - final IOnBackInvokedCallback iCallback = new OnBackInvokedCallbackWrapper( - callback, mTouchTracker, mProgressAnimator, mHandler); + final IOnBackInvokedCallback iCallback = new OnBackInvokedCallbackWrapper(callback, + mTouchTracker, mProgressAnimator, mHandler, this::callOnKeyPreIme); callbackInfo = new OnBackInvokedCallbackInfo( iCallback, priority, @@ -399,16 +411,20 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { private final BackTouchTracker mTouchTracker; @NonNull private final Handler mHandler; + @NonNull + private final BooleanSupplier mOnKeyPreIme; OnBackInvokedCallbackWrapper( @NonNull OnBackInvokedCallback callback, @NonNull BackTouchTracker touchTracker, @NonNull BackProgressAnimator progressAnimator, - @NonNull Handler handler) { + @NonNull Handler handler, + @NonNull BooleanSupplier onKeyPreIme) { mCallback = new WeakReference<>(callback); mTouchTracker = touchTracker; mProgressAnimator = progressAnimator; mHandler = handler; + mOnKeyPreIme = onKeyPreIme; } @Override @@ -451,11 +467,11 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { public void onBackInvoked() throws RemoteException { mHandler.post(() -> { mTouchTracker.reset(); + if (consumedByOnKeyPreIme()) return; boolean isInProgress = mProgressAnimator.isBackAnimationInProgress(); - mProgressAnimator.reset(); - // TODO(b/333957271): Re-introduce auto fling progress generation. final OnBackInvokedCallback callback = mCallback.get(); if (callback == null) { + mProgressAnimator.reset(); Log.d(TAG, "Trying to call onBackInvoked() on a null callback reference."); return; } @@ -463,10 +479,40 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { Log.w(TAG, "ProgressAnimator was not in progress, skip onBackInvoked()."); return; } - callback.onBackInvoked(); + OnBackAnimationCallback animationCallback = getBackAnimationCallback(); + if (animationCallback != null) { + mProgressAnimator.onBackInvoked(callback::onBackInvoked); + } else { + mProgressAnimator.reset(); + callback.onBackInvoked(); + } }); } + private boolean consumedByOnKeyPreIme() { + final OnBackInvokedCallback callback = mCallback.get(); + if (callback instanceof ImeBackAnimationController + || callback instanceof ImeOnBackInvokedDispatcher.ImeOnBackInvokedCallback) { + // call onKeyPreIme API if the current callback is an IME callback and the app has + // not set enableOnBackInvokedCallback="false" + try { + boolean consumed = mOnKeyPreIme.getAsBoolean(); + if (consumed) { + // back event intercepted by app in onKeyPreIme -> cancel the IME animation. + final OnBackAnimationCallback animationCallback = + getBackAnimationCallback(); + if (animationCallback != null) { + mProgressAnimator.onBackCancelled(animationCallback::onBackCancelled); + } + return true; + } + } catch (Exception e) { + Log.d(TAG, "Failed to call onKeyPreIme", e); + } + } + return false; + } + @Override public void setTriggerBack(boolean triggerBack) throws RemoteException { mTouchTracker.setTriggerBack(triggerBack); @@ -504,6 +550,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { public void setImeOnBackInvokedDispatcher( @NonNull ImeOnBackInvokedDispatcher imeDispatcher) { mImeDispatcher = imeDispatcher; + mImeDispatcher.setHandler(mHandler); } /** Returns true if a non-null {@link ImeOnBackInvokedDispatcher} has been set. **/ diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig index 0590c407d7e4..daf2fe345ffd 100644 --- a/core/java/android/window/flags/lse_desktop_experience.aconfig +++ b/core/java/android/window/flags/lse_desktop_experience.aconfig @@ -52,6 +52,13 @@ flag { } flag { + name: "enable_desktop_windowing_scvh_cache" + namespace: "lse_desktop_experience" + description: "Enables a SurfaceControlViewHost cache for window decorations" + bug: "345146928" +} + +flag { name: "enable_desktop_windowing_wallpaper_activity" namespace: "lse_desktop_experience" description: "Enables desktop wallpaper activity to show wallpaper in the desktop mode" @@ -92,3 +99,10 @@ flag { description: "Makes the App Header style adapt to the system's and app's light/dark theme" bug: "328668781" } + +flag { + name: "enable_camera_compat_for_desktop_windowing" + namespace: "lse_desktop_experience" + description: "Whether to apply Camera Compat treatment to fixed-orientation apps in desktop windowing mode" + bug: "314952133" +} diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index d6f65f8c9d8b..b71468247e37 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -19,6 +19,16 @@ flag { } flag { + name: "blast_sync_notification_shade_on_display_switch" + namespace: "windowing_frontend" + description: "Make the buffer content of notification shade synchronize with display switch" + bug: "337154331" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "edge_to_edge_by_default" namespace: "windowing_frontend" description: "Make app go edge-to-edge by default when targeting SDK 35 or greater" diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java index 71bbccb3d989..b8f7a3d0231a 100644 --- a/core/java/com/android/internal/app/PlatLogoActivity.java +++ b/core/java/com/android/internal/app/PlatLogoActivity.java @@ -69,7 +69,7 @@ public class PlatLogoActivity extends Activity { private static final long LAUNCH_TIME = 5000L; - private static final String U_EGG_UNLOCK_SETTING = "egg_mode_u"; + private static final String EGG_UNLOCK_SETTING = "egg_mode_v"; private static final float MIN_WARP = 1f; private static final float MAX_WARP = 10f; // after all these years @@ -309,13 +309,12 @@ public class PlatLogoActivity extends Activity { private void launchNextStage(boolean locked) { final ContentResolver cr = getContentResolver(); - try { if (shouldWriteSettings()) { Log.v(TAG, "Saving egg locked=" + locked); syncTouchPressure(); Settings.System.putLong(cr, - U_EGG_UNLOCK_SETTING, + EGG_UNLOCK_SETTING, locked ? 0 : System.currentTimeMillis()); } } catch (RuntimeException e) { @@ -499,4 +498,4 @@ public class PlatLogoActivity extends Activity { mDt = dt; } } -}
\ No newline at end of file +} diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 98d6ec6897a6..920981e2b8fe 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -923,7 +923,7 @@ public class ResolverActivity extends Activity implements mSystemWindowInsets = insets.getSystemWindowInsets(); mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top, - mSystemWindowInsets.right, mSystemWindowInsets.bottom); + mSystemWindowInsets.right, 0); resetButtonBar(); @@ -952,7 +952,7 @@ public class ResolverActivity extends Activity implements if (mSystemWindowInsets != null) { mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top, - mSystemWindowInsets.right, mSystemWindowInsets.bottom); + mSystemWindowInsets.right, 0); } } diff --git a/core/java/com/android/internal/dynamicanimation/animation/FlingAnimation.java b/core/java/com/android/internal/dynamicanimation/animation/FlingAnimation.java new file mode 100644 index 000000000000..2bd0568c3af5 --- /dev/null +++ b/core/java/com/android/internal/dynamicanimation/animation/FlingAnimation.java @@ -0,0 +1,203 @@ +/* + * 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.dynamicanimation.animation; + +import android.annotation.FloatRange; +/** + * <p>Fling animation is an animation that continues an initial momentum (most often from gesture + * velocity) and gradually slows down. The fling animation will come to a stop when the velocity of + * the animation is below the threshold derived from {@link #setMinimumVisibleChange(float)}, + * or when the value of the animation has gone beyond the min or max value defined via + * {@link DynamicAnimation#setMinValue(float)} or {@link DynamicAnimation#setMaxValue(float)}. + * It is recommended to restrict the fling animation with min and/or max value, such that the + * animation can end when it goes beyond screen bounds, thus preserving CPU cycles and resources. + * + * <p>For example, you can create a fling animation that animates the translationX of a view: + * <pre class="prettyprint"> + * FlingAnimation flingAnim = new FlingAnimation(view, DynamicAnimation.TRANSLATION_X) + * // Sets the start velocity to -2000 (pixel/s) + * .setStartVelocity(-2000) + * // Optional but recommended to set a reasonable min and max range for the animation. + * // In this particular case, we set the min and max to -200 and 2000 respectively. + * .setMinValue(-200).setMaxValue(2000); + * flingAnim.start(); + * </pre> + */ +public final class FlingAnimation extends DynamicAnimation<FlingAnimation> { + private final DragForce mFlingForce = new DragForce(); + /** + * <p>This creates a FlingAnimation that animates a {@link FloatValueHolder} instance. During + * the animation, the {@link FloatValueHolder} instance will be updated via + * {@link FloatValueHolder#setValue(float)} each frame. The caller can obtain the up-to-date + * animation value via {@link FloatValueHolder#getValue()}. + * + * <p><strong>Note:</strong> changing the value in the {@link FloatValueHolder} via + * {@link FloatValueHolder#setValue(float)} outside of the animation during an + * animation run will not have any effect on the on-going animation. + * + * @param floatValueHolder the property to be animated + */ + public FlingAnimation(FloatValueHolder floatValueHolder) { + super(floatValueHolder); + mFlingForce.setValueThreshold(getValueThreshold()); + } + /** + * Sets the friction for the fling animation. The greater the friction is, the sooner the + * animation will slow down. When not set, the friction defaults to 1. + * + * @param friction the friction used in the animation + * @return the animation whose friction will be scaled + * @throws IllegalArgumentException if the input friction is not positive + */ + public FlingAnimation setFriction( + @FloatRange(from = 0.0, fromInclusive = false) float friction) { + if (friction <= 0) { + throw new IllegalArgumentException("Friction must be positive"); + } + mFlingForce.setFrictionScalar(friction); + return this; + } + /** + * Returns the friction being set on the animation via {@link #setFriction(float)}. If the + * friction has not been set, the default friction of 1 will be returned. + * + * @return friction being used in the animation + */ + public float getFriction() { + return mFlingForce.getFrictionScalar(); + } + /** + * Sets the min value of the animation. When a fling animation reaches the min value, the + * animation will end immediately. Animations will not animate beyond the min value. + * + * @param minValue minimum value of the property to be animated + * @return the Animation whose min value is being set + */ + @Override + public FlingAnimation setMinValue(float minValue) { + super.setMinValue(minValue); + return this; + } + /** + * Sets the max value of the animation. When a fling animation reaches the max value, the + * animation will end immediately. Animations will not animate beyond the max value. + * + * @param maxValue maximum value of the property to be animated + * @return the Animation whose max value is being set + */ + @Override + public FlingAnimation setMaxValue(float maxValue) { + super.setMaxValue(maxValue); + return this; + } + /** + * Start velocity of the animation. Default velocity is 0. Unit: pixel/second + * + * <p>A <b>non-zero</b> start velocity is required for a FlingAnimation. If no start velocity is + * set through {@link #setStartVelocity(float)}, the start velocity defaults to 0. In that + * case, the fling animation will consider itself done in the next frame. + * + * <p>Note when using a fixed value as the start velocity (as opposed to getting the velocity + * through touch events), it is recommended to define such a value in dp/second and convert it + * to pixel/second based on the density of the screen to achieve a consistent look across + * different screens. + * + * <p>To convert from dp/second to pixel/second: + * <pre class="prettyprint"> + * float pixelPerSecond = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, + * getResources().getDisplayMetrics()); + * </pre> + * + * @param startVelocity start velocity of the animation in pixel/second + * @return the Animation whose start velocity is being set + */ + @Override + public FlingAnimation setStartVelocity(float startVelocity) { + super.setStartVelocity(startVelocity); + return this; + } + @Override + boolean updateValueAndVelocity(long deltaT) { + MassState state = mFlingForce.updateValueAndVelocity(mValue, mVelocity, deltaT); + mValue = state.mValue; + mVelocity = state.mVelocity; + // When the animation hits the max/min value, consider animation done. + if (mValue < mMinValue) { + mValue = mMinValue; + return true; + } + if (mValue > mMaxValue) { + mValue = mMaxValue; + return true; + } + if (isAtEquilibrium(mValue, mVelocity)) { + return true; + } + return false; + } + @Override + float getAcceleration(float value, float velocity) { + return mFlingForce.getAcceleration(value, velocity); + } + @Override + boolean isAtEquilibrium(float value, float velocity) { + return value >= mMaxValue + || value <= mMinValue + || mFlingForce.isAtEquilibrium(value, velocity); + } + @Override + void setValueThreshold(float threshold) { + mFlingForce.setValueThreshold(threshold); + } + private static final class DragForce implements Force { + private static final float DEFAULT_FRICTION = -4.2f; + // This multiplier is used to calculate the velocity threshold given a certain value + // threshold. The idea is that if it takes >= 1 frame to move the value threshold amount, + // then the velocity is a reasonable threshold. + private static final float VELOCITY_THRESHOLD_MULTIPLIER = 1000f / 16f; + private float mFriction = DEFAULT_FRICTION; + private float mVelocityThreshold; + // Internal state to hold a value/velocity pair. + private final DynamicAnimation.MassState mMassState = new DynamicAnimation.MassState(); + void setFrictionScalar(float frictionScalar) { + mFriction = frictionScalar * DEFAULT_FRICTION; + } + float getFrictionScalar() { + return mFriction / DEFAULT_FRICTION; + } + MassState updateValueAndVelocity(float value, float velocity, long deltaT) { + mMassState.mVelocity = (float) (velocity * Math.exp((deltaT / 1000f) * mFriction)); + mMassState.mValue = (float) (value - velocity / mFriction + + velocity / mFriction * Math.exp(mFriction * deltaT / 1000f)); + if (isAtEquilibrium(mMassState.mValue, mMassState.mVelocity)) { + mMassState.mVelocity = 0f; + } + return mMassState; + } + @Override + public float getAcceleration(float position, float velocity) { + return velocity * mFriction; + } + @Override + public boolean isAtEquilibrium(float value, float velocity) { + return Math.abs(velocity) < mVelocityThreshold; + } + void setValueThreshold(float threshold) { + mVelocityThreshold = threshold * VELOCITY_THRESHOLD_MULTIPLIER; + } + } +} + diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java index 244165f5e814..5c270e0e874c 100644 --- a/core/java/com/android/internal/os/BatteryStatsHistory.java +++ b/core/java/com/android/internal/os/BatteryStatsHistory.java @@ -1514,6 +1514,36 @@ public class BatteryStatsHistory { } /** + * Records an event when some state2 flag changes to true. + */ + public void recordState2StartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags, + int uid, String name) { + synchronized (this) { + mHistoryCur.states2 |= stateFlags; + mHistoryCur.eventCode = EVENT_STATE_CHANGE | EVENT_FLAG_START; + mHistoryCur.eventTag = mHistoryCur.localEventTag; + mHistoryCur.eventTag.uid = uid; + mHistoryCur.eventTag.string = name; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + } + + /** + * Records an event when some state2 flag changes to false. + */ + public void recordState2StopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags, + int uid, String name) { + synchronized (this) { + mHistoryCur.states2 &= ~stateFlags; + mHistoryCur.eventCode = EVENT_STATE_CHANGE | EVENT_FLAG_FINISH; + mHistoryCur.eventTag = mHistoryCur.localEventTag; + mHistoryCur.eventTag.uid = uid; + mHistoryCur.eventTag.string = name; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + } + + /** * Records an event when some state2 flag changes to false. */ public void recordState2StopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) { diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java index f2783c4215c8..bb3507caf7f4 100644 --- a/core/java/com/android/internal/protolog/ProtoLogGroup.java +++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java @@ -18,6 +18,8 @@ package com.android.internal.protolog; import com.android.internal.protolog.common.IProtoLogGroup; +import java.util.UUID; + /** * Defines logging groups for ProtoLog. * @@ -153,10 +155,18 @@ public enum ProtoLogGroup implements IProtoLogGroup { this.mLogToLogcat = logToLogcat; } + @Override + public int getId() { + return Consts.START_ID + this.ordinal(); + } + private static class Consts { private static final String TAG_WM = "WindowManager"; private static final boolean ENABLE_DEBUG = true; private static final boolean ENABLE_LOG_TO_PROTO_DEBUG = true; + private static final int START_ID = (int) ( + UUID.nameUUIDFromBytes(ProtoLogGroup.class.getName().getBytes()) + .getMostSignificantBits() % Integer.MAX_VALUE); } } diff --git a/core/java/com/android/internal/protolog/common/IProtoLogGroup.java b/core/java/com/android/internal/protolog/common/IProtoLogGroup.java index 149aa7aa7170..91b24fdab869 100644 --- a/core/java/com/android/internal/protolog/common/IProtoLogGroup.java +++ b/core/java/com/android/internal/protolog/common/IProtoLogGroup.java @@ -64,4 +64,9 @@ public interface IProtoLogGroup { * returns name of the logging group. */ String name(); + + /** + * returns the id of the logging group (unique for each group). + */ + int getId(); } diff --git a/core/java/com/android/internal/statusbar/StatusBarIcon.java b/core/java/com/android/internal/statusbar/StatusBarIcon.java index 4f80afaab696..76ce452858ad 100644 --- a/core/java/com/android/internal/statusbar/StatusBarIcon.java +++ b/core/java/com/android/internal/statusbar/StatusBarIcon.java @@ -22,7 +22,21 @@ import android.os.Parcelable; import android.os.UserHandle; import android.text.TextUtils; +import androidx.annotation.NonNull; + public class StatusBarIcon implements Parcelable { + public enum Type { + // Notification: the sender avatar for important conversations + PeopleAvatar, + // Notification: the monochrome version of the app icon if available; otherwise fall back to + // the small icon + MaybeMonochromeAppIcon, + // Notification: the small icon from the notification + NotifSmallIcon, + // The wi-fi, cellular or battery icon. + SystemIcon + } + public UserHandle user; public String pkg; public Icon icon; @@ -30,9 +44,10 @@ public class StatusBarIcon implements Parcelable { public boolean visible = true; public int number; public CharSequence contentDescription; + public Type type; public StatusBarIcon(UserHandle user, String resPackage, Icon icon, int iconLevel, int number, - CharSequence contentDescription) { + CharSequence contentDescription, Type type) { if (icon.getType() == Icon.TYPE_RESOURCE && TextUtils.isEmpty(icon.getResPackage())) { // This is an odd situation where someone's managed to hand us an icon without a @@ -46,15 +61,17 @@ public class StatusBarIcon implements Parcelable { this.iconLevel = iconLevel; this.number = number; this.contentDescription = contentDescription; + this.type = type; } public StatusBarIcon(String iconPackage, UserHandle user, int iconId, int iconLevel, int number, - CharSequence contentDescription) { + CharSequence contentDescription, Type type) { this(user, iconPackage, Icon.createWithResource(iconPackage, iconId), - iconLevel, number, contentDescription); + iconLevel, number, contentDescription, type); } + @NonNull @Override public String toString() { return "StatusBarIcon(icon=" + icon @@ -65,10 +82,11 @@ public class StatusBarIcon implements Parcelable { + " )"; } + @NonNull @Override public StatusBarIcon clone() { StatusBarIcon that = new StatusBarIcon(this.user, this.pkg, this.icon, - this.iconLevel, this.number, this.contentDescription); + this.iconLevel, this.number, this.contentDescription, this.type); that.visible = this.visible; return that; } @@ -88,6 +106,7 @@ public class StatusBarIcon implements Parcelable { this.visible = in.readInt() != 0; this.number = in.readInt(); this.contentDescription = in.readCharSequence(); + this.type = Type.valueOf(in.readString()); } public void writeToParcel(Parcel out, int flags) { @@ -98,6 +117,7 @@ public class StatusBarIcon implements Parcelable { out.writeInt(this.visible ? 1 : 0); out.writeInt(this.number); out.writeCharSequence(this.contentDescription); + out.writeString(this.type.name()); } public int describeContents() { diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java index eef33684e883..606e038a1a4b 100644 --- a/core/java/com/android/internal/widget/ActionBarContainer.java +++ b/core/java/com/android/internal/widget/ActionBarContainer.java @@ -93,8 +93,7 @@ public class ActionBarContainer extends FrameLayout { if (bg != null) { bg.setCallback(this); if (mActionBarView != null) { - mBackground.setBounds(mActionBarView.getLeft(), mActionBarView.getTop(), - mActionBarView.getRight(), mActionBarView.getBottom()); + bg.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); } } setWillNotDraw(mIsSplit ? mSplitBackground == null : @@ -293,6 +292,7 @@ public class ActionBarContainer extends FrameLayout { if (mActionBarView == null) return; if (mTabContainer != null && mTabContainer.getVisibility() != GONE) { + final int verticalPadding = getPaddingTop() + getPaddingBottom(); int nonTabMaxHeight = 0; final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { @@ -307,7 +307,9 @@ public class ActionBarContainer extends FrameLayout { final int maxHeight = mode == MeasureSpec.AT_MOST ? MeasureSpec.getSize(heightMeasureSpec) : Integer.MAX_VALUE; setMeasuredDimension(getMeasuredWidth(), - Math.min(nonTabMaxHeight + getMeasuredHeightWithMargins(mTabContainer), + Math.min( + verticalPadding + nonTabMaxHeight + + getMeasuredHeightWithMargins(mTabContainer), maxHeight)); } } @@ -335,13 +337,9 @@ public class ActionBarContainer extends FrameLayout { } } else { if (mBackground != null) { - if (mActionBarView.getVisibility() == View.VISIBLE) { - mBackground.setBounds(mActionBarView.getLeft(), mActionBarView.getTop(), - mActionBarView.getRight(), mActionBarView.getBottom()); - } else if (mActionContextView != null && - mActionContextView.getVisibility() == View.VISIBLE) { - mBackground.setBounds(mActionContextView.getLeft(), mActionContextView.getTop(), - mActionContextView.getRight(), mActionContextView.getBottom()); + if ((mActionBarView.getVisibility() == View.VISIBLE) || (mActionContextView != null + && mActionContextView.getVisibility() == View.VISIBLE)) { + mBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); } else { mBackground.setBounds(0, 0, 0, 0); } diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java index 0992db91356d..68328252abaf 100644 --- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java +++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java @@ -24,6 +24,7 @@ import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.content.res.TypedArray; import android.graphics.Canvas; +import android.graphics.Insets; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Build; @@ -51,6 +52,7 @@ import com.android.internal.view.menu.MenuPresenter; */ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentParent { private static final String TAG = "ActionBarOverlayLayout"; + private static final Rect EMPTY_RECT = new Rect(); private int mActionBarHeight; //private WindowDecorActionBar mActionBar; @@ -77,10 +79,13 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar private final Rect mBaseContentInsets = new Rect(); private final Rect mLastBaseContentInsets = new Rect(); private final Rect mContentInsets = new Rect(); + private final Rect mSystemInsets = new Rect(); private WindowInsets mBaseInnerInsets = WindowInsets.CONSUMED; private WindowInsets mLastBaseInnerInsets = WindowInsets.CONSUMED; private WindowInsets mInnerInsets = WindowInsets.CONSUMED; private WindowInsets mLastInnerInsets = WindowInsets.CONSUMED; + private boolean mDecorFitsSystemWindows = true; + private boolean mActionBarExtendsIntoSystemInsets = false; private ActionBarVisibilityCallback mActionBarVisibilityCallback; @@ -268,7 +273,8 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar // We want the bar to be visible if it is not being hidden, // or the app has not turned on a stable UI mode (meaning they // are performing explicit layout around the action bar). - mActionBarVisibilityCallback.enableContentAnimations(!stable); + mActionBarVisibilityCallback.enableContentAnimations( + !stable && !mActionBarExtendsIntoSystemInsets); if (barVisible || !stable) mActionBarVisibilityCallback.showForSystem(); else mActionBarVisibilityCallback.hideForSystem(); } @@ -288,10 +294,39 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar } } - private boolean applyInsets(View view, Rect insets, boolean left, boolean top, - boolean bottom, boolean right) { + private boolean applyInsets(View view, Rect insets, boolean toPadding, + boolean left, boolean top, boolean right, boolean bottom) { + boolean changed; + if (toPadding) { + changed = setMargin(view, EMPTY_RECT, left, top, right, bottom); + changed |= setPadding(view, insets, left, top, right, bottom); + } else { + changed = setPadding(view, EMPTY_RECT, left, top, right, bottom); + changed |= setMargin(view, insets, left, top, right, bottom); + } + return changed; + } + + private boolean setPadding(View view, Rect insets, + boolean left, boolean top, boolean right, boolean bottom) { + if ((left && view.getPaddingLeft() != insets.left) + || (top && view.getPaddingTop() != insets.top) + || (right && view.getPaddingRight() != insets.right) + || (bottom && view.getPaddingBottom() != insets.bottom)) { + view.setPadding( + left ? insets.left : view.getPaddingLeft(), + top ? insets.top : view.getPaddingTop(), + right ? insets.right : view.getPaddingRight(), + bottom ? insets.bottom : view.getPaddingBottom()); + return true; + } + return false; + } + + private boolean setMargin(View view, Rect insets, + boolean left, boolean top, boolean right, boolean bottom) { + final LayoutParams lp = (LayoutParams) view.getLayoutParams(); boolean changed = false; - LayoutParams lp = (LayoutParams)view.getLayoutParams(); if (left && lp.leftMargin != insets.left) { changed = true; lp.leftMargin = insets.left; @@ -316,12 +351,28 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar pullChildren(); final int vis = getWindowSystemUiVisibility(); - final Rect systemInsets = insets.getSystemWindowInsetsAsRect(); + final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0; + final boolean layoutIntoSystemInsets = (vis & SYSTEM_UI_LAYOUT_FLAGS) != 0; + mDecorFitsSystemWindows = hasContentOnApplyWindowInsetsListener(); + + // Only extend action bar into system insets area if the app doesn't fit system insets. + mActionBarExtendsIntoSystemInsets = + !mDecorFitsSystemWindows || (stable && layoutIntoSystemInsets); + + if (mActionBarVisibilityCallback != null) { + mActionBarVisibilityCallback.enableContentAnimations( + !stable && !mActionBarExtendsIntoSystemInsets); + } + + final Insets sysInsets = insets.getSystemWindowInsets(); + mSystemInsets.set(sysInsets.left, sysInsets.top, sysInsets.right, sysInsets.bottom); // The top and bottom action bars are always within the content area. - boolean changed = applyInsets(mActionBarTop, systemInsets, true, true, false, true); + boolean changed = applyInsets(mActionBarTop, mSystemInsets, + mActionBarExtendsIntoSystemInsets, true, true, true, false); if (mActionBarBottom != null) { - changed |= applyInsets(mActionBarBottom, systemInsets, true, false, true, true); + changed |= applyInsets(mActionBarBottom, mSystemInsets, + mActionBarExtendsIntoSystemInsets, true, false, true, true); } // Cannot use the result of computeSystemWindowInsets, because that consumes the @@ -406,6 +457,9 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar // This is the standard space needed for the action bar. For stable measurement, // we can't depend on the size currently reported by it -- this must remain constant. topInset = mActionBarHeight; + if (mActionBarExtendsIntoSystemInsets) { + topInset += mSystemInsets.top; + } if (mHasNonEmbeddedTabs) { final View tabs = mActionBarTop.getTabContainer(); if (tabs != null) { @@ -424,6 +478,9 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar if (mActionBarBottom != null) { if (stable) { bottomInset = mActionBarHeight; + if (mActionBarExtendsIntoSystemInsets) { + bottomInset += mSystemInsets.bottom; + } } else { bottomInset = mActionBarBottom.getMeasuredHeight(); } @@ -436,21 +493,35 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar // overlay. mContentInsets.set(mBaseContentInsets); mInnerInsets = mBaseInnerInsets; - if (!mOverlayMode && !stable && hasContentOnApplyWindowInsetsListener()) { - mContentInsets.top += topInset; - mContentInsets.bottom += bottomInset; + if (!mOverlayMode && !stable && mDecorFitsSystemWindows) { + if (mActionBarExtendsIntoSystemInsets) { + mContentInsets.top = Math.max(mContentInsets.top, topInset); + mContentInsets.bottom = Math.max(mContentInsets.bottom, bottomInset); + } else { + mContentInsets.top += topInset; + mContentInsets.bottom += bottomInset; + } // Content view has been shrunk, shrink all insets to match. mInnerInsets = mInnerInsets.inset(0 /* left */, topInset, 0 /* right */, bottomInset); } else { // Add ActionBar to system window inset, but leave other insets untouched. - mInnerInsets = mInnerInsets.replaceSystemWindowInsets( - mInnerInsets.getSystemWindowInsetLeft(), - mInnerInsets.getSystemWindowInsetTop() + topInset, - mInnerInsets.getSystemWindowInsetRight(), - mInnerInsets.getSystemWindowInsetBottom() + bottomInset - ); - } - applyInsets(mContent, mContentInsets, true, true, true, true); + if (mActionBarExtendsIntoSystemInsets) { + mInnerInsets = mInnerInsets.replaceSystemWindowInsets( + mInnerInsets.getSystemWindowInsetLeft(), + Math.max(mInnerInsets.getSystemWindowInsetTop(), topInset), + mInnerInsets.getSystemWindowInsetRight(), + Math.max(mInnerInsets.getSystemWindowInsetBottom(), bottomInset) + ); + } else { + mInnerInsets = mInnerInsets.replaceSystemWindowInsets( + mInnerInsets.getSystemWindowInsetLeft(), + mInnerInsets.getSystemWindowInsetTop() + topInset, + mInnerInsets.getSystemWindowInsetRight(), + mInnerInsets.getSystemWindowInsetBottom() + bottomInset + ); + } + } + setMargin(mContent, mContentInsets, true, true, true, true); if (!mLastInnerInsets.equals(mInnerInsets)) { // If the inner insets have changed, we need to dispatch this down to diff --git a/core/jni/android_database_SQLiteRawStatement.cpp b/core/jni/android_database_SQLiteRawStatement.cpp index 8fc13a82e74e..961486474821 100644 --- a/core/jni/android_database_SQLiteRawStatement.cpp +++ b/core/jni/android_database_SQLiteRawStatement.cpp @@ -83,6 +83,16 @@ static void throwIfInvalidColumn(JNIEnv *env, jlong stmtPtr, jint col) { } } +// If the last operation failed, throw an exception and return true. Otherwise return false. +static bool throwIfError(JNIEnv *env, jlong stmtPtr) { + switch (sqlite3_errcode(db(stmtPtr))) { + case SQLITE_OK: + case SQLITE_DONE: + case SQLITE_ROW: return false; + } + throw_sqlite3_exception(env, db(stmtPtr), nullptr); + return true; +} static jint bindParameterCount(JNIEnv* env, jclass, jlong stmtPtr) { return sqlite3_bind_parameter_count(stmt(stmtPtr)); @@ -223,17 +233,24 @@ static jstring columnName(JNIEnv* env, jclass, jlong stmtPtr, jint col) { static jint columnBytes(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); - return sqlite3_column_bytes16(stmt(stmtPtr), col); + int r = sqlite3_column_bytes16(stmt(stmtPtr), col); + throwIfError(env, stmtPtr); + return r; } - static jbyteArray columnBlob(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); const void* blob = sqlite3_column_blob(stmt(stmtPtr), col); if (blob == nullptr) { + if (throwIfError(env, stmtPtr)) { + return NULL; + } return (sqlite3_column_type(stmt(stmtPtr), col) == SQLITE_NULL) ? NULL : emptyArray; } size_t size = sqlite3_column_bytes(stmt(stmtPtr), col); + if (throwIfError(env, stmtPtr)) { + return NULL; + } jbyteArray result = env->NewByteArray(size); if (result == nullptr) { // An OutOfMemory exception will have been thrown. @@ -248,9 +265,13 @@ static int columnBuffer(JNIEnv* env, jclass, jlong stmtPtr, jint col, throwIfInvalidColumn(env, stmtPtr, col); const void* blob = sqlite3_column_blob(stmt(stmtPtr), col); if (blob == nullptr) { + throwIfError(env, stmtPtr); return 0; } jsize bsize = sqlite3_column_bytes(stmt(stmtPtr), col); + if (throwIfError(env, stmtPtr)) { + return 0; + } if (bsize == 0 || bsize <= srcOffset) { return 0; } @@ -278,9 +299,13 @@ static jstring columnText(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); const jchar* text = static_cast<const jchar*>(sqlite3_column_text16(stmt(stmtPtr), col)); if (text == nullptr) { + throwIfError(env, stmtPtr); return NULL; } size_t length = sqlite3_column_bytes16(stmt(stmtPtr), col) / sizeof(jchar); + if (throwIfError(env, stmtPtr)) { + return NULL; + } return env->NewString(text, length); } diff --git a/core/jni/android_tracing_PerfettoDataSource.cpp b/core/jni/android_tracing_PerfettoDataSource.cpp index 17129d8913d7..fec28987e7e6 100644 --- a/core/jni/android_tracing_PerfettoDataSource.cpp +++ b/core/jni/android_tracing_PerfettoDataSource.cpp @@ -245,7 +245,6 @@ static jlong nativeGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) { } void nativeWritePackets(JNIEnv* env, jclass clazz, jlong ds_ptr, jobjectArray packets) { - ALOG(LOG_DEBUG, LOG_TAG, "nativeWritePackets(%p)", (void*)ds_ptr); sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(ds_ptr); datasource->WritePackets(env, packets); } diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index 9b8dab78b342..fba0d81d431f 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -115,7 +115,8 @@ sumFiles(JNIEnv*, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char size_t* total = (size_t*) arg; uint32_t uncompLen; - if (!zipFile->getEntryInfo(zipEntry, nullptr, &uncompLen, nullptr, nullptr, nullptr, nullptr)) { + if (!zipFile->getEntryInfo(zipEntry, nullptr, &uncompLen, nullptr, nullptr, nullptr, nullptr, + nullptr)) { return INSTALL_FAILED_INVALID_APK; } diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 8e4addd6f331..0eb7c4aee287 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -49,6 +49,9 @@ static const char* kPathAllowlist[] = { "/dev/dri/renderD129", // Fixes b/31172436 "/dev/stune/foreground/tasks", "/dev/blkio/tasks", + "/metadata/aconfig/maps/system.package.map", + "/metadata/aconfig/maps/system.flag.map", + "/metadata/aconfig/boot/system.val" }; static const char kFdPath[] = "/proc/self/fd"; diff --git a/core/proto/android/nfc/apdu_service_info.proto b/core/proto/android/nfc/apdu_service_info.proto index fd110c44483c..9efdfcbea3d3 100644 --- a/core/proto/android/nfc/apdu_service_info.proto +++ b/core/proto/android/nfc/apdu_service_info.proto @@ -27,6 +27,20 @@ option java_multiple_files = true; message ApduServiceInfoProto { option (.android.msg_privacy).dest = DEST_EXPLICIT; + message AutoTransactMapping { + option (.android.msg_privacy).dest = DEST_EXPLICIT; + + optional string aid = 1; + optional bool should_auto_transact = 2; + } + + message AutoTransactPattern { + option (.android.msg_privacy).dest = DEST_EXPLICIT; + + optional string regexp_pattern = 1; + optional bool should_auto_transact = 2; + } + optional .android.content.ComponentNameProto component_name = 1; optional string description = 2; optional bool on_host = 3; @@ -35,4 +49,7 @@ message ApduServiceInfoProto { repeated AidGroupProto static_aid_groups = 6; repeated AidGroupProto dynamic_aid_groups = 7; optional string settings_activity_name = 8; + optional bool should_default_to_observe_mode = 9; + repeated AutoTransactMapping auto_transact_mapping = 10; + repeated AutoTransactPattern auto_transact_patterns = 11; } diff --git a/core/proto/android/nfc/card_emulation.proto b/core/proto/android/nfc/card_emulation.proto index 9c3c6d704922..81da30dd8bbf 100644 --- a/core/proto/android/nfc/card_emulation.proto +++ b/core/proto/android/nfc/card_emulation.proto @@ -59,6 +59,7 @@ message PreferredServicesProto { optional .android.content.ComponentNameProto foreground_requested = 5; optional .android.content.ComponentNameProto settings_default = 6; optional bool prefer_foreground = 7; + optional .android.content.ComponentNameProto wallet_role_holder_payment_service = 8; } // Debugging information for com.android.nfc.cardemulation.EnabledNfcFServices diff --git a/core/proto/android/providers/settings/system.proto b/core/proto/android/providers/settings/system.proto index 5fc2a59e3028..123306924c2b 100644 --- a/core/proto/android/providers/settings/system.proto +++ b/core/proto/android/providers/settings/system.proto @@ -122,6 +122,12 @@ message SystemSettingsProto { } optional Notification notification = 17; + message Pointer { + option (android.msg_privacy).dest = DEST_EXPLICIT; + + optional SettingProto pointer_fill_style = 1 [ (android.privacy).dest = DEST_AUTOMATIC ]; + } + optional Pointer pointer = 37; optional SettingProto pointer_speed = 18 [ (android.privacy).dest = DEST_AUTOMATIC ]; message Ringtone { @@ -268,5 +274,5 @@ message SystemSettingsProto { // Please insert fields in alphabetical order and group them into messages // if possible (to avoid reaching the method limit). - // Next tag = 37; + // Next tag = 38; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 6dbe44b483d2..09ffdf3d4e4c 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -8351,7 +8351,7 @@ <activity android:name="android.accounts.GrantCredentialsPermissionActivity" android:excludeFromRecents="true" android:exported="true" - android:theme="@style/Theme.DeviceDefault.Light.DialogWhenLarge" + android:theme="@style/GrantCredentialsPermissionActivity" android:process=":ui" android:visibleToInstantApps="true"> </activity> diff --git a/core/res/res/drawable/pointer_alias_vector.xml b/core/res/res/drawable/pointer_alias_vector.xml index 74dd6a0b2a23..035a099cf632 100644 --- a/core/res/res/drawable/pointer_alias_vector.xml +++ b/core/res/res/drawable/pointer_alias_vector.xml @@ -28,6 +28,6 @@ android:fillColor="#FFFFFF" android:pathData="M15.313 12.177a3 3 0 0 0-.416-.633l-.459-.534-.353.609a4.2 4.2 0 0 1-1.801 1.675 4.2 4.2 0 0 1-1.977.429l-.704-.02.213.671q.066.208.164.409l.975 1.995a2.967 2.967 0 1 0 5.332-2.606zm-.827 5.066a1.97 1.97 0 0 1-2.632-.904l-.81-1.658a5.2 5.2 0 0 0 1.68-.489 5.2 5.2 0 0 0 1.771-1.414l.896 1.833a1.97 1.97 0 0 1-.905 2.632m-3.697-7.565a4.2 4.2 0 0 1 1.977-.429l.704.02-.213-.671a3 3 0 0 0-.164-.409l-.975-1.995A2.967 2.967 0 1 0 6.785 8.8l.975 1.995q.172.35.416.633l.459.534.353-.609a4.2 4.2 0 0 1 1.801-1.675m-2.21.516-.895-1.833a1.968 1.968 0 1 1 3.536-1.728l.81 1.658a5.2 5.2 0 0 0-1.68.489 5.2 5.2 0 0 0-1.771 1.414m3.151 1.965a3 3 0 0 0 1.02-.818l.755-.95-1.205.142a2.97 2.97 0 0 0-1.975 1.1l-.755.95 1.205-.142c.324-.039.646-.132.955-.282" /> <path - android:fillColor="#000000" + android:fillColor="?attr/pointerIconVectorFill" android:pathData="M16.449 11.622a4.2 4.2 0 0 0-1.555-1.728l-.234-.146-.001-.276a4.2 4.2 0 0 0-.431-1.838l-.975-1.995a4.232 4.232 0 1 0-7.604 3.716l.975 1.995a4.2 4.2 0 0 0 1.555 1.729l.234.146.001.276c.002.617.141 1.244.431 1.838l.975 1.995a4.232 4.232 0 1 0 7.604-3.716zm-7.814.34-.459-.534a3 3 0 0 1-.416-.633L6.785 8.8a2.967 2.967 0 1 1 5.332-2.606l.975 1.995q.098.202.164.409l.214.672-.704-.02a4.2 4.2 0 0 0-1.977.429 4.2 4.2 0 0 0-1.801 1.675zm1.689-.33a2.97 2.97 0 0 1 1.975-1.1l1.205-.142-.755.95a2.95 2.95 0 0 1-1.02.818 3 3 0 0 1-.955.281l-1.204.143zm4.601 6.51a2.967 2.967 0 0 1-3.969-1.363l-.975-1.995a3 3 0 0 1-.164-.409l-.213-.671.704.02a4.2 4.2 0 0 0 1.977-.429 4.2 4.2 0 0 0 1.801-1.675l.353-.609.459.534q.245.284.416.633l.975 1.995a2.97 2.97 0 0 1-1.364 3.969" /> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/pointer_all_scroll_vector.xml b/core/res/res/drawable/pointer_all_scroll_vector.xml index 1692e5e62a46..45ad98c1b57c 100644 --- a/core/res/res/drawable/pointer_all_scroll_vector.xml +++ b/core/res/res/drawable/pointer_all_scroll_vector.xml @@ -21,7 +21,7 @@ android:viewportHeight="24"> <path android:pathData="M12.93 4.54a1.06 1.06 0 0 0-1.85 0L9.32 7.6c-.4.71.1 1.6.92 1.6h.82v1.86H9.2v-.84c0-.82-.88-1.33-1.6-.93l-3.06 1.76c-.7.41-.7 1.44 0 1.85l3.07 1.76c.7.4 1.6-.1 1.6-.93v-.79h1.86v1.87h-.82c-.81 0-1.33.88-.92 1.6l1.76 3.06c.4.71 1.44.71 1.85 0l1.75-3.07c.41-.7-.1-1.6-.92-1.6h-.82v-1.86h1.86v.8c0 .81.89 1.32 1.6.92l3.07-1.76c.7-.41.7-1.44 0-1.85L16.4 9.3c-.71-.4-1.6.1-1.6.93v.84h-1.86V9.2h.82c.82 0 1.33-.89.92-1.6l-1.75-3.06z" - android:fillColor="#000000"/> + android:fillColor="?attr/pointerIconVectorFill"/> <path android:pathData="M12 4c.36 0 .72.18.93.54l1.75 3.06c.41.71-.1 1.6-.92 1.6h-.82v1.86h1.86v-.84a1.07 1.07 0 0 1 1.6-.92l3.06 1.75c.72.41.72 1.44 0 1.85l-3.06 1.76a1.07 1.07 0 0 1-1.6-.92v-.8h-1.86v1.87h.82c.82 0 1.33.88.92 1.6l-1.75 3.06a1.07 1.07 0 0 1-1.85 0L9.32 16.4c-.4-.7.1-1.6.93-1.6h.81v-1.86H9.2v.8a1.07 1.07 0 0 1-1.6.92L4.54 12.9a1.06 1.06 0 0 1 0-1.85L7.6 9.3a1.07 1.07 0 0 1 1.6.92v.85h1.86V9.2h-.82c-.81 0-1.33-.89-.92-1.6l1.76-3.06c.2-.36.56-.54.92-.54m0-1c-.74 0-1.41.39-1.79 1.04L8.45 7.1c-.18.33-.28.7-.27 1.05h-.05c-.36 0-.71.1-1.03.28l-3.06 1.76a2.05 2.05 0 0 0 0 3.58l3.06 1.75c.32.18.67.28 1.03.28h.05c-.01.38.08.76.28 1.1l1.75 3.07c.38.65 1.05 1.03 1.8 1.03s1.41-.38 1.78-1.03l1.76-3.07c.2-.34.3-.72.28-1.1h.04c.36 0 .71-.1 1.03-.28l3.06-1.75a2.07 2.07 0 0 0 0-3.58L16.9 8.43a2.07 2.07 0 0 0-1.03-.28h-.04c0-.36-.09-.72-.28-1.05L13.8 4.04A2.04 2.04 0 0 0 12 3z" android:fillColor="#FFFFFF"/> diff --git a/core/res/res/drawable/pointer_arrow_vector.xml b/core/res/res/drawable/pointer_arrow_vector.xml index 562f0c05f662..2614170f6994 100644 --- a/core/res/res/drawable/pointer_arrow_vector.xml +++ b/core/res/res/drawable/pointer_arrow_vector.xml @@ -21,7 +21,7 @@ android:viewportHeight="24"> <path android:pathData="M16.34 11.18 6.77 4.02a1.78 1.78 0 0 0-1.88-.17c-.63.31-1 .91-1 1.6l.01 11.96c0 .9.6 1.46 1.15 1.67a1.74 1.74 0 0 0 1.98-.45l2.96-3.19c.3-.32.7-.52 1.13-.56l4.33-.47a1.8 1.8 0 0 0 .89-3.23z" - android:fillColor="#000000"/> + android:fillColor="?attr/pointerIconVectorFill"/> <path android:pathData="M16.94 10.38 7.37 3.22a2.77 2.77 0 0 0-2.93-.27 2.75 2.75 0 0 0-1.55 2.51l.01 11.95a2.78 2.78 0 0 0 2.82 2.8c.77 0 1.5-.32 2.03-.9l2.97-3.19a.8.8 0 0 1 .5-.25l4.34-.46a2.76 2.76 0 0 0 2.4-2.05 2.8 2.8 0 0 0-1.02-2.98zM17 13.1a1.77 1.77 0 0 1-1.55 1.31l-4.33.47a1.8 1.8 0 0 0-1.13.56l-2.97 3.2c-.4.42-.86.57-1.3.57-.24 0-.48-.05-.68-.13a1.77 1.77 0 0 1-1.14-1.67V5.46a1.81 1.81 0 0 1 1.8-1.8c.38 0 .75.11 1.07.36l9.57 7.16c.72.54.81 1.35.66 1.92z" android:fillColor="#FFFFFF"/> diff --git a/core/res/res/drawable/pointer_cell_vector.xml b/core/res/res/drawable/pointer_cell_vector.xml index 044a4f4014cb..cead1c4185b4 100644 --- a/core/res/res/drawable/pointer_cell_vector.xml +++ b/core/res/res/drawable/pointer_cell_vector.xml @@ -22,6 +22,6 @@ android:fillColor="#FFFFFF" android:pathData="M19 9.667h-4.668V5a2 2 0 0 0-2-2h-.667a2 2 0 0 0-2 2v4.667H5a2 2 0 0 0-2 2v.667a2 2 0 0 0 2 2h4.665V19a2 2 0 0 0 2 2h.667a2 2 0 0 0 2-2v-4.666H19a2 2 0 0 0 2-2v-.667a2 2 0 0 0-2-2m1 2.667a1 1 0 0 1-1 1h-5.668V19a1 1 0 0 1-1 1h-.667a1 1 0 0 1-1-1v-5.666H5a1 1 0 0 1-1-1v-.667a1 1 0 0 1 1-1h5.665V5a1 1 0 0 1 1-1h.667a1 1 0 0 1 1 1v5.667H19a1 1 0 0 1 1 1z" /> <path - android:fillColor="#000000" + android:fillColor="?attr/pointerIconVectorFill" android:pathData="M19 10.667h-5.668V5a1 1 0 0 0-1-1h-.667a1 1 0 0 0-1 1v5.667H5a1 1 0 0 0-1 1v.667a1 1 0 0 0 1 1h5.665V19a1 1 0 0 0 1 1h.667a1 1 0 0 0 1-1v-5.666H19a1 1 0 0 0 1-1v-.667a1 1 0 0 0-1-1" /> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/pointer_context_menu_vector.xml b/core/res/res/drawable/pointer_context_menu_vector.xml index 8e954d290619..fb2af431ffb6 100644 --- a/core/res/res/drawable/pointer_context_menu_vector.xml +++ b/core/res/res/drawable/pointer_context_menu_vector.xml @@ -26,9 +26,9 @@ android:fillColor="#FFFFFF" android:pathData="M16.938 10.38 7.372 3.216a2.77 2.77 0 0 0-2.931-.262A2.75 2.75 0 0 0 2.894 5.46l.009 11.951a2.785 2.785 0 0 0 1.776 2.604c.33.129.691.197 1.044.197a2.75 2.75 0 0 0 2.031-.897l2.969-3.193a.8.8 0 0 1 .5-.25l4.336-.467c1.397-.15 2.157-1.153 2.401-2.041a2.785 2.785 0 0 0-1.022-2.984m.058 2.718c-.157.571-.645 1.216-1.544 1.312l-4.335.467a1.8 1.8 0 0 0-1.126.563l-2.97 3.193a1.74 1.74 0 0 1-1.298.578 1.9 1.9 0 0 1-.678-.128c-.551-.217-1.141-.771-1.142-1.674l-.009-11.95c0-.697.371-1.299.994-1.611.262-.131.538-.196.813-.196.377 0 .75.123 1.072.365l9.566 7.163c.723.542.814 1.346.657 1.918" /> <path - android:fillColor="#000000" + android:fillColor="?attr/pointerIconVectorFill" android:pathData="M16.339 11.18 6.773 4.017a1.78 1.78 0 0 0-1.072-.365c-.274 0-.551.065-.813.196a1.77 1.77 0 0 0-.994 1.611l.009 11.951c0 .903.59 1.457 1.142 1.674.2.078.433.128.678.128.434 0 .906-.155 1.298-.578l2.97-3.193a1.8 1.8 0 0 1 1.126-.563l4.335-.467c.899-.097 1.387-.741 1.544-1.312.157-.573.066-1.377-.657-1.919" /> <path - android:fillColor="#000000" + android:fillColor="?attr/pointerIconVectorFill" android:pathData="M19.475 3.461h-2.66c-.37 0-.67.3-.67.67v2.66c0 .37.3.67.67.67h2.66c.37 0 .67-.3.67-.67v-2.66a.67.67 0 0 0-.67-.67m-.3 3.062h-2.067a.3.3 0 1 1 0-.6h2.067a.3.3 0 1 1 0 .6m0-.868h-2.067a.3.3 0 1 1 0-.6h2.067a.3.3 0 1 1 0 .6m0-.885h-2.067a.3.3 0 1 1 0-.6h2.067a.3.3 0 1 1 0 .6" /> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/pointer_copy_vector.xml b/core/res/res/drawable/pointer_copy_vector.xml index b1e8995269a7..3f138685e6eb 100644 --- a/core/res/res/drawable/pointer_copy_vector.xml +++ b/core/res/res/drawable/pointer_copy_vector.xml @@ -19,8 +19,8 @@ android:viewportHeight="24" android:viewportWidth="24"> <group> - <path android:fillColor="#FFFFFF" android:pathData="M17.5 2c-2.104 0-3.861 1.457-4.351 3.41A4.5 4.5 0 0 0 13 6.5c0 .344.047.675.12.997-.062-.002-.122-.009-.185-.009q-.225 0-.446.018V6.484a1 1 0 0 0-2 0v1.57a5.7 5.7 0 0 0-.997.625V7.583a1 1 0 0 0-2 0v4.205l-.697-.713c-.482-.494-1.265-.494-1.747 0s-.482 1.294 0 1.787l3.847 3.936q.056.057.117.106a5.58 5.58 0 0 0 3.922 1.613c3.045 0 5.563-2.469 5.563-5.514q0-.192-.013-.38v-1.739a4.4 4.4 0 0 0 1-.37C20.969 9.778 22 8.265 22 6.5 22 4.019 19.981 2 17.5 2m1.985 7.364a3.6 3.6 0 0 1-1 .478A3.5 3.5 0 0 1 17.5 10a3.5 3.5 0 0 1-3.486-3.358C14.012 6.594 14 6.549 14 6.5c0-.328.06-.639.145-.941C14.559 4.088 15.898 3 17.5 3 19.43 3 21 4.57 21 6.5a3.47 3.47 0 0 1-1.515 2.864" /> - <path android:fillColor="#FFFFFF" android:pathData="M19.299 6H18V4.7a.5.5 0 0 0-1 0V6h-1.301a.5.5 0 0 0 0 1H17v1.3a.5.5 0 0 0 1 0V7h1.299a.5.5 0 0 0 0-1" /> + <path android:fillColor="?attr/pointerIconVectorFillInverse" android:pathData="M17.5 2c-2.104 0-3.861 1.457-4.351 3.41A4.5 4.5 0 0 0 13 6.5c0 .344.047.675.12.997-.062-.002-.122-.009-.185-.009q-.225 0-.446.018V6.484a1 1 0 0 0-2 0v1.57a5.7 5.7 0 0 0-.997.625V7.583a1 1 0 0 0-2 0v4.205l-.697-.713c-.482-.494-1.265-.494-1.747 0s-.482 1.294 0 1.787l3.847 3.936q.056.057.117.106a5.58 5.58 0 0 0 3.922 1.613c3.045 0 5.563-2.469 5.563-5.514q0-.192-.013-.38v-1.739a4.4 4.4 0 0 0 1-.37C20.969 9.778 22 8.265 22 6.5 22 4.019 19.981 2 17.5 2m1.985 7.364a3.6 3.6 0 0 1-1 .478A3.5 3.5 0 0 1 17.5 10a3.5 3.5 0 0 1-3.486-3.358C14.012 6.594 14 6.549 14 6.5c0-.328.06-.639.145-.941C14.559 4.088 15.898 3 17.5 3 19.43 3 21 4.57 21 6.5a3.47 3.47 0 0 1-1.515 2.864" /> + <path android:fillColor="?attr/pointerIconVectorFillInverse" android:pathData="M19.299 6H18V4.7a.5.5 0 0 0-1 0V6h-1.301a.5.5 0 0 0 0 1H17v1.3a.5.5 0 0 0 1 0V7h1.299a.5.5 0 0 0 0-1" /> </group> <path android:fillColor="#000000" diff --git a/core/res/res/drawable/pointer_crosshair_vector.xml b/core/res/res/drawable/pointer_crosshair_vector.xml index b2e7e8a68615..8a50d1bdd497 100644 --- a/core/res/res/drawable/pointer_crosshair_vector.xml +++ b/core/res/res/drawable/pointer_crosshair_vector.xml @@ -23,6 +23,6 @@ android:pathData="M19.25 10.25h-5.5v-5.5a1.75 1.75 0 0 0-3.5 0v5.5h-5.5a1.75 1.75 0 0 0 0 3.5h5.5v5.5a1.75 1.75 0 0 0 3.5 0v-5.5h5.5a1.75 1.75 0 0 0 0-3.5m0 2.5h-6.5v6.5a.75.75 0 0 1-1.5 0v-6.5h-6.5a.75.75 0 0 1 0-1.5h6.5v-6.5a.75.75 0 0 1 1.5 0v6.5h6.5a.75.75 0 0 1 0 1.5" /> <path android:fillType="evenOdd" - android:fillColor="#000000" + android:fillColor="?attr/pointerIconVectorFill" android:pathData="M19.25 11.25h-6.5v-6.5a.75.75 0 0 0-1.5 0v6.5h-6.5a.75.75 0 0 0 0 1.5h6.5v6.5a.75.75 0 0 0 1.5 0v-6.5h6.5a.75.75 0 0 0 0-1.5" /> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/pointer_grab_vector.xml b/core/res/res/drawable/pointer_grab_vector.xml index 7d9f048bbbb6..48c01ceb6588 100644 --- a/core/res/res/drawable/pointer_grab_vector.xml +++ b/core/res/res/drawable/pointer_grab_vector.xml @@ -22,6 +22,6 @@ android:fillColor="#000000" android:pathData="M20.442 7.562a2 2 0 0 0-2-2c-.366 0-.705.106-1 .277V4.686a2 2 0 0 0-2-2 2 2 0 0 0-1.004.279 1.995 1.995 0 0 0-3.986-.06 2 2 0 0 0-1.006-.28 2 2 0 0 0-2 2v6.501l-.247-.253a2.216 2.216 0 0 0-3.178 0 2.286 2.286 0 0 0 0 3.186l5.106 5.224q.063.061.131.118l-.001.001a6.58 6.58 0 0 0 4.624 1.901c3.587 0 6.565-2.906 6.565-6.516q0-.105-.004-.21m-6.561 5.727a5.58 5.58 0 0 1-3.922-1.613 1 1 0 0 1-.117-.106l-5.106-5.224a1.286 1.286 0 0 1 0-1.788 1.215 1.215 0 0 1 1.747 0l1.962 2.008V4.625a1 1 0 0 1 2 0v5.833q.463-.362.996-.623V3a1 1 0 0 1 2 0v6.29a6 6 0 0 1 1 .011V4.686a1 1 0 0 1 2 0v5.21c.357.185.693.408 1 .663V7.562a1 1 0 0 1 2 0v7.019h.001-.001q.004.104.004.207c.001 3.046-2.518 5.516-5.564 5.516" /> <path - android:fillColor="#FFFFFF" + android:fillColor="?attr/pointerIconVectorFillInverse" android:pathData="M19.442 14.581V7.562a1 1 0 0 0-2 0v2.997a5.7 5.7 0 0 0-1-.663v-5.21a1 1 0 0 0-2 0v4.615a5.5 5.5 0 0 0-1-.011V3a1 1 0 0 0-2 0v6.835a5.6 5.6 0 0 0-.996.623V4.625a1 1 0 0 0-2 0v8.955l-1.962-2.008a1.215 1.215 0 0 0-1.747 0 1.286 1.286 0 0 0 0 1.788l5.106 5.224q.056.057.117.106a5.58 5.58 0 0 0 3.922 1.613c3.046 0 5.565-2.469 5.565-5.516z" /> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/pointer_grabbing_vector.xml b/core/res/res/drawable/pointer_grabbing_vector.xml index 9c9610366b6d..ad9f86c1848c 100644 --- a/core/res/res/drawable/pointer_grabbing_vector.xml +++ b/core/res/res/drawable/pointer_grabbing_vector.xml @@ -22,6 +22,6 @@ android:fillColor="#000000" android:pathData="M19.485 12.622V8.508a2 2 0 0 0-3.12-1.657 1.993 1.993 0 0 0-2.99-1.006 1.99 1.99 0 0 0-1.886-1.361c-.903 0-1.658.603-1.906 1.425a2 2 0 0 0-3.09 1.674v2.206a2.2 2.2 0 0 0-2.159.586 2.285 2.285 0 0 0 0 3.185l3.847 3.936q.063.061.13.118l-.001.001a6.58 6.58 0 0 0 4.624 1.902c3.586 0 6.563-2.905 6.563-6.514a5 5 0 0 0-.012-.381m-6.55 5.895a5.58 5.58 0 0 1-3.922-1.613 1 1 0 0 1-.117-.106l-3.847-3.936c-.482-.494-.482-1.294 0-1.787s1.265-.494 1.747 0l.697.713V7.583a1 1 0 0 1 2 0v1.096q.463-.364.997-.625v-1.57a1 1 0 0 1 2 0v1.022a5.5 5.5 0 0 1 .996.009v-.007a1 1 0 0 1 2 0v.599q.537.277 1 .66v-.259a1 1 0 0 1 2 0v4.115q.013.189.013.38c-.001 3.045-2.518 5.514-5.564 5.514" /> <path - android:fillColor="#FFFFFF" + android:fillColor="?attr/pointerIconVectorFillInverse" android:pathData="M18.485 12.622V8.508a1 1 0 0 0-2 0v.259a5.6 5.6 0 0 0-1-.66v-.599a1 1 0 0 0-2 0v.008a5.6 5.6 0 0 0-.996-.009V6.484a1 1 0 0 0-2 0v1.57a5.7 5.7 0 0 0-.997.625V7.583a1 1 0 0 0-2 0v4.205l-.697-.713c-.482-.494-1.265-.494-1.747 0s-.482 1.294 0 1.787l3.847 3.936q.056.057.117.106a5.58 5.58 0 0 0 3.922 1.613c3.045 0 5.563-2.469 5.563-5.514a5 5 0 0 0-.012-.381" /> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/pointer_hand_vector.xml b/core/res/res/drawable/pointer_hand_vector.xml index 79792f840c85..a06dc08b8b3f 100644 --- a/core/res/res/drawable/pointer_hand_vector.xml +++ b/core/res/res/drawable/pointer_hand_vector.xml @@ -22,6 +22,6 @@ android:fillColor="#000000" android:pathData="M20.492 15.197v-4.198A1.995 1.995 0 0 0 18.5 9.001c-.413 0-.797.126-1.115.342a1.99 1.99 0 0 0-1.873-1.341c-.411 0-.792.125-1.109.339a1.99 1.99 0 0 0-1.879-1.361c-.363 0-.699.105-.992.275V3.998A1.99 1.99 0 0 0 9.542 2c-1.1 0-1.992.895-1.992 1.998v7.831l-.242-.249a2.2 2.2 0 0 0-3.164 0 2.29 2.29 0 0 0 0 3.183l5.084 5.219q.063.061.13.118l-.001.001A6.54 6.54 0 0 0 13.963 22c3.572 0 6.537-2.903 6.537-6.509q0-.148-.008-.294m-6.529 5.804a5.55 5.55 0 0 1-3.906-1.611 1 1 0 0 1-.117-.106l-5.084-5.219a1.286 1.286 0 0 1 0-1.786 1.21 1.21 0 0 1 1.74 0l1.95 2.002V3.998c0-.552.446-.999.996-.999s.996.447.996.999v7.17l.011-.007a.495.495 0 0 0 .989-.037V8.939a.992.992 0 0 1 1.984.039v.796l-.007 1.386a.5.5 0 0 0 .495.502h.003a.5.5 0 0 0 .498-.497l.006-1.157h.001V10a.997.997 0 1 1 1.991 0v.601l.004.003v1.02q.001.107.042.199a.5.5 0 0 0 .153.187l.031.021a.5.5 0 0 0 .231.083c.014.001.026.008.04.008a.5.5 0 0 0 .498-.5v-.642a.996.996 0 0 1 .993-.98c.55 0 .996.447.996.999v4.199a6 6 0 0 1 .008.293c-.001 3.043-2.509 5.51-5.542 5.51" /> <path - android:fillColor="#FFFFFF" + android:fillColor="?attr/pointerIconVectorFillInverse" android:pathData="M19.496 10.999A.997.997 0 0 0 18.5 10a.995.995 0 0 0-.992.98v.644a.5.5 0 0 1-.498.5c-.014 0-.026-.007-.04-.008a.493.493 0 0 1-.457-.491v-1.02l-.004-.003V10c0-.552-.446-.999-.996-.999s-.996.447-.996.999v.008h-.001l-.005 1.003-.001.154a.5.5 0 0 1-.498.497h-.003a.5.5 0 0 1-.495-.502l.001-.159.006-1.227v-.796a.997.997 0 0 0-.996-.999.993.993 0 0 0-.988.96v2.185a.496.496 0 0 1-.989.037l-.011.007v-7.17a.997.997 0 0 0-.996-.999.997.997 0 0 0-.996.999V14.28l-1.95-2.002a1.21 1.21 0 0 0-1.74 0 1.286 1.286 0 0 0 0 1.786l5.084 5.219q.056.057.117.106A5.54 5.54 0 0 0 13.962 21c3.033 0 5.541-2.467 5.541-5.51a6 6 0 0 0-.008-.293z" /> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/pointer_handwriting_vector.xml b/core/res/res/drawable/pointer_handwriting_vector.xml index 09f3e31473dd..849759291101 100644 --- a/core/res/res/drawable/pointer_handwriting_vector.xml +++ b/core/res/res/drawable/pointer_handwriting_vector.xml @@ -23,6 +23,6 @@ <path android:fillColor="#FFFFFF" android:pathData="m16.431 7.64-6.29 6.29 1.43 1.43 6.29-6.29-1.42-1.43z" /> </group> <path - android:fillColor="#000000" + android:fillColor="?attr/pointerIconVectorFill" android:pathData="M5 4c-.55 0-1 .45-1 1v14c0 .55.45 1 1 1s1-.45 1-1V5c0-.55-.45-1-1-1m14.41 3.51-1.42-1.42c-.39-.39-.9-.59-1.41-.59h-.01c-.51 0-1.02.2-1.41.59L8 13.25v4.25h4.25l7.16-7.16c.78-.78.78-2.05 0-2.83m-7.839 7.85-1.43-1.43 6.29-6.29h.01l1.42 1.43z" /> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/pointer_help_vector.xml b/core/res/res/drawable/pointer_help_vector.xml index 6b7fd9f99a26..07970fbdd67a 100644 --- a/core/res/res/drawable/pointer_help_vector.xml +++ b/core/res/res/drawable/pointer_help_vector.xml @@ -19,12 +19,12 @@ android:viewportHeight="24" android:viewportWidth="24"> <path - android:fillColor="#000000" + android:fillColor="?attr/pointerIconVectorFill" android:pathData="M16.339 11.18 6.773 4.017a1.78 1.78 0 0 0-1.072-.365c-.274 0-.551.065-.813.196a1.77 1.77 0 0 0-.994 1.611l.009 11.951c0 .903.59 1.457 1.142 1.674.2.078.433.128.678.128.434 0 .906-.155 1.298-.578l2.97-3.193a1.8 1.8 0 0 1 1.126-.563l4.335-.467c.899-.097 1.387-.741 1.544-1.312.157-.573.066-1.377-.657-1.919" /> <path android:fillColor="#FFFFFF" android:pathData="M16.94 10.38 7.37 3.22a2.77 2.77 0 0 0-2.93-.27A2.75 2.75 0 0 0 2.9 5.46l.01 11.95a2.79 2.79 0 0 0 2.82 2.8c.78 0 1.5-.32 2.03-.9l2.97-3.19a.8.8 0 0 1 .5-.25l4.34-.46a2.76 2.76 0 0 0 2.4-2.05 2.8 2.8 0 0 0-1.02-2.98zM17 13.1a1.77 1.77 0 0 1-1.55 1.31l-4.33.47a1.8 1.8 0 0 0-1.13.56l-2.97 3.2c-.4.42-.86.57-1.3.57-.24 0-.48-.05-.68-.13a1.77 1.77 0 0 1-1.14-1.67V5.46a1.81 1.81 0 0 1 1.8-1.8c.38 0 .75.11 1.07.36l9.57 7.16c.72.54.81 1.35.66 1.92zm2.64-10.83a2.5 2.5 0 0 0-1.84-.72 3 3 0 0 0-2.83 1.93l-.39.94.96.37.86.32.12.05-.02.03c-.22.4-.3.82-.3 1.33v.94a1.56 1.56 0 0 0 .4 1.47 1.54 1.54 0 0 0 2.24.01 1.55 1.55 0 0 0 .28-1.84v-.52c0-.1.02-.17.03-.25l.16-.15c.32-.25.6-.56.78-.93.18-.37.26-.76.26-1.16 0-.68-.21-1.32-.7-1.82zm-1.5 5.96a.55.55 0 0 1-.82 0 .56.56 0 0 1-.17-.4c0-.16.06-.3.17-.4a.55.55 0 0 1 .41-.18c.15 0 .28.06.4.17a.55.55 0 0 1 0 .81zm1.05-3.42c-.1.22-.28.42-.52.6-.26.22-.42.42-.47.6-.05.18-.08.37-.08.57l-.93-.06c0-.38.07-.62.19-.86.13-.24.3-.46.54-.66.17-.13.3-.28.4-.43s.14-.3.14-.46c0-.2-.08-.37-.22-.5s-.31-.17-.52-.17c-.2 0-.39.06-.56.18-.17.13-.3.31-.4.56l-.87-.33a2.03 2.03 0 0 1 1.91-1.3c.48 0 .86.14 1.13.42.28.28.41.65.41 1.12 0 .26-.05.5-.15.72z" /> <path - android:fillColor="#000000" + android:fillColor="?attr/pointerIconVectorFill" android:pathData="M17.73 7.254a.55.55 0 0 0-.407.169.55.55 0 0 0-.169.407q0 .225.169.401a.55.55 0 0 0 .808 0 .56.56 0 0 0 .175-.413.53.53 0 0 0-.175-.394.56.56 0 0 0-.401-.17m1.202-4.288q-.413-.42-1.126-.419-.651 0-1.164.357a2.1 2.1 0 0 0-.751.945l.864.326q.15-.363.407-.551a.93.93 0 0 1 .557-.188q.313 0 .526.182c.213.182.213.286.213.495q0 .226-.144.457a1.4 1.4 0 0 1-.394.432q-.35.3-.538.657c-.125.238-.187.485-.187.86l.926.06q0-.3.081-.57t.469-.595q.363-.276.519-.601t.156-.726q-.002-.701-.414-1.121" /> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/pointer_horizontal_double_arrow_vector.xml b/core/res/res/drawable/pointer_horizontal_double_arrow_vector.xml index d1aea9eacf3f..32c56b6aa098 100644 --- a/core/res/res/drawable/pointer_horizontal_double_arrow_vector.xml +++ b/core/res/res/drawable/pointer_horizontal_double_arrow_vector.xml @@ -22,6 +22,6 @@ android:fillColor="#FFFFFF" android:pathData="m19.963 10.185-3.065-1.758c-1.327-.761-2.96.14-3.072 1.633h-3.651c-.113-1.492-1.746-2.394-3.072-1.633l-3.065 1.758c-1.383.793-1.383 2.786 0 3.579l3.065 1.758c1.311.752 2.918-.12 3.065-1.581h3.666c.147 1.46 1.754 2.333 3.065 1.581l3.065-1.758c1.382-.793 1.382-2.786-.001-3.579m-.498 2.712L16.4 14.655a1.065 1.065 0 0 1-1.596-.922v-.791H9.195v.791c0 .818-.886 1.33-1.596.922l-3.065-1.758a1.063 1.063 0 0 1 0-1.845l3.065-1.758a1.065 1.065 0 0 1 1.596.922v.843h5.609v-.843c0-.818.886-1.33 1.596-.922l3.065 1.758a1.063 1.063 0 0 1 0 1.845" /> <path - android:fillColor="#000000" + android:fillColor="?attr/pointerIconVectorFill" android:pathData="M19.465 11.052 16.4 9.294a1.065 1.065 0 0 0-1.596.922v.843H9.195v-.843c0-.818-.886-1.33-1.596-.922l-3.065 1.758a1.063 1.063 0 0 0 0 1.845l3.065 1.758a1.065 1.065 0 0 0 1.596-.922v-.791h5.609v.791c0 .818.886 1.33 1.596.922l3.065-1.758a1.063 1.063 0 0 0 0-1.845" /> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/pointer_nodrop_vector.xml b/core/res/res/drawable/pointer_nodrop_vector.xml index 3a38babd12d2..6108e9681fa5 100644 --- a/core/res/res/drawable/pointer_nodrop_vector.xml +++ b/core/res/res/drawable/pointer_nodrop_vector.xml @@ -19,8 +19,8 @@ android:viewportHeight="24" android:viewportWidth="24"> <group> - <path android:fillColor="#FFFFFF" android:pathData="M17.5 1.953c-2.108 0-3.869 1.449-4.382 3.398a4.5 4.5 0 0 0-.165 1.148c0 .343.045.674.117.995-.045-.001-.09-.007-.135-.007q-.225 0-.446.018V6.484a1 1 0 0 0-2 0v1.57a5.7 5.7 0 0 0-.997.625V7.583a1 1 0 0 0-2 0v4.205l-.697-.713c-.482-.494-1.265-.494-1.747 0s-.482 1.294 0 1.787l3.847 3.936q.056.057.117.106a5.58 5.58 0 0 0 3.922 1.613c3.045 0 5.563-2.469 5.563-5.514q0-.192-.013-.38v-1.69a4.5 4.5 0 0 0 1-.366c1.51-.739 2.562-2.275 2.562-4.066A4.55 4.55 0 0 0 17.5 1.953m0 8.047C15.57 10 14 8.43 14 6.5S15.57 3 17.5 3 21 4.57 21 6.5 19.43 10 17.5 10" /> - <path android:fillColor="#FFFFFF" android:pathData="M17.5 4c-.493 0-.95.148-1.337.395l3.442 3.442C19.852 7.45 20 6.993 20 6.5 20 5.121 18.879 4 17.5 4M15 6.5C15 7.879 16.121 9 17.5 9c.525 0 1.011-.164 1.413-.441l-3.472-3.472A2.5 2.5 0 0 0 15 6.5" /> + <path android:fillColor="?attr/pointerIconVectorFillInverse" android:pathData="M17.5 1.953c-2.108 0-3.869 1.449-4.382 3.398a4.5 4.5 0 0 0-.165 1.148c0 .343.045.674.117.995-.045-.001-.09-.007-.135-.007q-.225 0-.446.018V6.484a1 1 0 0 0-2 0v1.57a5.7 5.7 0 0 0-.997.625V7.583a1 1 0 0 0-2 0v4.205l-.697-.713c-.482-.494-1.265-.494-1.747 0s-.482 1.294 0 1.787l3.847 3.936q.056.057.117.106a5.58 5.58 0 0 0 3.922 1.613c3.045 0 5.563-2.469 5.563-5.514q0-.192-.013-.38v-1.69a4.5 4.5 0 0 0 1-.366c1.51-.739 2.562-2.275 2.562-4.066A4.55 4.55 0 0 0 17.5 1.953m0 8.047C15.57 10 14 8.43 14 6.5S15.57 3 17.5 3 21 4.57 21 6.5 19.43 10 17.5 10" /> + <path android:fillColor="?attr/pointerIconVectorFillInverse" android:pathData="M17.5 4c-.493 0-.95.148-1.337.395l3.442 3.442C19.852 7.45 20 6.993 20 6.5 20 5.121 18.879 4 17.5 4M15 6.5C15 7.879 16.121 9 17.5 9c.525 0 1.011-.164 1.413-.441l-3.472-3.472A2.5 2.5 0 0 0 15 6.5" /> </group> <path android:fillColor="#000000" diff --git a/core/res/res/drawable/pointer_text_vector.xml b/core/res/res/drawable/pointer_text_vector.xml index 9e44f28f5779..a14727309674 100644 --- a/core/res/res/drawable/pointer_text_vector.xml +++ b/core/res/res/drawable/pointer_text_vector.xml @@ -19,7 +19,7 @@ android:viewportHeight="24" android:viewportWidth="24"> <path - android:fillColor="#000000" + android:fillColor="?attr/pointerIconVectorFill" android:pathData="M12 3c-.551 0-1 .448-1 1v14a1.001 1.001 0 0 0 2 0V4c0-.552-.449-1-1-1" /> <path android:fillColor="#FFFFFF" diff --git a/core/res/res/drawable/pointer_top_left_diagonal_double_arrow_vector.xml b/core/res/res/drawable/pointer_top_left_diagonal_double_arrow_vector.xml index e5d5301ce009..7f95207d9e82 100644 --- a/core/res/res/drawable/pointer_top_left_diagonal_double_arrow_vector.xml +++ b/core/res/res/drawable/pointer_top_left_diagonal_double_arrow_vector.xml @@ -23,6 +23,6 @@ android:pathData="m18.896 16.365-.924-3.41c-.398-1.467-2.169-1.985-3.305-1.035L12.08 9.333c.952-1.136.434-2.908-1.034-3.306l-3.41-.924c-1.539-.416-2.948.993-2.532 2.532l.924 3.41c.398 1.468 2.17 1.986 3.306 1.034l2.586 2.586c-.953 1.136-.435 2.91 1.033 3.307l3.41.924c1.54.417 2.949-.992 2.533-2.531m-2.27 1.566-3.41-.924a1.065 1.065 0 0 1-.476-1.781l.579-.579-3.966-3.966-.579.579a1.066 1.066 0 0 1-1.781-.476L6.07 7.373a1.063 1.063 0 0 1 1.304-1.304l3.41.924a1.065 1.065 0 0 1 .476 1.781l-.578.578 3.966 3.966.577-.577a1.066 1.066 0 0 1 1.781.477l.924 3.41a1.062 1.062 0 0 1-1.304 1.303" /> <path android:fillType="evenOdd" - android:fillColor="#000000" + android:fillColor="?attr/pointerIconVectorFill" android:pathData="M6.07 7.373a1.063 1.063 0 0 1 1.304-1.304l3.41.924a1.065 1.065 0 0 1 .476 1.781l-.578.578 3.966 3.966.577-.577a1.066 1.066 0 0 1 1.781.476l.924 3.41a1.063 1.063 0 0 1-1.304 1.304l-3.41-.924a1.065 1.065 0 0 1-.476-1.781l.579-.579-3.966-3.966-.579.579a1.066 1.066 0 0 1-1.781-.476z" /> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/pointer_top_right_diagonal_double_arrow_vector.xml b/core/res/res/drawable/pointer_top_right_diagonal_double_arrow_vector.xml index e6f7aafe2e6b..8a3371524429 100644 --- a/core/res/res/drawable/pointer_top_right_diagonal_double_arrow_vector.xml +++ b/core/res/res/drawable/pointer_top_right_diagonal_double_arrow_vector.xml @@ -22,6 +22,6 @@ android:fillColor="#FFFFFF" android:pathData="m16.365 5.104-3.41.924c-1.468.398-1.986 2.171-1.033 3.307l-2.586 2.586c-1.136-.952-2.909-.434-3.306 1.034l-.924 3.41c-.417 1.539.992 2.948 2.531 2.531l3.41-.924c1.468-.398 1.986-2.17 1.034-3.306l2.587-2.587c1.136.951 2.908.432 3.305-1.035l.924-3.41c.415-1.538-.994-2.947-2.532-2.53m1.565 2.269-.924 3.41a1.065 1.065 0 0 1-1.781.476l-.577-.577-3.966 3.966.578.578a1.066 1.066 0 0 1-.476 1.781l-3.41.924a1.063 1.063 0 0 1-1.304-1.304l.924-3.41a1.066 1.066 0 0 1 1.781-.477l.578.578 3.966-3.966-.579-.579a1.066 1.066 0 0 1 .476-1.781l3.41-.924a1.063 1.063 0 0 1 1.304 1.305" /> <path - android:fillColor="#000000" + android:fillColor="?attr/pointerIconVectorFill" android:pathData="m16.626 6.069-3.41.924a1.065 1.065 0 0 0-.476 1.781l.579.579-3.966 3.966-.579-.579a1.066 1.066 0 0 0-1.781.477l-.924 3.41a1.063 1.063 0 0 0 1.304 1.304l3.41-.924a1.065 1.065 0 0 0 .476-1.781l-.578-.578 3.966-3.966.577.577a1.066 1.066 0 0 0 1.781-.476l.924-3.41a1.062 1.062 0 0 0-1.303-1.304" /> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/pointer_vertical_double_arrow_vector.xml b/core/res/res/drawable/pointer_vertical_double_arrow_vector.xml index 6ffcfefead3d..889372c39433 100644 --- a/core/res/res/drawable/pointer_vertical_double_arrow_vector.xml +++ b/core/res/res/drawable/pointer_vertical_double_arrow_vector.xml @@ -22,6 +22,6 @@ android:fillColor="#FFFFFF" android:pathData="M13.945 13.829V10.17c1.476-.131 2.363-1.75 1.606-3.069l-1.758-3.065c-.793-1.383-2.786-1.383-3.579 0L8.455 7.102c-.757 1.319.131 2.939 1.607 3.069v3.658c-1.477.13-2.364 1.75-1.607 3.069l1.758 3.065c.793 1.383 2.786 1.383 3.579 0l1.758-3.065c.758-1.319-.129-2.938-1.605-3.069m.739 2.572-1.758 3.065a1.063 1.063 0 0 1-1.845 0l-1.758-3.065a1.065 1.065 0 0 1 .922-1.596h.818v-5.61h-.818c-.818 0-1.33-.886-.922-1.596l1.758-3.065a1.063 1.063 0 0 1 1.845 0l1.758 3.065a1.065 1.065 0 0 1-.922 1.596h-.817v5.609h.817c.817.001 1.329.886.922 1.597" /> <path - android:fillColor="#000000" + android:fillColor="?attr/pointerIconVectorFill" android:pathData="M13.761 14.805h-.817v-5.61h.817c.818 0 1.33-.886.922-1.596l-1.758-3.065a1.063 1.063 0 0 0-1.845 0L9.323 7.599c-.407.71.104 1.596.922 1.596h.818v5.609h-.818c-.818 0-1.33.886-.922 1.596l1.758 3.065a1.063 1.063 0 0 0 1.845 0l1.758-3.065a1.065 1.065 0 0 0-.923-1.595" /> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/pointer_vertical_text_vector.xml b/core/res/res/drawable/pointer_vertical_text_vector.xml index 72f40ccfc82b..9238f94fa808 100644 --- a/core/res/res/drawable/pointer_vertical_text_vector.xml +++ b/core/res/res/drawable/pointer_vertical_text_vector.xml @@ -19,7 +19,7 @@ android:viewportHeight="24" android:viewportWidth="24"> <path - android:fillColor="#000000" + android:fillColor="?attr/pointerIconVectorFill" android:pathData="M19 11H5a1 1 0 0 0 0 2h14a1 1 0 0 0 0-2" /> <path android:fillColor="#FFFFFF" diff --git a/core/res/res/drawable/pointer_zoom_in_vector.xml b/core/res/res/drawable/pointer_zoom_in_vector.xml index 89216662964b..a7f56c23d5fb 100644 --- a/core/res/res/drawable/pointer_zoom_in_vector.xml +++ b/core/res/res/drawable/pointer_zoom_in_vector.xml @@ -23,7 +23,7 @@ <path android:fillColor="#FFFFFF" android:pathData="M10.55 5a4.546 4.546 0 1 0 0 9.093 4.546 4.546 0 0 0 0-9.093m2.462 5h-2v2a.5.5 0 0 1-1 0v-2h-2a.5.5 0 0 1 0-1h2V7a.5.5 0 0 1 1 0v2h2a.5.5 0 0 1 0 1" /> </group> <group> - <path android:fillColor="#000000" android:pathData="m19.736 18.003-4.194-4.22a6.547 6.547 0 1 0-1.382 1.226l4.268 4.294a.923.923 0 0 0 1.308-1.3m-9.186-3.91A4.546 4.546 0 1 1 10.549 5a4.546 4.546 0 0 1 .001 9.093" /> - <path android:fillColor="#000000" android:pathData="M13.012 9h-2V7a.5.5 0 0 0-1 0v2h-2a.5.5 0 0 0 0 1h2v2a.5.5 0 0 0 1 0v-2h2a.5.5 0 0 0 0-1" /> + <path android:fillColor="?attr/pointerIconVectorFill" android:pathData="m19.736 18.003-4.194-4.22a6.547 6.547 0 1 0-1.382 1.226l4.268 4.294a.923.923 0 0 0 1.308-1.3m-9.186-3.91A4.546 4.546 0 1 1 10.549 5a4.546 4.546 0 0 1 .001 9.093" /> + <path android:fillColor="?attr/pointerIconVectorFill" android:pathData="M13.012 9h-2V7a.5.5 0 0 0-1 0v2h-2a.5.5 0 0 0 0 1h2v2a.5.5 0 0 0 1 0v-2h2a.5.5 0 0 0 0-1" /> </group> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/pointer_zoom_out_vector.xml b/core/res/res/drawable/pointer_zoom_out_vector.xml index 815ce0ebe9b4..e46b978df5b6 100644 --- a/core/res/res/drawable/pointer_zoom_out_vector.xml +++ b/core/res/res/drawable/pointer_zoom_out_vector.xml @@ -23,7 +23,7 @@ <path android:fillColor="#FFFFFF" android:pathData="M10.55 5a4.546 4.546 0 1 0 0 9.093 4.546 4.546 0 0 0 0-9.093m2.462 5h-5a.5.5 0 0 1 0-1h5a.5.5 0 0 1 0 1" /> </group> <group> - <path android:fillColor="#000000" android:pathData="m19.736 18.003-4.194-4.22a6.547 6.547 0 1 0-1.382 1.226l4.268 4.294a.923.923 0 0 0 1.308-1.3m-9.186-3.91A4.546 4.546 0 1 1 10.549 5a4.546 4.546 0 0 1 .001 9.093" /> - <path android:fillColor="#000000" android:pathData="M13.012 9h-5a.5.5 0 0 0 0 1h5a.5.5 0 0 0 0-1" /> + <path android:fillColor="?attr/pointerIconVectorFill" android:pathData="m19.736 18.003-4.194-4.22a6.547 6.547 0 1 0-1.382 1.226l4.268 4.294a.923.923 0 0 0 1.308-1.3m-9.186-3.91A4.546 4.546 0 1 1 10.549 5a4.546 4.546 0 0 1 .001 9.093" /> + <path android:fillColor="?attr/pointerIconVectorFill" android:pathData="M13.012 9h-5a.5.5 0 0 0 0 1h5a.5.5 0 0 0 0-1" /> </group> </vector>
\ No newline at end of file diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index ca6a384bd96f..704d44278a78 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privaat ruimte"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Kloon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Gemeenskaplik"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Sensitiewe kennisgewinginhoud is versteek"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Appinhoud is weens sekuriteit van skermdeling verberg"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 218b13ae3de7..d1e18dacd5b4 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"የግል ቦታ"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"አባዛ"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"የጋራ"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"አደገኛ የማሳወቂያ ይዘት ተደብቋል"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ለደኅንነት ሲባል የመተግበሪያ ይዘት ከማያ ገጽ ማጋራት ተደብቋል"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index d0e28b7b243a..5ef18af8129a 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -2411,6 +2411,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"المساحة الخاصة"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"نسخة طبق الأصل"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ملف شخصي مشترك"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"تم إخفاء المحتوى الحساس في الإشعار"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"تم إخفاء محتوى التطبيق بعد تفعيل ميزة \"مشاركة الشاشة\" للحفاظ على أمانك"</string> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 42b0af9d4490..5443f12881b4 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"প্ৰাইভেট স্পে’চ"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ক্ল’ন"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"সম্প্ৰদায়ৰ সৈতে জড়িত"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"সংবেদনশীল জাননী লুকুওৱা হৈছে"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"সুৰক্ষাৰ বাবে এপৰ সমল স্ক্ৰীণ শ্বেয়াৰ কৰাৰ পৰা লুকুৱাই ৰখা হৈছে"</string> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index 5633c06f6b92..b9ec7428a4e6 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Məxfi sahə"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Kommunal"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Həssas bildiriş kontenti gizlədildi"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Güvənlik üçün tətbiq kontenti ekran paylaşımından gizlədildi"</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index e38706ea866c..858075ba4893 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -2408,6 +2408,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privatan prostor"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klonirano"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Zajedničko"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Osetljiv sadržaj obaveštenja je skriven"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije je skriven za deljenje sadržaja ekrana zbog bezbednosti"</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 25ae5a764360..2739cb212353 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -2409,6 +2409,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Прыватная прастора"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клон"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Супольны"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Канфідэнцыяльнае змесціва ў апавяшчэннях схавана"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Змесціва праграмы выключана з абагульвання экрана ў мэтах бяспекі"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 6b388d8d6e6d..0d4cadcae10b 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Частно пространство"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клониране"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Общи"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Деликатното съдържание в известието е скрито"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Съдържанието на приложението е скрито от функцията за споделяне на екрана от съображения за сигурност"</string> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index 3f338cce08aa..03fba4b39d94 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"প্রাইভেট স্পেস"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ক্লোন"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"কমিউনাল"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"সংবেদনশীল বিজ্ঞপ্তির কন্টেন্ট লুকানো আছে"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"নিরাপত্তার জন্য স্ক্রিন শেয়ার করা থেকে লুকানো অ্যাপের কন্টেন্ট"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 0438302d762b..6ce10c0c8907 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -2408,6 +2408,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privatni prostor"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Opće"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Sakriven je osjetljiv sadržaj obavještenja"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije je sakriven od dijeljenja ekrana radi sigurnosti"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 0287a27df115..4b1af3444446 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -2408,6 +2408,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espai privat"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Comunitari"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"S\'ha amagat contingut sensible de les notificacions"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Contingut de l\'aplicació amagat de la compartició de pantalla per motius de seguretat"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 4013a034a5c3..cc4bd3cfeb9a 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -2409,6 +2409,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Soukromý prostor"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Komunální"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Obsah citlivých oznámení je skrytý"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Obsah aplikace je z bezpečnostních důvodů při sdílení obrazovky skryt"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 5226d562384c..665ea1750b14 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privat område"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Fælles"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Følsomt indhold i notifikationen er skjult"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Af sikkerhedsmæssige årsager vises appindhold ikke ved skærmdeling"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 949150ac18c4..cd637e12b70a 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Vertrauliches Profil"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Gemeinsam genutzt"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Vertrauliche Benachrichtigungsinhalte ausgeblendet"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App-Inhalte werden aus Sicherheitsgründen bei der Bildschirmfreigabe ausgeblendet"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 11dac6c4e16b..09ecc2c5f22f 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Ιδιωτικός χώρος"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Κλώνος"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Κοινόχρηστο"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Έγινε απόκρυψη της ειδοποίησης ευαίσθητου περιεχομένου"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Για λόγους ασφάλειας, έγινε απόκρυψη του περιεχομένου της εφαρμογής από την κοινή χρήση οθόνης"</string> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 1effe7c8f7d1..20e391d173eb 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Private space"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Communal"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Sensitive notification content hidden"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 4abc5816a744..7f33f6a83c21 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Private space"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Communal"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Sensitive notification content hidden"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 425d88ce49ea..b7fedbe45d78 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Private space"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Communal"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Sensitive notification content hidden"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 56ff14aa994c..b83a7cfb877b 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Private space"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Communal"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Sensitive notification content hidden"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index e599c0355c8b..d358e5e37481 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Private space"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Communal"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Sensitive notification content hidden"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index f5859bf78846..45ea7ee341ae 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -2408,6 +2408,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espacio privado"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Compartido"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Se ocultó contenido sensible de la notificación"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Se ocultó el contenido de la app durante el uso compartido de la pantalla por motivos de seguridad"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index d8b1f59a721d..19c5f842acc7 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -273,7 +273,7 @@ <string name="bugreport_option_full_title" msgid="7681035745950045690">"Informe completo"</string> <string name="bugreport_option_full_summary" msgid="1975130009258435885">"Utiliza esta opción para que la interferencia del sistema sea mínima cuando el dispositivo no responda o funcione demasiado lento, o bien cuando necesites todas las secciones del informe. No permite introducir más detalles ni hacer más capturas de pantalla."</string> <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{La captura de pantalla para el informe de errores se hará en # segundo.}many{La captura de pantalla para el informe de errores se hará en # segundos.}other{La captura de pantalla para el informe de errores se hará en # segundos.}}"</string> - <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Se ha hecho la captura de pantalla con el informe de errores"</string> + <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Captura de pantalla generada con el informe de errores"</string> <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"No se ha podido hacer la captura de pantalla con el informe de errores"</string> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo Silencio"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"El sonido está desactivado. Activar"</string> @@ -2408,6 +2408,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espacio privado"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Común"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Contenido sensible de la notificación oculto"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Contenido de la aplicación oculto en pantalla compartida por motivos de seguridad"</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 77e665aa87a9..46c7341f2725 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privaatne ruum"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Kloon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Ühine"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Märguande delikaatne sisu peideti"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Rakenduse sisu on ekraani jagamises turvalisuse huvides peidetud"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 9bf2a4d0380e..3c47f68bad97 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Eremu pribatua"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klona"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Partekatua"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Jakinarazpenaren kontuzko edukia ezkutatu da"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Aplikazioko edukia ezkutatu egin da pantaila partekatzeko eginbidetik, segurtasuna bermatzeko"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 308260f0019d..3c50b070f9d3 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"فضای خصوصی"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"همسانهسازی"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"همگانی"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"محتوای اعلان حساس پنهان شده است"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"بهدلایل امنیتی، محتوای برنامه از دید همرسانی صفحهنمایش پنهان شد"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index db579f223781..0e159f2a83a6 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Yksityinen tila"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klooni"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Yhteinen"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Arkaluontoisen ilmoituksen sisältö piilotettu"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sovelluksen sisältö piilotettu näytön jakamiselta turvallisuussyistä"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index a2443d7b1656..7fca5e67a7bd 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -717,7 +717,7 @@ <string name="face_acquired_too_right" msgid="6245286514593540859">"Déplacez le téléphone vers la gauche"</string> <string name="face_acquired_too_left" msgid="9201762240918405486">"Déplacez le téléphone vers la droite"</string> <string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Veuillez regarder plus directement votre appareil."</string> - <string name="face_acquired_not_detected" msgid="1057966913397548150">"Visage non détecté. Tenez votre téléphone à hauteur des yeux."</string> + <string name="face_acquired_not_detected" msgid="1057966913397548150">"Visage non détecté. Tenez le téléphone au niveau des yeux."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Trop de mouvement. Tenez le téléphone immobile."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Veuillez inscrire votre visage à nouveau."</string> <string name="face_acquired_too_different" msgid="4505278456634706967">"Visage non reconnu. Réessayez."</string> @@ -2408,6 +2408,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espace privé"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Commun"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Le contenu confidentiel de la notification est masqué"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Le contenu de l\'application est masqué du Partage d\'écran par mesure de sécurité"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index c69af7c341b2..e08f4269eebd 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -2408,6 +2408,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espace privé"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Commun"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Le contenu sensible de la notification a été masqué"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Le contenu de l\'appli est masqué lors du partage d\'écran pour des raisons de sécurité"</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 0ffd299378df..1eec828b8ad1 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espazo privado"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clonado"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Compartido"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Contido confidencial da notificación oculto"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Por motivos de seguranza, ocultouse o contido da aplicación para que no se mostre na pantalla compartida"</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 55032c9301af..303f00125ee1 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"ખાનગી સ્પેસ"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ક્લોન"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"કૉમ્યુનલ"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"સંવેદનશીલ માહિતીવાળા નોટિફિકેશનનું કન્ટેન્ટ છુપાવ્યું"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"સુરક્ષા માટે સ્ક્રીન શેર કરતી વખતે ઍપનું કન્ટેન્ટ છુપાવેલું છે"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index e47715ab25f2..14d2bf7086c9 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"प्राइवेट स्पेस"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"क्लोन"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"कम्यूनिटी"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"संवेदनशील जानकारी वाली सूचना का कॉन्टेंट छिपा है"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"स्क्रीन शेयर करने के दौरान सुरक्षा के लिए, ऐप्लिकेशन का कॉन्टेंट छिपाया गया"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 0b9b662397f2..e69a59d969cf 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -1413,7 +1413,7 @@ <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Omogućen je način testnog okvira"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Vratite na tvorničke postavke da biste onemogućili način testnog okvira."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Serijska konzola omogućena"</string> - <string name="console_running_notification_message" msgid="7892751888125174039">"Izvedba je otežana. Provjerite početni program za pokretanje da biste onemogućili konzolu."</string> + <string name="console_running_notification_message" msgid="7892751888125174039">"Izvedba je otežana. Provjerite pokretač operativnog sustava da biste onemogućili konzolu."</string> <string name="mte_override_notification_title" msgid="4731115381962792944">"Omogućen je eksperimentalni MTE"</string> <string name="mte_override_notification_message" msgid="2441170442725738942">"To može utjecati na izvedbu i stabilnost. Ponovno pokrenite da biste onemogućili. Ako je omogućeno pomoću arm64.memtag.bootctl, prethodno postavite na \"none\"."</string> <string name="usb_contaminant_detected_title" msgid="4359048603069159678">"Tekućina ili prljavština u USB priključku"</string> @@ -2408,6 +2408,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privatni prostor"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Zajedničko"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Skriven je osjetljiv sadržaj obavijesti"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije sakriven je od dijeljenja zaslona radi sigurnosti"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index de6777e8bce7..f1ff23613ab6 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privát terület"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klón"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Közös"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Bizalmas értesítéstartalom elrejtve"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"A biztonság érdekében a képernyőmegosztástól elrejtett alkalmazástartalom"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 58331c7a1b3b..40812068752a 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Մասնավոր տարածք"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Կլոն"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Ընդհանուր"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Ծանուցման զգայուն բովանդակությունը թաքցված է"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Անվտանգության նկատառումներից ելնելով՝ հավելվածի բովանդակությունը թաքցվել է էկրանի ցուցադրումից"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index eeaf2b6514fa..866e9468ae3b 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Ruang privasi"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Umum"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Konten notifikasi sensitif disembunyikan"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Konten aplikasi disembunyikan dari berbagi layar untuk alasan keamanan"</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 7e68a06cc9f8..76ba64bc9d4f 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Leynirými"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Afrit"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Sameiginlegt"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Viðkvæmt tilkynningaefni falið"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Efni forrits falið í skjádeilingu af öryggisástæðum"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 5ed3706a538d..5e87dcec0736 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -2037,7 +2037,7 @@ <string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"Tocca per visualizzare i file"</string> <string name="pin_target" msgid="8036028973110156895">"Fissa"</string> <string name="pin_specific_target" msgid="7824671240625957415">"Blocca <xliff:g id="LABEL">%1$s</xliff:g>"</string> - <string name="unpin_target" msgid="3963318576590204447">"Sgancia"</string> + <string name="unpin_target" msgid="3963318576590204447">"Sblocca"</string> <string name="unpin_specific_target" msgid="3859828252160908146">"Sblocca <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="app_info" msgid="6113278084877079851">"Informazioni app"</string> <string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string> @@ -2408,6 +2408,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Spazio privato"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Condiviso"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Contenuti sensibili della notifica nascosti"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Contenuti dell\'app nascosti dalla condivisione schermo per sicurezza"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index a1e72da42cae..439565d5951c 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -2408,6 +2408,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"המרחב הפרטי"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"שכפול"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"שיתופי"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"יש תוכן רגיש בהתראה שהוסתר"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"תוכן האפליקציה מוסתר משיתוף המסך מטעמי אבטחה"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 04e47a782e12..fcaef68c6ebf 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -716,7 +716,7 @@ <string name="face_acquired_too_right" msgid="6245286514593540859">"スマートフォンを左に動かしてください"</string> <string name="face_acquired_too_left" msgid="9201762240918405486">"スマートフォンを右に動かしてください"</string> <string name="face_acquired_poor_gaze" msgid="4427153558773628020">"もっとまっすぐデバイスに顔を向けてください。"</string> - <string name="face_acquired_not_detected" msgid="1057966913397548150">"顔を確認できません。スマートフォンを目の高さに合わせます。"</string> + <string name="face_acquired_not_detected" msgid="1057966913397548150">"顔を確認できません。目の高さに合わせてください"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"あまり動かさないでください。安定させてください。"</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"顔を登録し直してください。"</string> <string name="face_acquired_too_different" msgid="4505278456634706967">"顔を認識できません。もう一度お試しください。"</string> @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"プライベート スペース"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"複製"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"共用"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"プライベートな通知内容は表示されません"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"セキュリティ上、画面共有ではアプリの内容は非表示となります"</string> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index ef37d4f8b551..2b98c58ff272 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"კერძო სივრცე"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"კლონის შექმნა"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"საერთო"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"სენსიტიური შეტყობინების კონტენტი დამალულია"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ეკრანის გაზიარებიდან აპის კონტენტი დამალულია უსაფრთხოების მიზნით"</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index f36d9fca2a35..6e9eb1220b50 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Құпия кеңістік"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клон"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Жалпы"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Хабарландырудың құпия контенті жасырылған."</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Қауіпсіздік мақсатында қолданба контенті экранды көрсету кезінде жасырылды."</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 195eb133c872..70f59c1c9235 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"លំហឯកជន"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ក្លូន"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ទូទៅ"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"បានលាក់ខ្លឹមសារជូនដំណឹងដែលមានលក្ខណៈរសើប"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"បានលាក់ខ្លឹមសារកម្មវិធីពីការបង្ហាញអេក្រង់ដើម្បីសុវត្ថិភាព"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 073e44885f6c..f22c43a4dd03 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"ಪ್ರೈವೆಟ್ ಸ್ಪೇಸ್"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ಕ್ಲೋನ್"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ಸಮುದಾಯ"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"ಸೂಕ್ಷ್ಮ ನೋಟಿಫಿಕೇಶನ್ ಕಂಟೆಂಟ್ ಅನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ಭದ್ರತೆಗಾಗಿ ಸ್ಕ್ರೀನ್ ಹಂಚಿಕೊಳ್ಳುವಿಕೆಯಲ್ಲಿ ಆ್ಯಪ್ ಕಂಟೆಂಟ್ ಅನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index bbe8aef4bc70..99b871579c1c 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"비공개 스페이스"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"클론"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"공동"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"민감한 알림 콘텐츠 숨김"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"보안을 위해 화면 공유에서 앱 콘텐츠가 숨겨집니다."</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 9686a141d528..427010b0e356 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Жеке мейкиндик"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клон"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Жалпы"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Купуя билдирменин мазмуну жашырылган"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Коопсуздук үчүн колдонмодогу контент бөлүшүлгөн экрандан жашырылды"</string> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index b6bd4b2dec51..4682bb0f1a93 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"ພື້ນທີ່ສ່ວນບຸກຄົນ"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ໂຄລນ"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ສ່ວນກາງ"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"ເນື້ອຫາການແຈ້ງເຕືອນທີ່ລະອຽດອ່ອນເຊື່ອງຢູ່"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ເນື້ອຫາແອັບຖືກເຊື່ອງໄວ້ຈາກການແບ່ງປັນໜ້າຈໍເພື່ອຄວາມປອດໄພ"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 2b4f370ffc45..6fbb9b829164 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -2409,6 +2409,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privati erdvė"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klonuoti"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Bendruomenės"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Neskelbtinos informacijos pranešimo turinys paslėptas"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Programos turinys paslėptas bendrinant ekraną saugumo sumetimais"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 3669f041f877..0bea4ff64fbf 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -2408,6 +2408,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privātā telpa"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klons"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Kopīgs"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Sensitīvs paziņojuma saturs ir paslēpts"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Drošības nolūkos lietotnes saturs kopīgotajā ekrānā ir paslēpts"</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 8902619d341d..d7a6dd2902cc 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Приватен простор"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клониран профил"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Профил на заедницата"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Содржината на чувствителните известувања е скриена"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Од безбедносни причини, содржините на апликацијата се скриени од споделувањето екран"</string> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 005d7cb5da4f..402333699754 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"സ്വകാര്യ സ്പേസ്"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ക്ലോൺ ചെയ്യുക"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"കമ്മ്യൂണൽ"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"സൂക്ഷ്മമായി കൈകാര്യം ചെയ്യേണ്ട അറിയിപ്പ് ഉള്ളടക്കം മറച്ചിരിക്കുന്നു"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ആപ്പ് ഉള്ളടക്കം, അതിന്റെ സുരക്ഷയ്ക്കായി സ്ക്രീൻ പങ്കിടലിൽ നിന്ന് മറച്ചിരിക്കുന്നു"</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index f7bf6ca2a6f5..9aa18e2d4b82 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Хаалттай орон зай"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клон"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Нийтийн"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Эмзэг мэдэгдлийн контентыг нуусан"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Аюулгүй байдлын улмаас аппын контентыг дэлгэц хуваалцахаас нуусан"</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 77a58aff3157..a115e2c61724 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"खाजगी स्पेस"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"क्लोन"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"सामुदायिक"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"संवेदनशील नोटिफिकेशनचा आशय लपवलेला आहे"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"स्क्रीन शेअर करताना सुरक्षेसाठी अॅपमधील आशय लपवला आहे"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 96691f60b151..2fa571ceb8a0 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Ruang persendirian"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Umum"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Kandungan pemberitahuan yang sensitif disembunyikan"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Kandungan apl disembunyikan daripada perkongsian skrin untuk keselamatan"</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index c1b782236a65..364a7b169c50 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"သီးသန့်နေရာ"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ပုံတူပွားရန်"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"အများသုံး"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"သတိထားရမည့် အကြောင်းကြားချက်ပါ အချက်အလက်ကို ဖျောက်ထားသည်"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"အက်ပ်အကြောင်းအရာသည် လုံခြုံရေးအတွက် မျက်နှာပြင် မျှဝေခြင်းမှ ဖျောက်ထားသည်"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 23f675e73f78..e2de428b1e93 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -342,7 +342,7 @@ <string name="permgrouplab_calllog" msgid="7926834372073550288">"Samtalelogger"</string> <string name="permgroupdesc_calllog" msgid="2026996642917801803">"lese og skrive samtaleloggen"</string> <string name="permgrouplab_phone" msgid="570318944091926620">"Telefon"</string> - <string name="permgroupdesc_phone" msgid="270048070781478204">"ring og administrer anrop"</string> + <string name="permgroupdesc_phone" msgid="270048070781478204">"ringe og administrere anrop"</string> <string name="permgrouplab_sensors" msgid="9134046949784064495">"Kroppssensorer"</string> <string name="permgroupdesc_sensors" msgid="2610631290633747752">"få tilgang til sensordata om de vitale tegnene dine"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Varsler"</string> @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privat område"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Felles"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Sensitivt varselinnhold er skjult"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Av sikkerhetsgrunner er appinnholdet skjult for skjermdelingen"</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index d25a7a35e3df..8d5f560d521a 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"निजी स्पेस"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"क्लोन"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"सामुदायिक"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"संवेदनशील सूचनासम्बन्धी सामग्री लुकाइएको छ"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"स्क्रिन सेयर गर्दा सुरक्षाका लागि एपमा भएको सामग्री लुकाइएको छ"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 0b2c507b644f..5bc6c4421339 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privégedeelte"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Kloon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Gemeenschappelijk"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Content van gevoelige meldingen verborgen"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App-content verborgen voor scherm delen vanwege beveiligingsrisico\'s"</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index f3cd70e83db1..4c7868d03914 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -1751,7 +1751,7 @@ <string name="color_correction_feature_name" msgid="7975133554160979214">"ରଙ୍ଗ ସଂଶୋଧନ"</string> <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ଏକ-ହାତ ମୋଡ୍"</string> <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ଅତ୍ୟଧିକ ଡିମ"</string> - <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ହିଅରିଂ ଡିଭାଇସଗୁଡ଼ିକ"</string> + <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ଶ୍ରବଣ ଡିଭାଇସଗୁଡ଼ିକ"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ଭଲ୍ୟୁମ୍ କୀ\'ଗୁଡ଼ିକୁ ଧରି ରଖାଯାଇଛି। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ଚାଲୁ ହୋଇଛି।"</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ଭଲ୍ୟୁମ୍ କୀ\'ଗୁଡ଼ିକୁ ଧରି ରଖାଯାଇଛି। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ବନ୍ଦ ହୋଇଛି।"</string> <string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"ଭଲ୍ୟୁମ କୀ\'ଗୁଡ଼ିକୁ ରିଲିଜ କରନ୍ତୁ। <xliff:g id="SERVICE_NAME">%1$s</xliff:g>କୁ ଚାଲୁ କରିବା ପାଇଁ ଉଭୟ ଭଲ୍ୟୁମ କୀ\'କୁ ପୁଣି 3 ସେକେଣ୍ଡ ପାଇଁ ଦବାଇ ଧରି ରଖନ୍ତୁ।"</string> @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"ପ୍ରାଇଭେଟ ସ୍ପେସ"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"କ୍ଲୋନ"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"କମ୍ୟୁନାଲ"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"ସମ୍ୱେଦନଶୀଳ ବିଜ୍ଞପ୍ତି ବିଷୟବସ୍ତୁକୁ ଲୁଚାଯାଇଛି"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ସୁରକ୍ଷା ପାଇଁ ସ୍କ୍ରିନ ସେୟାରରୁ ଆପ ବିଷୟବସ୍ତୁକୁ ଲୁଚାଯାଇଛି"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 60d8737405da..38780b610f18 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ਕਲੋਨ"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ਭਾਈਚਾਰਕ"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"ਲੁਕੀ ਹੋਈ ਸੰਵੇਦਨਸ਼ੀਲ ਸੂਚਨਾ ਸਮੱਗਰੀ"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ਐਪ ਸਮੱਗਰੀ ਨੂੰ ਸੁਰੱਖਿਆ ਲਈ ਸਕ੍ਰੀਨ ਸਾਂਝਾਕਰਨ ਤੋਂ ਲੁਕਾਇਆ ਗਿਆ ਹੈ"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index ec5fee76d73d..95e1a30a6dd4 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -2409,6 +2409,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Przestrzeń prywatna"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Wspólny"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Treść poufnego powiadomienia została ukryta"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Ze względów bezpieczeństwa zawartość aplikacji jest niewidoczna podczas udostępniania ekranu"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 807c4ce9521d..c9d36b149fdf 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -2408,6 +2408,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espaço privado"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Público"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Conteúdo de notificação sensível oculto"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo do app oculto no compartilhamento de tela por motivos de segurança"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 0dcf4c5dd741..f1b2bd07acca 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -2408,6 +2408,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espaço privado"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Comum"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Conteúdo das notificações sensíveis ocultado"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo da app ocultado da partilha de ecrã por motivos de segurança"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 807c4ce9521d..c9d36b149fdf 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -2408,6 +2408,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espaço privado"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Público"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Conteúdo de notificação sensível oculto"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo do app oculto no compartilhamento de tela por motivos de segurança"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index bf82cd8cb5b7..e14aec706cb7 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -2408,6 +2408,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Spațiu privat"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clonă"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Comun"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Conținutul sensibil din notificări a fost ascuns"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conținutul aplicației este ascuns de permiterea accesului la ecran din motive de securitate"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index c1900a86487a..79b0daa445fa 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -2409,6 +2409,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Частное пространство"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клонированный"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Совместный"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Конфиденциальная информация в уведомлении скрыта"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Содержимое приложения исключено из демонстрации экрана в целях безопасности."</string> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index f216ce2da9fe..1e69e0bc9911 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"රහසිගත අවකාශය"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ක්ලෝන කරන්න"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"වාර්ගික"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"සංවේදී දැනුම්දීම් අන්තර්ගතය සැඟවී ඇත"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ආරක්ෂාව සඳහා යෙදුම් අන්තර්ගතය තිරය බෙදා ගැනීමෙන් සඟවා ඇත"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 9c2a87537a4b..c7ca9f471942 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -2409,6 +2409,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Súkromný priestor"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Spoločný"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Obsah citlivého upozornenia je skrytý"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Obsah aplikácie bol na účely zabezpečenia skrytý v zdieľaní obrazovky"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index b3530e716b2f..4f23a546376d 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -2409,6 +2409,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Zasebni prostor"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Skupno"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Občutljiva vsebina obvestila je bila skrita"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Pri deljenju zaslona je vsebina aplikacije skrita zaradi varnosti"</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index d577e7b8ea05..c49402bc2cc5 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Hapësira private"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"I përbashkët"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Përmbajtjet delikate të njoftimeve janë fshehur"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Përmbajtja e aplikacionit është fshehur nga ndarja e ekranit për arsye sigurie"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 301fe244bbf1..2b3f75a60555 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -2408,6 +2408,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Приватан простор"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клонирано"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Заједничко"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Осетљив садржај обавештења је скривен"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Садржај апликације је скривен за дељење садржаја екрана због безбедности"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index b3c2063a6df7..28333815e1d0 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privat område"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klona"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Allmän"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Känsligt aviseringsinnehåll dolt"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Av säkerhetsskäl döljs appinnehållet vid skärmdelning"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index f15796e5241b..d3af99f7798f 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Sehemu ya faragha"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Nakala"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Wasifu wa pamoja"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Maudhui nyeti kwenye arifa yamefichwa"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Maudhui ya programu yamefichwa ili yasionekane kwenye skrini ya pamoja kwa sababu za kiusalama"</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 0f2805d14677..37abcef212cf 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"ரகசிய இடம்"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"குளோன்"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"பொது"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"உணர்வுபூர்வமான அறிவிப்பு உள்ளடக்கம் மறைக்கப்பட்டது"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"பாதுகாப்பிற்காக, திரைப் பகிர்வில் இருந்து ஆப்ஸ் உள்ளடக்கம் மறைக்கப்பட்டுள்ளது"</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index b4484133da64..2766248dabbd 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -1301,7 +1301,7 @@ <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"గేమ్ను ఎంచుకోండి"</string> <string name="heavy_weight_switcher_text" msgid="6814316627367160126">"మెరుగైన పనితీరు పొందడానికి, ఈ గేమ్లలో ఒకసారికి ఒక్కటి మాత్రమే తెరవగలరు."</string> <string name="old_app_action" msgid="725331621042848590">"<xliff:g id="OLD_APP">%1$s</xliff:g>కి తిరిగి వెళ్లు"</string> - <string name="new_app_action" msgid="547772182913269801">"<xliff:g id="NEW_APP">%1$s</xliff:g>ని తెరువు"</string> + <string name="new_app_action" msgid="547772182913269801">"<xliff:g id="NEW_APP">%1$s</xliff:g>ను తెరవండి"</string> <string name="new_app_description" msgid="1958903080400806644">"<xliff:g id="OLD_APP">%1$s</xliff:g> సేవ్ చేయకుండానే మూసివేయబడుతుంది"</string> <string name="dump_heap_notification" msgid="5316644945404825032">"<xliff:g id="PROC">%1$s</xliff:g> మెమరీ పరిమితిని మించిపోయింది"</string> <string name="dump_heap_ready_notification" msgid="2302452262927390268">"<xliff:g id="PROC">%1$s</xliff:g> హీప్ డంప్ సిద్ధంగా ఉంది"</string> @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"ప్రైవేట్ స్పేస్"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"క్లోన్"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"కమ్యూనల్"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"గోప్యమైన నోటిఫికేషన్ కంటెంట్ దాచబడింది"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"సెక్యూరిటీ కోసం స్క్రీన్ షేర్ నుండి యాప్ కంటెంట్ దాచబడింది"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index e34b526ba940..1f2a0911ff5f 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"พื้นที่ส่วนตัว"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"โคลน"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ส่วนกลาง"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"เนื้อหาการแจ้งเตือนที่ละเอียดอ่อนซ่อนอยู่"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ซ่อนเนื้อหาแอปจากการแชร์หน้าจอเพื่อความปลอดภัย"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 4288460e6e97..7bce4b78c437 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Pribadong space"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Communal"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Nakatago ang content ng sensitibong notification"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Nakatago ang content ng app mula sa pagbabahagi ng screen para sa seguridad"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 906ccbc2ddc7..cbfb77037e73 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Özel alan"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Paylaşılan"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Hassas bildirim içerikleri gizlendi"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Uygulama içerikleri, güvenlik nedeniyle ekran paylaşımında gizlendi"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index cc9df2e09efc..5266acde1ecb 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -2409,6 +2409,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Приватний простір"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Копія профілю"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Спільний профіль"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Чутливий вміст сповіщення приховано"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"З міркувань безпеки вміст додатка приховано під час показу екрана"</string> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index c0be641c84c7..2fe52f83d09a 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"پرائیویٹ اسپیس"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"کلون"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"کمیونل"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"حساس اطلاعی مواد چھپا ہوا ہے"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"سیکیورٹی کے مد نظر ایپ کا مواد اسکرین کے اشتراک سے چھپا ہوا ہے"</string> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index 517176b33a02..d40f38338138 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Maxfiy makon"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Nusxalash"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Umumiy"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Bildirishnomadagi maxfiy axborot berkitildi"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Ekran namoyishida xavfsizlik maqsadida ilova kontenti berkitildi"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index e6db9dd4c680..1051cdab6599 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -306,7 +306,7 @@ <string name="notification_channel_foreground_service" msgid="7102189948158885178">"Các ứng dụng tiêu thụ pin"</string> <string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Phóng to"</string> <string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Việc sử dụng tính năng hỗ trợ tiếp cận"</string> - <string name="notification_channel_display" msgid="6905032605735615090">"Màn hình"</string> + <string name="notification_channel_display" msgid="6905032605735615090">"Hiển thị"</string> <string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang sử dụng pin"</string> <string name="foreground_service_apps_in_background" msgid="7340037176412387863">"<xliff:g id="NUMBER">%1$d</xliff:g> ứng dụng đang sử dụng pin"</string> <string name="foreground_service_tap_for_details" msgid="9078123626015586751">"Nhấn để biết chi tiết về mức sử dụng dữ liệu và pin"</string> @@ -1098,8 +1098,8 @@ <string name="js_dialog_before_unload_negative_button" msgid="3873765747622415310">"Ở lại trang này"</string> <string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nBạn có chắc chắn muốn điều hướng khỏi trang này không?"</string> <string name="autofill_window_title" msgid="4379134104008111961">"Tự động điền với <xliff:g id="SERVICENAME">%1$s</xliff:g>"</string> - <string name="permlab_setAlarm" msgid="1158001610254173567">"đặt báo thức"</string> - <string name="permdesc_setAlarm" msgid="2185033720060109640">"Cho phép ứng dụng đặt báo thức trong ứng dụng đồng hồ báo thức được cài đặt. Một số ứng dụng đồng hồ báo thức có thể không thực thi tính năng này."</string> + <string name="permlab_setAlarm" msgid="1158001610254173567">"đặt chuông báo"</string> + <string name="permdesc_setAlarm" msgid="2185033720060109640">"Cho phép ứng dụng đặt chuông báo trong ứng dụng đồng hồ được cài đặt. Một số ứng dụng đồng hồ có thể không có năng này."</string> <string name="permlab_addVoicemail" msgid="4770245808840814471">"thêm thư thoại"</string> <string name="permdesc_addVoicemail" msgid="5470312139820074324">"Cho phép ứng dụng thêm thông báo vào hộp thư thoại đến của bạn."</string> <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> đã dán dữ liệu từ bảng nhớ tạm của bạn"</string> @@ -1329,7 +1329,7 @@ <string name="ringtone_default_with_actual" msgid="2709686194556159773">"Mặc định (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> <string name="ringtone_silent" msgid="397111123930141876">"Không"</string> <string name="ringtone_picker_title" msgid="667342618626068253">"Nhạc chuông"</string> - <string name="ringtone_picker_title_alarm" msgid="7438934548339024767">"Âm thanh báo thức"</string> + <string name="ringtone_picker_title_alarm" msgid="7438934548339024767">"Âm thanh chuông báo"</string> <string name="ringtone_picker_title_notification" msgid="6387191794719608122">"Âm thanh thông báo"</string> <string name="ringtone_unknown" msgid="5059495249862816475">"Không xác định"</string> <string name="wifi_available_sign_in" msgid="381054692557675237">"Đăng nhập vào mạng Wi-Fi"</string> @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Không gian riêng tư"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Nhân bản"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Dùng chung"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Đã ẩn nội dung thông báo nhạy cảm"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Nội dung ứng dụng bị ẩn khỏi tính năng chia sẻ màn hình vì lý do bảo mật"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 4b0494004dd7..d16a353e9bfc 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"私密空间"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"克隆"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"共用"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"已隐藏敏感通知内容"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"为安全起见而在屏幕共享画面中处于隐藏状态的应用内容"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 1aa9c72c8cb9..672a638e6932 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"私人空間"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"複製"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"共用"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"已隱藏敏感通知內容"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"為安全起見,應用程式內容已從分享螢幕畫面隱藏"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index eaed7d2c76c9..8a224ed24675 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"私人空間"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"複製"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"共通"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"系統已隱藏含有私密資訊的通知內容"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"為安全起見,分享螢幕畫面未顯示應用程式內容"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index ba3ae9f07340..27bd3c949c14 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -2407,6 +2407,8 @@ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Indawo engasese"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Yenza i-Clone"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Okomphakathi"</string> + <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) --> + <skip /> <string name="redacted_notification_message" msgid="1520587845842228816">"Okuqukethwe kwesaziso esizwelayo kufihliwe"</string> <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Okuqukethwe kwe-app kufihliwe kusuka ekwabelaneni kwesikrini ngokuvikelwa"</string> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 405324bf76af..c74bc9ba6e75 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -9702,6 +9702,12 @@ <attr name="hotSpotY" format="dimension" /> </declare-styleable> + <!-- @hide --> + <declare-styleable name="PointerIconVectorTheme"> + <attr name="pointerIconVectorFill" format="color" /> + <attr name="pointerIconVectorFillInverse" format="color" /> + </declare-styleable> + <declare-styleable name="Storage"> <!-- path to mount point for the storage. --> <attr name="mountPoint" format="string" /> diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml index dcda5d8669a4..fba95a5e41b4 100644 --- a/core/res/res/values/config_telephony.xml +++ b/core/res/res/values/config_telephony.xml @@ -409,4 +409,10 @@ <bool name="config_force_phone_globals_creation">false</bool> <java-symbol type="bool" name="config_force_phone_globals_creation" /> + <!-- Boolean indicating whether to enable persistent logging via DropBoxManager. + Used in persisting SOS/emergency related log messages. + --> + <bool name="config_dropboxmanager_persistent_logging_enabled">false</bool> + <java-symbol type="bool" name="config_dropboxmanager_persistent_logging_enabled" /> + </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 87141c790f0c..b547a7a00ba8 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -6473,6 +6473,9 @@ ul.</string> <!-- Accessibility label for clone profile user type [CHAR LIMIT=30] --> <string name="accessibility_label_communal_profile">Communal</string> + <!-- Label for private space biometric prompt logo description [CHAR LIMIT=30] --> + <string name="private_space_biometric_prompt_title">Private space</string> + <!-- Notification message used when a notification's normal message contains sensitive information [CHAR_LIMIT=NOTIF_BODY] --> <string name="redacted_notification_message">Sensitive notification content hidden</string> <!-- Notification action title used instead of a notification's normal title sensitive [CHAR_LIMIT=NOTIF_BODY] --> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index a46dc045269d..50c3b1a93d75 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -1497,6 +1497,36 @@ please see styles_device_defaults.xml. </style> <!-- @hide --> + <style name="PointerIconVectorStyleFillBlack"> + <item name="pointerIconVectorFill">@color/black</item> + <item name="pointerIconVectorFillInverse">@color/white</item> + </style> + + <!-- @hide --> + <style name="PointerIconVectorStyleFillGreen"> + <item name="pointerIconVectorFill">#6DD58C</item> + <item name="pointerIconVectorFillInverse">#6DD58C</item> + </style> + + <!-- @hide --> + <style name="PointerIconVectorStyleFillYellow"> + <item name="pointerIconVectorFill">#FDD663</item> + <item name="pointerIconVectorFillInverse">#FDD663</item> + </style> + + <!-- @hide --> + <style name="PointerIconVectorStyleFillPink"> + <item name="pointerIconVectorFill">#F2B8B5</item> + <item name="pointerIconVectorFillInverse">#F2B8B5</item> + </style> + + <!-- @hide --> + <style name="PointerIconVectorStyleFillBlue"> + <item name="pointerIconVectorFill">#8AB4F8</item> + <item name="pointerIconVectorFillInverse">#8AB4F8</item> + </style> + + <!-- @hide --> <style name="aerr_list_item" parent="Widget.Material.Light.Button.Borderless"> <item name="minHeight">?attr/listPreferredItemHeightSmall</item> <item name="textAppearance">?attr/textAppearanceListItemSmall</item> @@ -1690,4 +1720,12 @@ please see styles_device_defaults.xml. parent="@style/Theme.DeviceDefault.Resolver"> <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item> </style> + + <!-- + TODO(b/309578419): Make activities go edge-to-edge properly and then remove this. + --> + <style name="GrantCredentialsPermissionActivity" + parent="@style/Theme.DeviceDefault.Light.DialogWhenLarge"> + <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item> + </style> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index bb73934450c9..cc74d023ee5e 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1116,6 +1116,7 @@ <java-symbol type="string" name="accessibility_label_private_profile" /> <java-symbol type="string" name="accessibility_label_clone_profile" /> <java-symbol type="string" name="accessibility_label_communal_profile" /> + <java-symbol type="string" name="private_space_biometric_prompt_title" /> <java-symbol type="string" name="mediasize_unknown_portrait" /> <java-symbol type="string" name="mediasize_unknown_landscape" /> <java-symbol type="string" name="mediasize_iso_a0" /> @@ -1694,6 +1695,12 @@ <java-symbol type="style" name="Pointer" /> <java-symbol type="style" name="LargePointer" /> <java-symbol type="style" name="VectorPointer" /> + <java-symbol type="style" name="PointerIconVectorStyleFillBlack" /> + <java-symbol type="style" name="PointerIconVectorStyleFillGreen" /> + <java-symbol type="style" name="PointerIconVectorStyleFillYellow" /> + <java-symbol type="style" name="PointerIconVectorStyleFillPink" /> + <java-symbol type="style" name="PointerIconVectorStyleFillBlue" /> + <java-symbol type="attr" name="pointerIconVectorFill" /> <java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Title" /> <java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Info" /> diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java index 30ec940bda8e..b64eeca04101 100644 --- a/core/tests/coretests/src/android/app/NotificationTest.java +++ b/core/tests/coretests/src/android/app/NotificationTest.java @@ -703,10 +703,10 @@ public class NotificationTest { hugeIcon).build(); Bitmap smallNotificationIcon = notification.getSmallIcon().getBitmap(); - assertThat(smallNotificationIcon.getWidth()).isEqualTo( + assertThat((float) smallNotificationIcon.getWidth()).isWithin(3f).of( mContext.getResources().getDimensionPixelSize( R.dimen.notification_small_icon_size)); - assertThat(smallNotificationIcon.getHeight()).isEqualTo( + assertThat((float) smallNotificationIcon.getHeight()).isWithin(3f).of( mContext.getResources().getDimensionPixelSize( R.dimen.notification_small_icon_size)); } @@ -730,23 +730,23 @@ public class NotificationTest { Notification notification = new Notification.Builder(mContext, "Channel").setStyle( style).build(); - int targetSize = mContext.getResources().getDimensionPixelSize( + float targetSize = mContext.getResources().getDimensionPixelSize( ActivityManager.isLowRamDeviceStatic() ? R.dimen.notification_person_icon_max_size_low_ram : R.dimen.notification_person_icon_max_size); Bitmap personIcon = style.getUser().getIcon().getBitmap(); - assertThat(personIcon.getWidth()).isEqualTo(targetSize); - assertThat(personIcon.getHeight()).isEqualTo(targetSize); + assertThat((float) personIcon.getWidth()).isWithin(3f).of(targetSize); + assertThat((float) personIcon.getHeight()).isWithin(3f).of(targetSize); Bitmap avatarIcon = style.getMessages().get(0).getSenderPerson().getIcon().getBitmap(); - assertThat(avatarIcon.getWidth()).isEqualTo(targetSize); - assertThat(avatarIcon.getHeight()).isEqualTo(targetSize); + assertThat((float) avatarIcon.getWidth()).isWithin(3f).of(targetSize); + assertThat((float) avatarIcon.getHeight()).isWithin(3f).of(targetSize); Bitmap historicAvatarIcon = style.getHistoricMessages().get( 0).getSenderPerson().getIcon().getBitmap(); - assertThat(historicAvatarIcon.getWidth()).isEqualTo(targetSize); - assertThat(historicAvatarIcon.getHeight()).isEqualTo(targetSize); + assertThat((float) historicAvatarIcon.getWidth()).isWithin(3f).of(targetSize); + assertThat((float) historicAvatarIcon.getHeight()).isWithin(3f).of(targetSize); } @Test @@ -760,10 +760,10 @@ public class NotificationTest { style).build(); Bitmap shortcutIcon = style.getShortcutIcon().getBitmap(); - assertThat(shortcutIcon.getWidth()).isEqualTo( + assertThat((float) shortcutIcon.getWidth()).isWithin(3f).of( mContext.getResources().getDimensionPixelSize( R.dimen.notification_small_icon_size)); - assertThat(shortcutIcon.getHeight()).isEqualTo( + assertThat((float) shortcutIcon.getHeight()).isWithin(3f).of( mContext.getResources().getDimensionPixelSize( R.dimen.notification_small_icon_size)); } diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java index f05390dff5cd..ae7f465baa87 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -32,6 +32,7 @@ import static android.view.WindowInsets.Type.ime; import static android.view.WindowInsets.Type.navigationBars; import static android.view.WindowInsets.Type.statusBars; import static android.view.WindowInsets.Type.systemBars; +import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; @@ -52,6 +53,9 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static java.util.concurrent.TimeUnit.SECONDS; + +import android.annotation.NonNull; import android.content.Context; import android.graphics.Insets; import android.graphics.Point; @@ -80,6 +84,8 @@ import org.mockito.ArgumentCaptor; import org.mockito.InOrder; import org.mockito.Mockito; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CountDownLatch; /** @@ -668,30 +674,58 @@ public class InsetsControllerTest { } @Test - public void testResizeAnimation_withFlagAnimateResizing() { + public void testResizeAnimation_withFlagAnimateResizing() throws InterruptedException { + final int id = ID_NAVIGATION_BAR; + final @InsetsType int type = navigationBars(); + final int fromInsetsHeight = 50; + final int toInsetsHeight = 60; + final ArrayList<WindowInsets> progressList = new ArrayList<>(); + final CountDownLatch animationEndLatch = new CountDownLatch(1); InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { - final int id = ID_NAVIGATION_BAR; - final @InsetsType int type = navigationBars(); final InsetsState state1 = new InsetsState(); state1.getOrCreateSource(id, type) .setVisible(true) - .setFrame(0, 0, 500, 50) + .setFrame(0, 0, 500, fromInsetsHeight) .setFlags(FLAG_ANIMATE_RESIZING, FLAG_ANIMATE_RESIZING); final InsetsState state2 = new InsetsState(state1, true /* copySources */); - state2.peekSource(id).setFrame(0, 0, 500, 60); + state2.peekSource(id).setFrame(0, 0, 500, toInsetsHeight); // New insets source won't cause the resize animation. mController.onStateChanged(state1); assertEquals("There must not be resize animation.", ANIMATION_TYPE_NONE, mController.getAnimationType(type)); + mViewRoot.getView().setWindowInsetsAnimationCallback( + new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) { + @Override + public WindowInsets onProgress( + @NonNull WindowInsets insets, + @NonNull List<WindowInsetsAnimation> runningAnimations) { + progressList.add(insets); + return insets; + } + + @Override + public void onEnd(@NonNull WindowInsetsAnimation animation) { + animationEndLatch.countDown(); + } + }); + // Changing frame of the source with FLAG_ANIMATE_RESIZING will cause the resize // animation. mController.onStateChanged(state2); assertEquals("There must be resize animation.", ANIMATION_TYPE_RESIZE, mController.getAnimationType(type)); + + mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw(); }); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + + assertTrue("Animation must be ended.", animationEndLatch.await(3, SECONDS)); + assertEquals("The first insets height must be the same as `fromInsetsHeight`", + fromInsetsHeight, progressList.get(0).getInsets(type).top); + assertEquals("The last insets height must be the same as `toInsetsHeight`", + toInsetsHeight, progressList.get(progressList.size() - 1).getInsets(type).top); } @Test diff --git a/core/tests/coretests/src/android/view/ViewFrameRateTest.java b/core/tests/coretests/src/android/view/ViewFrameRateTest.java index 1491d77b020b..35b984a5d86e 100644 --- a/core/tests/coretests/src/android/view/ViewFrameRateTest.java +++ b/core/tests/coretests/src/android/view/ViewFrameRateTest.java @@ -499,12 +499,9 @@ public class ViewFrameRateTest { toolkitFrameRateDefaultNormalReadOnly() ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH; } else { - // intermittent - // Even though this is not a small View, step 3 is triggered by this flag, which - // brings intermittent to LOW - expectedCategory = toolkitFrameRateBySizeReadOnly() - ? FRAME_RATE_CATEGORY_LOW - : FRAME_RATE_CATEGORY_NORMAL; + // intermittent. + // The expected category is normal. + expectedCategory = FRAME_RATE_CATEGORY_NORMAL; } mActivityRule.runOnUiThread(() -> { mMovingView.invalidate(); diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java index 5a6824bf0d7e..b5c264c4ae5e 100644 --- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java +++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java @@ -146,10 +146,6 @@ public class AccessibilityServiceConnectionImpl extends IAccessibilityServiceCon public void setMagnificationCallbackEnabled(int displayId, boolean enabled) {} - public boolean isMagnificationSystemUIConnected() { - return false; - } - public boolean setSoftKeyboardShowMode(int showMode) { return false; } diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java index 50d7f59f70e9..d4482f243939 100644 --- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java +++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java @@ -28,6 +28,7 @@ import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -111,7 +112,7 @@ public class WindowOnBackInvokedDispatcherTest { doReturn(mApplicationInfo).when(mContext).getApplicationInfo(); mDispatcher = new WindowOnBackInvokedDispatcher(mContext, Looper.getMainLooper()); - mDispatcher.attachToWindow(mWindowSession, mWindow, mImeBackAnimationController); + mDispatcher.attachToWindow(mWindowSession, mWindow, null, mImeBackAnimationController); } private void waitForIdle() { @@ -368,7 +369,7 @@ public class WindowOnBackInvokedDispatcherTest { callbackInfo.getCallback().onBackInvoked(); waitForIdle(); - verify(mCallback1).onBackInvoked(); + verify(mCallback1, timeout(/*millis*/ 1000)).onBackInvoked(); verify(mCallback1, never()).onBackCancelled(); } @@ -454,25 +455,26 @@ public class WindowOnBackInvokedDispatcherTest { @Test public void registerImeCallbacks_onBackInvokedCallbackEnabled() throws RemoteException { - mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mDefaultImeCallback); + verifyImeCallackRegistrations(); + } + + @Test + public void registerImeCallbacks_onBackInvokedCallbackDisabled() throws RemoteException { + doReturn(false).when(mApplicationInfo).isOnBackInvokedCallbackEnabled(); + verifyImeCallackRegistrations(); + } + + private void verifyImeCallackRegistrations() throws RemoteException { + // verify default callback is replaced with ImeBackAnimationController + mDispatcher.registerOnBackInvokedCallbackUnchecked(mDefaultImeCallback, PRIORITY_DEFAULT); assertCallbacksSize(/* default */ 1, /* overlay */ 0); assertSetCallbackInfo(); assertTopCallback(mImeBackAnimationController); - mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mImeCallback); + // verify regular ime callback is successfully registered + mDispatcher.registerOnBackInvokedCallbackUnchecked(mImeCallback, PRIORITY_DEFAULT); assertCallbacksSize(/* default */ 2, /* overlay */ 0); assertSetCallbackInfo(); assertTopCallback(mImeCallback); } - - @Test - public void registerImeCallbacks_legacyBack() throws RemoteException { - doReturn(false).when(mApplicationInfo).isOnBackInvokedCallbackEnabled(); - - mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mDefaultImeCallback); - assertNoSetCallbackInfo(); - - mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mImeCallback); - assertNoSetCallbackInfo(); - } } diff --git a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java index f79ba28d946f..af2a2bbe2893 100644 --- a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java +++ b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java @@ -48,7 +48,8 @@ public class RegisterStatusBarResultTest { final String dumyIconKey = "dummyIcon1"; final ArrayMap<String, StatusBarIcon> iconMap = new ArrayMap<>(); iconMap.put(dumyIconKey, new StatusBarIcon("com.android.internal.statusbar.test", - UserHandle.of(100), 123, 1, 2, "dummyIconDescription")); + UserHandle.of(100), 123, 1, 2, "dummyIconDescription", + StatusBarIcon.Type.SystemIcon)); final LetterboxDetails letterboxDetails = new LetterboxDetails( /* letterboxInnerBounds= */ new Rect(1, 2, 3, 4), /* letterboxFullBounds= */ new Rect(5, 6, 7, 8), diff --git a/core/tests/coretests/src/com/android/internal/statusbar/StatusBarIconTest.java b/core/tests/coretests/src/com/android/internal/statusbar/StatusBarIconTest.java index fe552a08f629..a895378eaaf9 100644 --- a/core/tests/coretests/src/com/android/internal/statusbar/StatusBarIconTest.java +++ b/core/tests/coretests/src/com/android/internal/statusbar/StatusBarIconTest.java @@ -44,7 +44,8 @@ public class StatusBarIconTest { final int dummyIconNumber = 2; final CharSequence dummyIconContentDescription = "dummyIcon"; final StatusBarIcon original = new StatusBarIcon(dummyIconPackageName, dummyUserHandle, - dummyIconId, dummyIconLevel, dummyIconNumber, dummyIconContentDescription); + dummyIconId, dummyIconLevel, dummyIconNumber, dummyIconContentDescription, + StatusBarIcon.Type.SystemIcon); final StatusBarIcon copy = clone(original); diff --git a/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java index 1dbb7758bf39..2b8adcbe0656 100644 --- a/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java +++ b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java @@ -20,6 +20,7 @@ import static android.view.DisplayCutout.NO_CUTOUT; import static android.view.View.MeasureSpec.EXACTLY; import static android.view.View.MeasureSpec.makeMeasureSpec; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.Matchers.is; @@ -69,6 +70,7 @@ public class ActionBarOverlayLayoutTest { private ViewGroup mContent; private ViewGroup mActionBarTop; + private ViewGroup mActionBarView; private Toolbar mToolbar; private FakeOnApplyWindowListener mContentInsetsListener; @@ -86,15 +88,22 @@ public class ActionBarOverlayLayoutTest { mContentInsetsListener = new FakeOnApplyWindowListener(); mContent.setOnApplyWindowInsetsListener(mContentInsetsListener); + // mActionBarView and mToolbar are supposed to be the same view. Here makes mToolbar a child + // of mActionBarView is to control the height of mActionBarView. In this way, the child + // views of mToolbar won't affect the measurement of mActionBarView or mActionBarTop. + mActionBarView = new FrameLayout(mContext); + mActionBarView.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, 20)); + + mToolbar = new Toolbar(mContext); + mToolbar.setId(com.android.internal.R.id.action_bar); + mActionBarView.addView(mToolbar); + mActionBarTop = new ActionBarContainer(mContext); mActionBarTop.setId(com.android.internal.R.id.action_bar_container); - mActionBarTop.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, 20)); + mActionBarTop.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT)); + mActionBarTop.addView(mActionBarView); mLayout.addView(mActionBarTop); mLayout.setActionBarHeight(20); - - mToolbar = new Toolbar(mContext); - mToolbar.setId(com.android.internal.R.id.action_bar); - mActionBarTop.addView(mToolbar); } @Test diff --git a/data/etc/Android.bp b/data/etc/Android.bp index 1410950966e9..050f9b5e264f 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -200,13 +200,3 @@ prebuilt_etc { src: "com.android.systemui.xml", filename_from_src: true, } - -filegroup { - name: "services.core.protolog.json", - srcs: ["services.core.protolog.json"], -} - -filegroup { - name: "file-core.protolog.pb", - srcs: ["core.protolog.pb"], -} diff --git a/data/etc/core.protolog.pb b/data/etc/core.protolog.pb Binary files differdeleted file mode 100644 index a105ba756d51..000000000000 --- a/data/etc/core.protolog.pb +++ /dev/null diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json deleted file mode 100644 index db68f9528151..000000000000 --- a/data/etc/services.core.protolog.json +++ /dev/null @@ -1,4870 +0,0 @@ -{ - "version": "2.0.0", - "messages": { - "7286191062634870297": { - "message": "Binding proc %s with config %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/am\/ActivityManagerService.java" - }, - "-4921282642721622589": { - "message": "Report configuration: %s %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityClientController.java" - }, - "-1597980207704427048": { - "message": "Frontmost changed immersion: %s", - "level": "DEBUG", - "group": "WM_DEBUG_IMMERSIVE", - "at": "com\/android\/server\/wm\/ActivityClientController.java" - }, - "-6509265758887333864": { - "message": "Can't report activity moved to display - client not running, activityRecord=%s, displayId=%d", - "level": "WARN", - "group": "WM_DEBUG_SWITCH", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-4183059578873561863": { - "message": "Reporting activity moved to display, activityRecord=%s, displayId=%d, config=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_SWITCH", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "7435279034964784633": { - "message": "Can't report activity configuration update - client not running, activityRecord=%s", - "level": "WARN", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-7418876140361338495": { - "message": "Sending new config to %s, config: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-4284934398288119962": { - "message": "Can't report activity position update - client not running, activityRecord=%s", - "level": "WARN", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "7244227111034368231": { - "message": "Sending position change to %s, onTop: %b", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "338586566486930495": { - "message": "Checking theme of starting window: 0x%x", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-2561793317091789573": { - "message": "Translucent=%s Floating=%s ShowWallpaper=%s Disable=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "7269690012594027154": { - "message": "Creating SplashScreenStartingData", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-3432060893368468911": { - "message": "Creating SnapshotStartingData", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "5659016061937922595": { - "message": "Add starting %s: startingData=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "7506106334102501360": { - "message": "Added starting %s: startingWindow=%s startingView=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "1048048288756547220": { - "message": "Surface returned was null: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-1298801500610545721": { - "message": "Cleaning splash screen token=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-1948849214526113495": { - "message": "Clearing startingData for token=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "5545923784327902026": { - "message": "Schedule remove starting %s startingWindow=%s animate=%b Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-5150982660941074218": { - "message": "startingWindow was set but startingSurface==null, couldn't remove", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-2178757341169633804": { - "message": "Tried to remove starting window but startingWindow was null: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "5521236266092347335": { - "message": "reparent: moving activity=%s to new task fragment in task=%d at %d", - "level": "INFO", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-9024836052864189016": { - "message": "moveFocusableActivityToTop: unfocusable activity=%s", - "level": "DEBUG", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "134255351804410010": { - "message": "moveFocusableActivityToTop: already on top and focused, activity=%s", - "level": "DEBUG", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-1058622321669556178": { - "message": "moveFocusableActivityToTop: set focused, activity=%s", - "level": "DEBUG", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "731006689098152100": { - "message": "moveFocusableActivityToTop: activity=%s", - "level": "DEBUG", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "3707721620395081349": { - "message": "Finishing activity r=%s, result=%d, data=%s, reason=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-3691592300155948194": { - "message": "Finish needs to pause: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "5813636479397543744": { - "message": "Finish waiting for pause of: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-2989211291975863399": { - "message": "destroyIfPossible: r=%s destroy returned removed=%s", - "level": "DEBUG", - "group": "WM_DEBUG_CONTAINERS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "3169053633576517098": { - "message": "Enqueueing pending finish: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "9050478058743283018": { - "message": "activity %s already destroying, skipping request with reason:%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "5672598223877126839": { - "message": "Moving to DESTROYING: %s (destroy requested)", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-1834399855266808961": { - "message": "Moving to DESTROYED: %s (destroy skipped)", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "3282063745558462269": { - "message": "Moving to DESTROYED: %s (no app)", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "8836546031252812807": { - "message": "Removing activity %s, reason= %s callers=%s", - "level": "INFO", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "8348126473928520781": { - "message": "Moving to DESTROYED: %s (removed from history)", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-8001673213497887656": { - "message": "activityDestroyedLocked: r=%s", - "level": "DEBUG", - "group": "WM_DEBUG_CONTAINERS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "587363723665813898": { - "message": "Removing activity %s hasSavedState=%b stateNotNeeded=%s finishing=%b state=%s callers=%s", - "level": "INFO", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-1842512343787359105": { - "message": "Removing app token: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "5548174277852675449": { - "message": "Removing app %s delayed=%b animation=%s animating=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-601582700132879947": { - "message": "removeAppToken: %s delayed=%b Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "3478214322581157355": { - "message": "removeAppToken make exiting: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-7226216420432530281": { - "message": "Removing focused app token:%s displayId=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "8361394136152947990": { - "message": "Moving existing starting %s from %s to %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-3450064502566932331": { - "message": "Removing starting %s from %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "8639603536400037285": { - "message": "Moving pending starting from %s to %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-3452055378690362514": { - "message": "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "1728033820691545386": { - "message": "No longer Stopped: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "5062176994575790703": { - "message": "TRANSIT_FLAG_OPEN_BEHIND, adding %s to mOpeningApps", - "level": "DEBUG", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-477271988506706928": { - "message": "commitVisibility: %s: visible=%b visibleRequested=%b, isInTransition=%b, runningAnimation=%b, caller=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-6873410057142191118": { - "message": "State movement: %s from:%s to:%s reason:%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "4437231720834282527": { - "message": "State unchanged from:%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "926038819327785799": { - "message": "notifyAppResumed: wasStopped=%b %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "1734586111478674085": { - "message": "Resumed activity; dropping state of: %s", - "level": "INFO", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-69666241054231397": { - "message": "Refreshed activity: %s", - "level": "INFO", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "1256300416726217367": { - "message": "Activity paused: token=%s, timeout=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "6879640870754727133": { - "message": "Moving to PAUSED: %s %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "2737811012914917932": { - "message": "Executing finish of failed to pause activity: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-2566496855129705006": { - "message": "Waiting for pause to complete...", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "7498807658620137882": { - "message": "no-history finish of %s", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "3207149655622038378": { - "message": "Not finishing noHistory %s on stop because we're just sleeping", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-2530718588485487045": { - "message": "Moving to STOPPING: %s (stop requested)", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-8424334454318351870": { - "message": "Stop failed; moving to STOPPED: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-4913512058893421188": { - "message": "Saving icicle of %s: %s", - "level": "INFO", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "7613353074402340933": { - "message": "Moving to STOPPED: %s (stop complete)", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "3981777934616509782": { - "message": "Scheduling idle now: forceIdle=%b immediate=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "1083992181663415298": { - "message": "Skipping set freeze of %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "3713860954819212080": { - "message": "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s", - "level": "INFO", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "7696002120820208745": { - "message": "Clear freezing of %s force=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-8387262166329116492": { - "message": "No longer freezing: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-6965298896142649709": { - "message": "Finish starting %s: first real window is shown, no animation", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "3235691043029201724": { - "message": "Setting mOrientationChangeComplete=true because wtoken %s numInteresting=%d numDrawn=%d", - "level": "INFO", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "5991628884266137609": { - "message": "Creating animation bounds layer", - "level": "INFO", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-1836789237982086339": { - "message": "No thumbnail header bitmap for: %s", - "level": "DEBUG", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-8809523216004991008": { - "message": "Animation done in %s: reportedVisible=%b okToDisplay=%b okToAnimate=%b startingDisplayed=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-9178011226407552682": { - "message": "Setting requested orientation %s for %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-1963190756391505590": { - "message": "Sandbox max bounds for uid %s to bounds %s. config to never sandbox = %s, config to always sandbox = %s, letterboxing from mismatch with parent bounds = %s, has mCompatDisplayInsets = %s, should create compatDisplayInsets = %s", - "level": "DEBUG", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "2612201759169917322": { - "message": "Pausing configuration dispatch for %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "5153784493059555057": { - "message": "Resuming configuration dispatch for %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-8630021188868292872": { - "message": "Skipping config check (will change): %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-3976984054291875926": { - "message": "Configuration doesn't matter in finishing %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-1036762753077003128": { - "message": "Skipping config check in destroyed state %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-6543078196636665108": { - "message": "Skipping config check invisible: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-3588725633248053181": { - "message": "Ensuring correct configuration: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "4672360193194734037": { - "message": "Configuration & display unchanged in %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-8624278141553396410": { - "message": "Skipping config check for initializing activity: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "2485365009287691179": { - "message": "Configuration no differences in %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-8909639363543223474": { - "message": "Configuration changes for %s, allChanges=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-8048404379899908050": { - "message": "Configuration doesn't matter not running %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "4979286847769557939": { - "message": "Checking to restart %s: changed=0x%s, handles=0x%s, mLastReportedConfiguration=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "6779426581354721909": { - "message": "Config is relaunching %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "8969401915706456725": { - "message": "Config is relaunching invisible activity %s called by %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "328802837600679598": { - "message": "Moving to %s Relaunching %s callers=%s", - "level": "INFO", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-3997125892953197985": { - "message": "Resumed after relaunch %s", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "7211222997110112110": { - "message": "Refreshing activity for freeform camera compatibility treatment, activityRecord=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRefresher.java" - }, - "1665699123574159131": { - "message": "Starting activity when config will change = %b", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityStarter.java" - }, - "4748139468532105082": { - "message": "Updating to new configuration after starting activity.", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityStarter.java" - }, - "-2867366986304729": { - "message": "Bring to front target: %s from %s", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityStarter.java" - }, - "-2190454940975874759": { - "message": "Starting new activity %s in new task %s", - "level": "VERBOSE", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityStarter.java" - }, - "5445799252721678675": { - "message": "Initial config: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "-3811526397232923712": { - "message": "Cannot launch dream activity due to invalid state. dream component: %s packageName: %s", - "level": "ERROR", - "group": "WM_DEBUG_DREAM", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "-6981899770129924827": { - "message": "Dream packageName does not match active dream. Package %s does not match %s", - "level": "ERROR", - "group": "WM_DEBUG_DREAM", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "6075150529915862250": { - "message": "Applying new update lock state '%s' for %s", - "level": "DEBUG", - "group": "WM_DEBUG_IMMERSIVE", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "-4356952232698761083": { - "message": "setFocusedRootTask: taskId=%d", - "level": "DEBUG", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "301842347780487555": { - "message": "setFocusedTask: taskId=%d touchedActivity=%s", - "level": "DEBUG", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "7095858131234795548": { - "message": "moveTaskToFront: moving taskId=%d", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "-4458288191054594222": { - "message": "Could not find task for id: %d", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "-1136891560663761442": { - "message": "moveTaskToRootTask: moving task=%d to rootTaskId=%d toTop=%b", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "6954122272402912822": { - "message": "startLockTaskMode: %s", - "level": "WARN", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "-829638795650515884": { - "message": "Allowlisting %d:%s", - "level": "WARN", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "893763316922465955": { - "message": "moveRootTaskToDisplay: moving taskId=%d to displayId=%d", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "8392804603924461448": { - "message": "%s: caller %d is using old GET_TASKS but privileged; allowing", - "level": "WARN", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "4303745325174700522": { - "message": "%s: caller %d does not hold REAL_GET_TASKS; limiting output", - "level": "WARN", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "-559595900417262876": { - "message": "Allowing features %d:0x%s", - "level": "WARN", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "2008996027621913637": { - "message": "Updating global configuration to: %s", - "level": "INFO", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "-6404059840638143757": { - "message": "Update process config of %s to new config %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "-1123414663662718691": { - "message": "setVr2dDisplayId called for: %d", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "7803197981786977817": { - "message": "no-history finish of %s on new resume", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" - }, - "4094852138446437211": { - "message": "realStartActivityLocked: Skipping start of r=%s some activities pausing...", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" - }, - "1045761390992110034": { - "message": "Moving to PAUSED: %s (starting in paused state)", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" - }, - "-8529426827020190143": { - "message": "Launch on display check: displayId=%d callingPid=%d callingUid=%d", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" - }, - "9147909968067116569": { - "message": "Launch on display check: no caller info, skip check", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" - }, - "4781135167649953680": { - "message": "Launch on display check: allow launch any on display", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" - }, - "7828411869729995271": { - "message": "Launch on display check: disallow launch on virtual display for not-embedded activity.", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" - }, - "-2215878620906309682": { - "message": "Launch on display check: disallow activity embedding without permission.", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" - }, - "986565579776405555": { - "message": "Launch on display check: %s launch for userId=%d on displayId=%d", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" - }, - "-2201418325681949201": { - "message": "Launch on display check: allow launch for owner of the display", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" - }, - "-4258279435559028377": { - "message": "Launch on display check: allow launch for caller present on the display", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" - }, - "1496536241884839051": { - "message": "Stopping %s: nowVisible=%b animating=%b finishing=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" - }, - "5677125188685281770": { - "message": "Ready to stop: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" - }, - "3604633008357193496": { - "message": "Waiting for top state to be released by %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" - }, - "3997062844427155487": { - "message": "Top resumed state released %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" - }, - "-4049608245387511746": { - "message": "applyAnimation: override requested, but it is prohibited by policy.", - "level": "ERROR", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" - }, - "-2133100418670643322": { - "message": "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" - }, - "6121116119545820299": { - "message": "applyAnimation: anim=%s transit=%s Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" - }, - "-8382864384468306610": { - "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s isEntrance=%b Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" - }, - "222576013987954454": { - "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM_IN_PLACE transit=%s Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" - }, - "4808089291562562413": { - "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CLIP_REVEAL transit=%s Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" - }, - "-1463563572526433695": { - "message": "applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s isEntrance=%s Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" - }, - "-8749850292010208926": { - "message": "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" - }, - "5939232373291430513": { - "message": "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: anim=%s transit=%s isEntrance=true Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" - }, - "9082776604722675018": { - "message": "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" - }, - "-1218632020771063497": { - "message": "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b canCustomizeAppTransition=%b Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" - }, - "6217525691846442213": { - "message": "Override pending remote transitionSet=%b adapter=%s", - "level": "INFO", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransition.java" - }, - "5233255302148535928": { - "message": "*** APP TRANSITION TIMEOUT. displayId=%d isTransitionSet()=%b mOpeningApps.size()=%d mClosingApps.size()=%d mChangingApps.size()=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransition.java" - }, - "-5726018006883159788": { - "message": "Delaying app transition for recents animation to finish", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "6514556033257323299": { - "message": "**** GOOD TO GO", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "3518082157667760495": { - "message": "handleAppTransitionReady: displayId=%d appTransition={%s} openingApps=[%s] closingApps=[%s] transit=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "-2503124388387340567": { - "message": "Wallpaper animation!", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "855146509305002043": { - "message": "We don't support remote animation for Task with multiple TaskFragmentOrganizers.", - "level": "ERROR", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "59396412370137517": { - "message": "Override with TaskFragment remote animation for transit=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "2280055488397326910": { - "message": "Task=%d contains embedded TaskFragment. Disabled all input during TaskFragment remote animation.", - "level": "DEBUG", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "-3156084190956669377": { - "message": "Changing app %s visible=%b performLayout=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "-8226278785414579647": { - "message": "getAnimationTarget in=%s, out=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "4418653408751596915": { - "message": "Now opening app %s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "-8367738619313176909": { - "message": "Now closing app %s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "1855459282905873641": { - "message": "Now changing app %s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "2951634988136738868": { - "message": "Checking %d opening apps (frozen=%b timeout=%b)...", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "4963754906024950916": { - "message": "Delaying app transition for screen rotation animation to finish", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "5073676463280304697": { - "message": "Check opening app=%s: allDrawn=%b startingDisplayed=%b startingMoved=%b isRelaunching()=%b startingWindow=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "3437142041296647115": { - "message": "isFetchingAppTransitionSpecs=true", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "1461079689316480707": { - "message": "unknownApps is not empty: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "3579533288018884842": { - "message": "Organized TaskFragment is not ready= %s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "495867940519492701": { - "message": "SyncGroup %d: onSurfacePlacement checking %s", - "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" - }, - "8452501904614439940": { - "message": "SyncGroup %d: Unfinished dependencies: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" - }, - "616739530932040800": { - "message": "SyncGroup %d: Unfinished container: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" - }, - "6649777898123506907": { - "message": "SyncGroup %d: Finished!", - "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" - }, - "4174320302463990554": { - "message": "PendingStartTransaction found", - "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" - }, - "6310906192788668020": { - "message": "SyncGroup %d: Set ready %b", - "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" - }, - "-476337038362199951": { - "message": "SyncGroup %d: Adding to group: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" - }, - "-2978812352001196863": { - "message": "SyncGroup %d: Started %sfor listener: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" - }, - "-699215053676660941": { - "message": "No focused window, defaulting to top current task's window", - "level": "WARN", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" - }, - "2881085074175114605": { - "message": "Focused window didn't have a valid surface drawn.", - "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" - }, - "-6183551796617134986": { - "message": "Focus window is closing.", - "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" - }, - "4039315468791789889": { - "message": "startBackNavigation currentTask=%s, topRunningActivity=%s, callbackInfo=%s, currentFocus=%s", - "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" - }, - "8456834061534378653": { - "message": "Previous Destination is Activity:%s Task:%s removedContainer:%s, backType=%s", - "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" - }, - "4900967164780429209": { - "message": "Pending back animation due to another animation is running", - "level": "WARN", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" - }, - "-6431452312492819825": { - "message": "onTransactionReady, opening: %s, closing: %s, animating: %s, match: %b", - "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" - }, - "-4051770154814262074": { - "message": "Handling the deferred animation after transition finished", - "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" - }, - "2077221835543623088": { - "message": "Setting Activity.mLauncherTaskBehind to true. Activity=%s", - "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" - }, - "-4442170697458371588": { - "message": "Setting Activity.mLauncherTaskBehind to false. Activity=%s", - "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" - }, - "267946503010201613": { - "message": "onBackNavigationDone backType=%s, triggerBack=%b", - "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" - }, - "-2963535976860666511": { - "message": " BLACK %s: CREATE layer=%d", - "level": "INFO", - "group": "WM_SHOW_SURFACE_ALLOC", - "at": "com\/android\/server\/wm\/BlackFrame.java" - }, - "-5633771912572750947": { - "message": " BLACK %s: DESTROY", - "level": "INFO", - "group": "WM_SHOW_SURFACE_ALLOC", - "at": "com\/android\/server\/wm\/BlackFrame.java" - }, - "8116030277393789125": { - "message": "Display id=%d is notified that Camera %s is open for package %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/CameraStateMonitor.java" - }, - "-3774458166471278611": { - "message": "Display id=%d is notified that Camera %s is closed.", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/CameraStateMonitor.java" - }, - "-74949168947384056": { - "message": "Sending to proc %s new compat %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/CompatModePackages.java" - }, - "-6620483833570774987": { - "message": "Content Recording: Unexpectedly null window container; unable to update recording for display %d", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "7226080178642957768": { - "message": "Content Recording: Display %d was already recording, but pause capture since the task is in PIP", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "-311001578548807570": { - "message": "Content Recording: Display %d was already recording, so apply transformations if necessary", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "2350883351096538149": { - "message": "Content Recording: Going ahead with updating recording for display %d to new bounds %s and\/or orientation %d and\/or surface size %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "8446758574558556540": { - "message": "Content Recording: Unable to update recording for display %d to new bounds %s and\/or orientation %d and\/or surface size %s, since the surface is not available.", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "-4320004054011530388": { - "message": "Content Recording: Display %d has content (%b) so pause recording", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "5951434375221687741": { - "message": "Content Recording: Stop MediaProjection on virtual display %d", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "-3395581813971405090": { - "message": "Content Recording: waiting to record, so do nothing", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "6779858226066635065": { - "message": "Content Recording: Display %d should start recording, but don't yet since the task is in PIP", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "7051210836345306671": { - "message": "Content Recording: Unable to start recording for display %d since the surface is not available.", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "2255758299558330282": { - "message": "Content Recording: Display %d has no content and is on, so start recording for state %d", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "2269158922723670768": { - "message": "Unable to retrieve window container to start recording for display %d", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "-2177493963028285555": { - "message": "Content Recording: Unable to start recording due to null token for display %d", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "-928577038848872043": { - "message": "Content Recording: Unable to retrieve task to start recording for display %d", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "-3564317873468917405": { - "message": "Content Recording: Unable to start recording due to invalid region for display %d", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "1100676037289065396": { - "message": "Content Recording: Apply transformations of shift %d x %d, scale %f x %f, crop (aka recorded content size) %d x %d for display %d; display has size %d x %d; surface has size %d x %d", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "2330946591287751995": { - "message": "Content Recording: Provided surface for recording on display %d is not present, so do not update the surface", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "7993045936648632984": { - "message": "Content Recording: Recorded task is removed, so stop recording on display %d", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "3197882223327917085": { - "message": "Content Recording: stopping active projection for display %d", - "level": "ERROR", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "4391984931064789228": { - "message": "Content Recording: Unable to tell MediaProjectionManagerService to stop the active projection for display %d: %s", - "level": "ERROR", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "6721270269112237694": { - "message": "Content Recording: Unable to tell MediaProjectionManagerService about resizing the active projection: %s", - "level": "ERROR", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "1600318776990120244": { - "message": "Content Recording: Unable to tell MediaProjectionManagerService about visibility change on the active projection: %s", - "level": "ERROR", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "-1451477179301743956": { - "message": "Content Recording: Unable to tell log windowing mode change: %s", - "level": "ERROR", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "-225319884529912382": { - "message": "Content Recording: Accept session updating same display %d with granted consent, with an existing session %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecordingController.java" - }, - "-5981322449150461244": { - "message": "Content Recording: Ignoring session on same display %d, with an existing session %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecordingController.java" - }, - "4226710957373144819": { - "message": "Content Recording: Handle incoming session on display %d, with a pre-existing session %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecordingController.java" - }, - "-1415855962859555663": { - "message": "Content Recording: Incoming session on display %d can't be set since it is already null; the corresponding VirtualDisplay must have already been removed.", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecordingController.java" - }, - "-5750232782380780139": { - "message": "Content Recording: Pause the recording session on display %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecordingController.java" - }, - "-8058211784911995417": { - "message": "DeferredDisplayUpdater: applying DisplayInfo immediately", - "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java" - }, - "1944392458089872195": { - "message": "DeferredDisplayUpdater: partially applying DisplayInfo immediately", - "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java" - }, - "8391643185322408089": { - "message": "DeferredDisplayUpdater: deferring DisplayInfo update", - "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java" - }, - "-915675022936690176": { - "message": "DeferredDisplayUpdater: applied DisplayInfo after deferring", - "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java" - }, - "3778139410556664218": { - "message": "%s skipping animation and directly setting alpha=%f, blur=%d", - "level": "DEBUG", - "group": "WM_DEBUG_DIMMER", - "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java" - }, - "-6357087772993832060": { - "message": "Starting animation on %s", - "level": "VERBOSE", - "group": "WM_DEBUG_DIMMER", - "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java" - }, - "-1187783168730646350": { - "message": "Dim animation requested: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_DIMMER", - "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java" - }, - "2230151187668089583": { - "message": "%s forcing orientation to %d for display id=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayArea.java" - }, - "3968604152682328317": { - "message": "Register display organizer=%s uid=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" - }, - "-3066370283926570943": { - "message": "Don't organize or trigger events for untrusted displayId=%d", - "level": "WARN", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" - }, - "-943497726140336963": { - "message": "Unregister display organizer=%s uid=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" - }, - "5147103403966149923": { - "message": "Create TaskDisplayArea uid=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" - }, - "-1659480097203667175": { - "message": "Delete TaskDisplayArea uid=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" - }, - "-4514772405648277945": { - "message": "DisplayArea appeared name=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" - }, - "995846188225477231": { - "message": "DisplayArea vanished name=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" - }, - "-1007032390526684388": { - "message": "DisplayArea info changed name=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" - }, - "4917824058925068521": { - "message": "The TaskDisplayArea with %s does not exist.", - "level": "WARN", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/DisplayAreaPolicyBuilder.java" - }, - "1432179297701477868": { - "message": "Looking for focus: %s, flags=%d, canReceive=%b, reason=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "-1998969924927409574": { - "message": "findFocusedWindow: focusedApp=null using new focus @ %s", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "-1513212297283619351": { - "message": "findFocusedWindow: focusedApp windows not focusable using new focus @ %s", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "271075236829935631": { - "message": "findFocusedWindow: Reached focused app=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "3066566560703920191": { - "message": "findFocusedWindow: Found new focus @ %s", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "-8667452489821572603": { - "message": "First draw done in potential wallpaper target %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "6283995720623600346": { - "message": "handleNotObscuredLocked: %s was holding screen wakelock but no longer has FLAG_KEEP_SCREEN_ON!!! called by%s", - "level": "DEBUG", - "group": "WM_DEBUG_KEEP_SCREEN_ON", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "1959209522588955826": { - "message": "Acquiring screen wakelock due to %s", - "level": "DEBUG", - "group": "WM_DEBUG_KEEP_SCREEN_ON", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "352937214222086717": { - "message": "Releasing screen wakelock, obscured by %s", - "level": "DEBUG", - "group": "WM_DEBUG_KEEP_SCREEN_ON", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "2632363530212357762": { - "message": "Set mOrientationChanging of %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "-9191821315942566105": { - "message": "Display id=%d is frozen while keyguard locked, return %d", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "-74384795669614579": { - "message": "Display id=%d is ignoring orientation request for %d, return %d following a per-app override for %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "-3395592185328682328": { - "message": "Display id=%d is ignoring orientation request for %d, return %d", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "3438870491084701232": { - "message": "No app or window is requesting an orientation, return %d for display id=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "-1123818872155982592": { - "message": "findFocusedWindow: No focusable windows, display=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "-2192125645150932161": { - "message": "Current transition prevents automatic focus change", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "3101160328044493048": { - "message": "Changing focus from %s to %s displayId=%d Callers=%s", - "level": "DEBUG", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "7634130879993688940": { - "message": "setFocusedApp %s displayId=%d Callers=%s", - "level": "INFO", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "-4130402450005935184": { - "message": "SURFACE LEAK DESTROY: %s", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "4464269036743635127": { - "message": "setInputMethodTarget %s", - "level": "INFO", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "4835192778854186097": { - "message": "create IME snapshot for %s, buff width=%s, height=%s", - "level": "INFO", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "2408509162360028352": { - "message": "Set IME snapshot position: (%d, %d)", - "level": "INFO", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "2005731931732324688": { - "message": "remove IME snapshot, caller=%s", - "level": "INFO", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "-6495118720675662641": { - "message": "show IME snapshot, ime target=%s, callers=%s", - "level": "INFO", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "-4354595179162289537": { - "message": "setInputMethodInputTarget %s", - "level": "INFO", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "2432701541536053712": { - "message": "DisplayContent: boot is waiting for window of type %d to be drawn", - "level": "DEBUG", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "5683557566110711213": { - "message": "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b wallEnabled=%b haveKeyguard=%b", - "level": "INFO", - "group": "WM_DEBUG_SCREEN_ON", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "-124113386733162358": { - "message": "onWindowAnimationFinished, wc=%s, type=%s, imeSnapshot=%s, target=%s", - "level": "INFO", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "-1556099709547629010": { - "message": "ImeContainer just became organized. Reparenting under parent. imeParentSurfaceControl=%s", - "level": "INFO", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "1119786654111970652": { - "message": "ImeContainer just became organized but it doesn't have a parent or the parent doesn't have a surface control. mSurfaceControl=%s imeParentSurfaceControl=%s", - "level": "ERROR", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "7019634211809476510": { - "message": "Execute app transition: %s, displayId: %d Callers=%s", - "level": "WARN", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "-3219913508985161450": { - "message": "Wallpaper layer changed: assigning layers + relayout", - "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "-8165317816061445169": { - "message": "Content Recording: Display %d state was (%d), is now (%d), so update recording?", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "4162342172327950908": { - "message": "Content Recording: Attempting to mirror self on %d", - "level": "WARN", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "5489691866309868814": { - "message": "Content Recording: Found no matching mirror display for id=%d for DEFAULT_DISPLAY. Nothing to mirror.", - "level": "WARN", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "-39794010824230928": { - "message": "Content Recording: Attempting to mirror %d from %d but no DisplayContent associated. Changing to mirror default display.", - "level": "WARN", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "6545352723229848841": { - "message": "Content Recording: Successfully created a ContentRecordingSession for displayId=%d to mirror content from displayId=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "-6228339285356824882": { - "message": "finishScreenTurningOn: mAwake=%b, mScreenOnEarly=%b, mScreenOnFully=%b, mKeyguardDrawComplete=%b, mWindowManagerDrawComplete=%b", - "level": "DEBUG", - "group": "WM_DEBUG_SCREEN_ON", - "at": "com\/android\/server\/wm\/DisplayPolicy.java" - }, - "-6028033043540330282": { - "message": "Finished screen turning on...", - "level": "INFO", - "group": "WM_DEBUG_SCREEN_ON", - "at": "com\/android\/server\/wm\/DisplayPolicy.java" - }, - "-7427596081878257508": { - "message": "selectAnimation in %s: transit=%d", - "level": "INFO", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/DisplayPolicy.java" - }, - "-6269658847003264525": { - "message": "**** STARTING EXIT", - "level": "INFO", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/DisplayPolicy.java" - }, - "-6776561147903919733": { - "message": "Deferring rotation, rotation is paused.", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "7439675997626642740": { - "message": "Deferring rotation, animation in progress.", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "1104181226551849840": { - "message": "Deferring rotation, still finishing previous rotation", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "-2222079183499215612": { - "message": "Deferring rotation, display is not enabled.", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "662988298513100908": { - "message": "Reverting orientation. Rotating to %s from %s rather than %s.", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "-7113483678655694375": { - "message": "Computed rotation=%s (%d) for display id=%d based on lastOrientation=%s (%d) and oldRotation=%s (%d)", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "-8809129029906317617": { - "message": "Display id=%d selected orientation %s (%d), got rotation %s (%d)", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "6753221849083491323": { - "message": "Display id=%d rotation changed to %d from %d, lastOrientation=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "-1216224951455892544": { - "message": "Performing post-rotate rotation after seamless rotation", - "level": "INFO", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "-7672508047849737424": { - "message": "selectRotationAnimation topFullscreen=%s rotationAnimation=%d forceJumpcut=%b", - "level": "INFO", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "-2426404033822048710": { - "message": "screenOnEarly=%b, awake=%b, currentAppOrientation=%d, orientationSensorEnabled=%b, keyguardDrawComplete=%b, windowManagerDrawComplete=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "7339471241580327852": { - "message": "rotationForOrientation(orient=%s (%d), last=%s (%d)); user=%s (%d) %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "5325136615007859122": { - "message": "Invalid surface rotation angle in config_deviceTabletopRotations: %d", - "level": "ERROR", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "4616480353797749295": { - "message": "config_deviceTabletopRotations is not defined. Half-fold letterboxing will work inconsistently.", - "level": "WARN", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "8852346340572084230": { - "message": "foldStateChanged: displayId %d, halfFoldStateChanged %s, saved rotation: %d, mUserRotation: %d, mLastSensorRotation: %d, mLastOrientation: %d, mRotation: %d", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "-8674269704471038429": { - "message": "onProposedRotationChanged, rotation=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "418312772547457152": { - "message": "Enabling listeners", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "4641814558273780952": { - "message": "Disabling listeners", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "7429138692709430028": { - "message": "Display id=%d is ignoring all orientation requests, camera is active and the top activity is eligible for force rotation, return %s,portrait activity: %b, is natural orientation portrait: %b.", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" - }, - "-5176775281239247368": { - "message": "Reverting orientation after camera compat force rotation", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" - }, - "-2188976047008497712": { - "message": "Saving original orientation before camera compat, last orientation is %d", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" - }, - "-1534784331886673955": { - "message": "DisplayRotationCompatPolicy: Multi-window toast not shown as package '%s' cannot be found.", - "level": "ERROR", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" - }, - "-5121743609317543819": { - "message": "Display id=%d is notified that camera is closed but activity is still refreshing. Rescheduling an update.", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" - }, - "1769752961776628557": { - "message": "Display id=%d is notified that Camera is closed, updating rotation.", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" - }, - "-6949326633913532620": { - "message": "NOSENSOR override detected", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java" - }, - "-2060428960792625366": { - "message": "NOSENSOR override is absent: reverting", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java" - }, - "-4296736202875980050": { - "message": "Other orientation overrides are in place: not reverting", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java" - }, - "7928129513685401229": { - "message": "Pausing rotation during drag", - "level": "DEBUG", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DragState.java" - }, - "8231481023986546563": { - "message": "Resuming rotation after drag", - "level": "DEBUG", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DragState.java" - }, - "12662399232325663": { - "message": "DRAG %s: pos=(%d,%d)", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/DragState.java" - }, - "-1797662102094201628": { - "message": "Attempt to transfer touch gesture with non-existent embedded window", - "level": "WARN", - "group": "WM_DEBUG_EMBEDDED_WINDOWS", - "at": "com\/android\/server\/wm\/EmbeddedWindowController.java" - }, - "929964979835124721": { - "message": "Attempt to transfer touch gesture using embedded window with no associated host", - "level": "WARN", - "group": "WM_DEBUG_EMBEDDED_WINDOWS", - "at": "com\/android\/server\/wm\/EmbeddedWindowController.java" - }, - "676191989331669410": { - "message": "Attempt to transfer touch gesture with host window not associated with embedded window", - "level": "WARN", - "group": "WM_DEBUG_EMBEDDED_WINDOWS", - "at": "com\/android\/server\/wm\/EmbeddedWindowController.java" - }, - "553249487221306249": { - "message": "Attempt to transfer touch gesture using embedded window that has no input channel", - "level": "WARN", - "group": "WM_DEBUG_EMBEDDED_WINDOWS", - "at": "com\/android\/server\/wm\/EmbeddedWindowController.java" - }, - "-8678904073078032058": { - "message": "Attempt to transfer touch gesture using a host window with no input channel", - "level": "WARN", - "group": "WM_DEBUG_EMBEDDED_WINDOWS", - "at": "com\/android\/server\/wm\/EmbeddedWindowController.java" - }, - "-786355099910065121": { - "message": "IME target changed within ActivityRecord", - "level": "DEBUG", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" - }, - "2634707843050913730": { - "message": "Schedule IME show for %s", - "level": "DEBUG", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" - }, - "8923821958256605927": { - "message": "Run showImeRunner", - "level": "DEBUG", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" - }, - "-3529253275087521638": { - "message": "call showInsets(ime) on %s", - "level": "INFO", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" - }, - "7927729210300708186": { - "message": "showInsets(ime) was requested by different window: %s ", - "level": "WARN", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" - }, - "-6529782994356455131": { - "message": "abortShowImePostLayout", - "level": "DEBUG", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" - }, - "-6629998049460863403": { - "message": "dcTarget: %s mImeRequester: %s", - "level": "DEBUG", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" - }, - "-8553129529717081823": { - "message": "Input focus has changed to %s display=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/InputMonitor.java" - }, - "4027486077547983902": { - "message": "App %s is focused, but the window is not ready. Start a transaction to remove focus from the window of non-focused apps.", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/InputMonitor.java" - }, - "-8537908614386667236": { - "message": "Focus not requested for window=%s because it has no surface or is not focusable.", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/InputMonitor.java" - }, - "-6346673514571615151": { - "message": "Focus requested for window=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/InputMonitor.java" - }, - "1522894362518893789": { - "message": "InsetsSource setWin %s for type %s", - "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_INSETS", - "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" - }, - "6243049416211184258": { - "message": "InsetsSource Control %s for target %s", - "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_INSETS", - "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" - }, - "-8234068212532234206": { - "message": "InsetsSource updateVisibility for %s, serverVisible: %s clientVisible: %s", - "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_INSETS", - "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" - }, - "-8601070090234611338": { - "message": "ControlAdapter startAnimation mSource: %s controlTarget: %s", - "level": "INFO", - "group": "WM_DEBUG_WINDOW_INSETS", - "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" - }, - "-6857870589074001153": { - "message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s", - "level": "INFO", - "group": "WM_DEBUG_WINDOW_INSETS", - "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" - }, - "-6684172224226118673": { - "message": "onImeControlTargetChanged %s", - "level": "DEBUG", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/InsetsStateController.java" - }, - "8891808212671675155": { - "message": "clearLockedTasks: %s", - "level": "INFO", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/LockTaskController.java" - }, - "8970634498594714645": { - "message": "removeLockedTask: removed %s", - "level": "DEBUG", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/LockTaskController.java" - }, - "8735562128135241598": { - "message": "removeLockedTask: task=%s last task, reverting locktask mode. Callers=%s", - "level": "DEBUG", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/LockTaskController.java" - }, - "737192738184050156": { - "message": "startLockTaskMode: Can't lock due to auth", - "level": "WARN", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/LockTaskController.java" - }, - "-7119521978513736788": { - "message": "Mode default, asking user", - "level": "WARN", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/LockTaskController.java" - }, - "-1557441750657584614": { - "message": "%s", - "level": "WARN", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/LockTaskController.java" - }, - "-4314079913933391851": { - "message": "setLockTaskMode: Can't lock due to auth", - "level": "WARN", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/LockTaskController.java" - }, - "3321878763832425380": { - "message": "setLockTaskMode: Locking to %s Callers=%s", - "level": "WARN", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/LockTaskController.java" - }, - "-4819015209006579825": { - "message": "onLockTaskPackagesUpdated: removing %s mLockTaskAuth()=%s", - "level": "DEBUG", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/LockTaskController.java" - }, - "2119751067469297845": { - "message": "onLockTaskPackagesUpdated: starting new locktask task=%s", - "level": "DEBUG", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/LockTaskController.java" - }, - "3788905348567806832": { - "message": "startAnimation", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java" - }, - "705955074330737483": { - "message": "onAnimationCancelled", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java" - }, - "5106303602270682056": { - "message": "Adding display switch to existing collecting transition", - "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/PhysicalDisplaySwitchTransitionLauncher.java" - }, - "-1640401313436844534": { - "message": "Resetting frozen recents task list reason=app touch win=%s x=%d y=%d insetFrame=%s", - "level": "INFO", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RecentTasks.java" - }, - "-8803811426486764449": { - "message": "Setting frozen recents task list", - "level": "INFO", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RecentTasks.java" - }, - "4040735335719974079": { - "message": "Resetting frozen recents task list reason=timeout", - "level": "INFO", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RecentTasks.java" - }, - "3308140128142966415": { - "message": "remove RecentTask %s when finishing user %d", - "level": "INFO", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RecentTasks.java" - }, - "-3758280623533049031": { - "message": "Preload recents with %s", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" - }, - "-3365656764099317101": { - "message": "Updated config=%s", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" - }, - "-7165162073742035900": { - "message": "Real start recents", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" - }, - "-3403665718306852375": { - "message": "startRecentsActivity(): intent=%s", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" - }, - "-8325607672707336373": { - "message": "No root task above target root task=%s", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" - }, - "-7278356485797757819": { - "message": "Moved rootTask=%s behind rootTask=%s", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" - }, - "1012359606301505741": { - "message": "Started intent=%s", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" - }, - "5474198007669537235": { - "message": "onAnimationFinished(): controller=%s reorderMode=%d", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" - }, - "3525834288436624965": { - "message": "onAnimationFinished(): targetRootTask=%s targetActivity=%s mRestoreTargetBehindRootTask=%s", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" - }, - "-5961176083217302671": { - "message": "Expected target rootTask=%s to be top most but found rootTask=%s", - "level": "WARN", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" - }, - "-5893976429537642045": { - "message": "Expected target rootTask=%s to restored behind rootTask=%s but it is behind rootTask=%s", - "level": "WARN", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" - }, - "4515487264815398694": { - "message": "onRootTaskOrderChanged(): rootTask=%s", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" - }, - "6530904107141905844": { - "message": "screenshotTask(%d): mCanceled=%b", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" - }, - "-3286551982713129633": { - "message": "setFinishTaskTransaction(%d): transaction=%s", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" - }, - "5187133389446459984": { - "message": "finish(%b): mCanceled=%b", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" - }, - "6879496555046975661": { - "message": "setInputConsumerEnabled(%s): mCanceled=%b", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" - }, - "-5305978958548091997": { - "message": "setHomeApp(%s)", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" - }, - "-3801497203749932106": { - "message": "addAnimation(%s)", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" - }, - "3721473589747203697": { - "message": "removeAnimation(%d)", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" - }, - "5156407755139006078": { - "message": "removeWallpaperAnimation()", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" - }, - "-1997836523186474317": { - "message": "startAnimation(): mPendingStart=%b mCanceled=%b", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" - }, - "-7532294363367395195": { - "message": "startAnimation(): Notify animation start: %s", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" - }, - "-1336603089105439710": { - "message": "collectTaskRemoteAnimations, target: %s", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" - }, - "2547528895718568379": { - "message": "createWallpaperAnimations()", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" - }, - "5444932814080651576": { - "message": "cancelAnimation(): reason=%s", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" - }, - "622027757443954945": { - "message": "cleanupAnimation(): Notify animation finished mPendingAnimations=%d reorderMode=%d", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" - }, - "-5444412205083968021": { - "message": "createAnimationAdapter(): container=%s", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "6986037643494242400": { - "message": "goodToGo()", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "-1902984034737899928": { - "message": "goodToGo(): Animation canceled already", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "6727618365838540075": { - "message": "goodToGo(): No apps to animate, mPendingAnimations=%d", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "-2525509826755873433": { - "message": "goodToGo(): onAnimationStart, transit=%s, apps=%d, wallpapers=%d, nonApps=%d", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "-1148281153370899511": { - "message": "startAnimation(): Notify animation start:", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "7501495587927045391": { - "message": "cancelAnimation(): reason=%s", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "-1424368765415574722": { - "message": "Starting remote animation", - "level": "INFO", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "-2676700429940607853": { - "message": "%s", - "level": "INFO", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "7094394833775573933": { - "message": "createAppAnimations()", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "-4411070227420990074": { - "message": "\tAdd container=%s", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "-4411631520586057580": { - "message": "\tRemove container=%s", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "-7002230949892506736": { - "message": "createWallpaperAnimations()", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "8743612568733301175": { - "message": "createNonAppWindowAnimations()", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "-2716313493239418198": { - "message": "onAnimationFinished(): mPendingAnimations=%d", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "7221400292415257709": { - "message": "onAnimationFinished(): Notify animation finished:", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "7483194715776694698": { - "message": "\tcontainer=%s", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "6697982664439247822": { - "message": "\twallpaper=%s", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "6938838346517131964": { - "message": "\tnonApp=%s", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "-3880290251819699866": { - "message": "Finishing remote animation", - "level": "INFO", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "-7169244688499657832": { - "message": "app-onAnimationFinished(): mOuter=%s", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "3923111589554171989": { - "message": "app-release(): mOuter=%s", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "8918152561092803537": { - "message": "startAnimation", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "1736084564226683342": { - "message": "Starting remote display change: from [rot = %d], to [%dx%d, rot = %d]", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/RemoteDisplayChangeController.java" - }, - "-4617490621756721600": { - "message": "resetTaskIntendedTask: calling finishActivity on %s", - "level": "WARN", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java" - }, - "3361857745281957526": { - "message": "Removing activity %s from task=%s adding to task=%s Callers=%s", - "level": "INFO", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java" - }, - "3958829063955690349": { - "message": "Pushing next activity %s out to target's task %s", - "level": "VERBOSE", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java" - }, - "1730793580703791926": { - "message": "Start pushing activity %s out to bottom task %s", - "level": "VERBOSE", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java" - }, - "-8961882615747561040": { - "message": "Looking for task of %s in %s", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "8899721161806265460": { - "message": "Skipping task: (mismatch activity\/task) %s", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "6841550641928224256": { - "message": "Skipping %s: voice session", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "4468520936943270392": { - "message": "Skipping %s: different user", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "-4764624740388751268": { - "message": "Skipping %s: mismatch root %s", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "9031436623838917667": { - "message": "Skipping %s: mismatch activity type", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "6022828946761399284": { - "message": "Comparing existing cls=%s \/aff=%s to new cls=%s \/aff=%s", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "-3413620974545388702": { - "message": "Found matching class!", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "-2649361982747625232": { - "message": "For Intent %s bringing to top: %s", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "7046266138098744790": { - "message": "Found matching affinity candidate!", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "6481733556290926693": { - "message": "Not a match: %s", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "3331249072840061049": { - "message": "New topFocusedDisplayId=%d", - "level": "DEBUG", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "865845626039449679": { - "message": "SURFACE RECOVER DESTROY: %s", - "level": "INFO", - "group": "WM_SHOW_SURFACE_ALLOC", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "-4150611780753674023": { - "message": "Wallpaper may change! Adjusting", - "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "4177291132772627699": { - "message": "With display frozen, orientationChangeComplete=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "-5513616928833586179": { - "message": "Performing post-rotate rotation", - "level": "DEBUG", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "-7698723716637247994": { - "message": "handleNotObscuredLocked w: %s, w.mHasSurface: %b, w.isOnScreen(): %b, w.isDisplayedLw(): %b, w.mAttrs.userActivityTimeout: %d", - "level": "DEBUG", - "group": "WM_DEBUG_KEEP_SCREEN_ON", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "8621291657500572364": { - "message": "mUserActivityTimeout set to %d", - "level": "DEBUG", - "group": "WM_DEBUG_KEEP_SCREEN_ON", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "-1418592110950138870": { - "message": "Looking for task of type=%s, taskAffinity=%s, intent=%s, info=%s, preferredTDA=%s", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "2828976699481734755": { - "message": "No task found", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "-4405347314716558580": { - "message": "Create sleep token: tag=%s, displayId=%d", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "1329131651776855609": { - "message": "Remove sleep token: tag=%s, displayId=%d", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "1653728842643223887": { - "message": "allResumedActivitiesIdle: rootTask=%d %s not idle", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "3785779399471740019": { - "message": "allPausedActivitiesComplete: r=%s state=%s", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "4666728330189027178": { - "message": "Failed to register MediaProjectionWatcherCallback", - "level": "ERROR", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/ScreenRecordingCallbackController.java" - }, - "8010999385228654193": { - "message": " FREEZE %s: CREATE", - "level": "INFO", - "group": "WM_SHOW_SURFACE_ALLOC", - "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" - }, - "-6586462455018013482": { - "message": "Start rotation animation. customAnim=%s, mCurRotation=%s, mOriginalRotation=%s", - "level": "DEBUG", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" - }, - "-5825336546511998057": { - "message": " FREEZE %s: DESTROY", - "level": "INFO", - "group": "WM_SHOW_SURFACE_ALLOC", - "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" - }, - "6883897856740637908": { - "message": "ScreenRotation still animating: type: %d\nmDisplayAnimator: %s\nmEnterBlackFrameAnimator: %s\nmRotateScreenAnimator: %s\nmScreenshotRotationAnimator: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" - }, - "-3943622313307983155": { - "message": "ScreenRotationAnimation onAnimationEnd", - "level": "DEBUG", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" - }, - "-1594708154257031561": { - "message": " NEW SURFACE SESSION %s", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/Session.java" - }, - "2638961674625826260": { - "message": " KILL SURFACE SESSION %s", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/Session.java" - }, - "5380455212389185829": { - "message": "Removing dim surface %s on transaction %s", - "level": "DEBUG", - "group": "WM_DEBUG_DIMMER", - "at": "com\/android\/server\/wm\/SmoothDimmer.java" - }, - "-820649637734629482": { - "message": "Animation start delayed for %s", - "level": "INFO", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/SurfaceAnimator.java" - }, - "1371702561758591499": { - "message": "Animation start for %s, anim=%s", - "level": "DEBUG", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/SurfaceAnimator.java" - }, - "-5370506662233296228": { - "message": "Cancelling animation restarting=%b for %s", - "level": "INFO", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/SurfaceAnimator.java" - }, - "-3045933321063743917": { - "message": "Reparenting to original parent: %s for %s", - "level": "INFO", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/SurfaceAnimator.java" - }, - "-855083149623806053": { - "message": "Reparenting to leash for %s", - "level": "INFO", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/SurfaceAnimator.java" - }, - "-2595923278763115975": { - "message": " THUMBNAIL %s: CREATE", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/SurfaceFreezer.java" - }, - "-8609432747982701423": { - "message": "Setting Intent of %s to %s", - "level": "VERBOSE", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/Task.java" - }, - "-9155008290180285590": { - "message": "Setting Intent of %s to target %s", - "level": "VERBOSE", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/Task.java" - }, - "6424220442758232673": { - "message": "Removing and adding activity %s to root task at top callers=%s", - "level": "INFO", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/Task.java" - }, - "-1028890010429408946": { - "message": "addChild: %s at top.", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/Task.java" - }, - "38991867929900764": { - "message": "setLockTaskAuth: task=%s mLockTaskAuth=%s", - "level": "DEBUG", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/Task.java" - }, - "-3401780415681318335": { - "message": "applyAnimationUnchecked, control: %s, task: %s, transit: %s", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/Task.java" - }, - "4037728373502324767": { - "message": "resumeNextFocusableActivityWhenRootTaskIsEmpty: %s, go home", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/Task.java" - }, - "-2261257617975724313": { - "message": "Adding activity %s to task %s callers: %s", - "level": "INFO", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/Task.java" - }, - "7378236902389922467": { - "message": "App is requesting an orientation, return %d for display id=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/TaskDisplayArea.java" - }, - "2005499548343677845": { - "message": "No app is requesting an orientation, return %d for display id=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/TaskDisplayArea.java" - }, - "646076184396185067": { - "message": "App died while pausing: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "-7596917112222697106": { - "message": "Waiting for screen on due to %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "-8472961767591168851": { - "message": "Sleep needs to pause %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "-1472885369931482317": { - "message": "Sleep still waiting to pause %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "-2693016397674039814": { - "message": "Sleep still need to stop %d activities", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "8892147402270850613": { - "message": "resumeTopActivity: Skip resume: some activity pausing.", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "958293038551087087": { - "message": "resumeTopActivity: Top activity resumed %s", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "4340810061306869942": { - "message": "resumeTopActivity: Going to sleep and all paused", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "-7681635901109618685": { - "message": "resumeTopActivity: Pausing %s", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "-3463034909521330970": { - "message": "resumeTopActivity: Skip resume: need to start pausing", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "-2264725269594226780": { - "message": "resumeTopActivity: Top activity resumed (dontWaitForPause) %s", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "-8359248677489986541": { - "message": "Moving to RESUMED: %s (in existing)", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "-8483536760290526299": { - "message": "resumeTopActivity: Resumed %s", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "-4911500660485375799": { - "message": "Resume failed; resetting state to %s: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "3723891427717889172": { - "message": "resumeTopActivity: Restarting %s", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "1529152423206006904": { - "message": "startPausing: taskFrag =%s mResumedActivity=%s", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "136971836458873178": { - "message": "Moving to PAUSING: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "-208996201631695262": { - "message": "Auto-PIP allowed, requesting PIP mode via requestStartTransition(): %s, willAutoPip: %b", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "-4123447037565780632": { - "message": "Auto-PIP allowed, entering PIP mode directly: %s, didAutoPip: %b", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "-3710776151994843320": { - "message": "Key dispatch not paused for screen off", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "8543865526552245064": { - "message": "Activity not running or entered PiP, resuming next.", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "1917394294249960915": { - "message": "Enqueueing pending pause: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "-8936154984341817384": { - "message": "Complete pause: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "4971958459026584561": { - "message": "Executing finish of activity: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "-7113165071559345173": { - "message": "Enqueue pending stop if needed: %s wasStopping=%b visibleRequested=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "-3777748052684097788": { - "message": "App died during pause, not stopping: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "-2808577027789344626": { - "message": "TaskFragment appeared name=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" - }, - "-3582112419663037270": { - "message": "TaskFragment vanished name=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" - }, - "3294593748816836746": { - "message": "TaskFragment info changed name=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" - }, - "5007230330523630579": { - "message": "TaskFragment parent info changed name=%s parentTaskId=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" - }, - "6475066005515810081": { - "message": "Sending TaskFragment error exception=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" - }, - "-7893265697482064583": { - "message": "Activity=%s reparent to taskId=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" - }, - "7048981249808281819": { - "message": "Defer transition id=%d for TaskFragmentTransaction=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" - }, - "-1315509853595025526": { - "message": "Deferred transition id=%d has been continued before the TaskFragmentTransaction=%s is finished", - "level": "WARN", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" - }, - "7421521217481553621": { - "message": "Continue transition id=%d for TaskFragmentTransaction=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" - }, - "3509684748201636981": { - "message": "Register task fragment organizer=%s uid=%d pid=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" - }, - "-6777461169027010201": { - "message": "Unregister task fragment organizer=%s uid=%d pid=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" - }, - "1327792561585467865": { - "message": "Register remote animations for organizer=%s uid=%d pid=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" - }, - "-2524361347368208519": { - "message": "Unregister remote animations for organizer=%s uid=%d pid=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" - }, - "-6181189296332065162": { - "message": "Task appeared taskId=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" - }, - "6535296991997214354": { - "message": "Task vanished taskId=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" - }, - "-6638141753476761854": { - "message": "Task info changed taskId=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" - }, - "-8100069665346602959": { - "message": "Task back pressed on root taskId=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" - }, - "-610138383571469481": { - "message": "Register task organizer=%s uid=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" - }, - "1705860547080436016": { - "message": "Unregister task organizer=%s uid=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" - }, - "-2286607251115721394": { - "message": "createRootTask unknown displayId=%d", - "level": "ERROR", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" - }, - "8466395828406204368": { - "message": "Create root task displayId=%d winMode=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" - }, - "6867170298997192615": { - "message": "Delete root task display=%d winMode=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" - }, - "-4296644831871159510": { - "message": "Set intercept back pressed on root=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" - }, - "-558727273888268534": { - "message": "Restart top activity process of Task taskId=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" - }, - "-7064081458956324316": { - "message": "Update camera compat control state to %s for taskId=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" - }, - "3007492640459931179": { - "message": "Pausing rotation during re-position", - "level": "DEBUG", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/TaskPositioner.java" - }, - "5478864901888225320": { - "message": "Resuming rotation after re-position", - "level": "DEBUG", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/TaskPositioner.java" - }, - "-2700498872917476567": { - "message": "Starting a Recents transition which can be parallel.", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-8676279589273455859": { - "message": "Transition %d: Set %s as transient-launch", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "2734227875286695843": { - "message": "Override sync-method for %s because seamless rotating", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "2808217645990556209": { - "message": "Starting Transition %d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-4672522645315112127": { - "message": "Collecting in transition %d: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "65881049096729394": { - "message": " Creating Ready-group for Transition %d with root=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "1101215730201607371": { - "message": "Existence Changed in transition %d: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-3942072270654590479": { - "message": "Set transition ready=%b %d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-4688704756793656554": { - "message": " Commit activity becoming invisible: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "1817207111271920503": { - "message": " Skipping post-transition snapshot for task %d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-2960171012238790176": { - "message": " Commit wallpaper becoming invisible: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "1230784960534033968": { - "message": "Aborting Transition: %d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-892865733969888022": { - "message": "Force Playing Transition: %d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-1354622424895965634": { - "message": "#%d: Met condition: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-5350671621840749173": { - "message": "Calling onTransitionReady: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "1830385055586991567": { - "message": "Apply and finish immediately because player is disabled for transition #%d .", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-758501334967569539": { - "message": " SKIP: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-2714847784842612086": { - "message": " SKIP: is wallpaper", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "1855461834864671586": { - "message": " check sibling %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-6292043690918793069": { - "message": " SKIP: sibling is visible but not part of transition", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "7897657428993391672": { - "message": " unrelated invisible sibling %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "3873493605120555608": { - "message": " sibling is a participant with mode %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "7665553560859456426": { - "message": " SKIP: common mode mismatch. was %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-8916099332247176657": { - "message": " checking %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-6818387694968032301": { - "message": " SKIP: its sibling was rejected", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-7326702978448933012": { - "message": " keep as target %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "943961036184959431": { - "message": " remove from targets %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "841543868388687804": { - "message": " CAN PROMOTE: promoting to parent %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "743586316159041023": { - "message": "Start calculating TransitionInfo based on participants: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-7247430213293162757": { - "message": " Rejecting as detached: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-5811837191094192313": { - "message": " Rejecting as no-op: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-1153926883525904120": { - "message": " Initial targets: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-9191328656870721224": { - "message": " Final targets: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-2971560715211489406": { - "message": " Add condition %s for #%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "7631061720069910622": { - "message": " Met condition %s for #%d (%d left)", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-4770394322045550928": { - "message": " Setting Ready-group to %b. group=%s from %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "6039132370452820927": { - "message": " Setting allReady override", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-3263748870548668913": { - "message": " allReady query: used=%b override=%b defer=%d states=[%s]", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "2699903406935781477": { - "message": "Screenshotting %s [%s]", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-233096875591058130": { - "message": "Creating Transition: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "2154694726162725342": { - "message": "Start collecting in Transition: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "-4546322749928357965": { - "message": "Registering transition player %s over %d other players", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "-4250307779892136611": { - "message": "Registering transition player %s ", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "3242771541905259983": { - "message": "Attempt to unregister transition player %s but it isn't registered", - "level": "WARN", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "3691912781236221027": { - "message": "Unregistering active transition player %s at index=%d leaving %d in stack", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "-2879980134100946679": { - "message": "Unregistering transition player %s at index=%d leaving %d in stack", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "-4235778637051052061": { - "message": "Disabling player for transition #%d because display isn't enabled yet", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "4005704720444963797": { - "message": "Requesting StartTransition: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "-6030030735787868329": { - "message": "Finish Transition: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "-1611886029896664304": { - "message": "Moving #%d from collecting to waiting.", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "-7097461682459496366": { - "message": "Playing #%d in parallel on track #%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "-7364464699035275052": { - "message": "Marking #%d animation as SYNC.", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "-5509640937151643757": { - "message": "Queueing transition: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "-2741593375634604522": { - "message": "Queueing legacy sync-set: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "-5051723169912572741": { - "message": "%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "4281568181321808508": { - "message": " startWCT=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "5141999957143860655": { - "message": " info=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "3445530300764535903": { - "message": "unregister failed, couldn't find deathRecipient for %s with id=%d", - "level": "ERROR", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" - }, - "-6140852484700685564": { - "message": "Registering listener=%s with id=%d for window=%s with %s", - "level": "DEBUG", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" - }, - "3691097873058247482": { - "message": "Unregistering listener=%s with id=%d", - "level": "DEBUG", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" - }, - "6408851516381868623": { - "message": "Checking %d windows", - "level": "VERBOSE", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" - }, - "7718187745767272532": { - "message": "Skipping %s", - "level": "VERBOSE", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" - }, - "-1135667737459933313": { - "message": "coveredRegionsAbove updated with %s frame:%s region:%s", - "level": "VERBOSE", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" - }, - "854487339271667012": { - "message": "checkIfInThreshold fractionRendered=%f alpha=%f currTimeMs=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" - }, - "-2248576188205088843": { - "message": "lastState=%s newState=%s alpha=%f minAlpha=%f fractionRendered=%f minFractionRendered=%f", - "level": "VERBOSE", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" - }, - "6236170793308011579": { - "message": "Adding untrusted state listener=%s with id=%d", - "level": "DEBUG", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" - }, - "5405816744363636527": { - "message": "Adding trusted state listener=%s with id=%d", - "level": "DEBUG", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" - }, - "-5162728346383863020": { - "message": "computeFractionRendered: visibleRegion=%s screenBounds=%s contentSize=%s scale=%f,%f", - "level": "VERBOSE", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" - }, - "898769258643799441": { - "message": "fractionRendered scale=%f", - "level": "VERBOSE", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" - }, - "-455501334697331596": { - "message": "fractionRendered boundsOverSource=%f", - "level": "VERBOSE", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" - }, - "1964980935866463086": { - "message": "\tWallpaper of display=%s is not visible", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java" - }, - "8131665298937888044": { - "message": "startAnimation", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java" - }, - "8030745595351281943": { - "message": "onAnimationCancelled", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java" - }, - "-5254364639040552989": { - "message": "Hiding wallpaper %s from %s target=%s prev=%s callers=%s", - "level": "DEBUG", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" - }, - "-6856158722649737204": { - "message": "Waiting for offset complete...", - "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" - }, - "-5966696477376431672": { - "message": "Offset complete!", - "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" - }, - "4198834090919802045": { - "message": "Timeout waiting for wallpaper to offset: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" - }, - "-3477087868568520027": { - "message": "No longer animating wallpaper targets!", - "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" - }, - "-3751289048117070874": { - "message": "New wallpaper target: %s prevTarget: %s caller=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" - }, - "5625223922466895079": { - "message": "New animation: %s old animation: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" - }, - "7634524672408826188": { - "message": "Animating wallpapers: old: %s hidden=%b new: %s hidden=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" - }, - "-4345077332231178044": { - "message": "Old wallpaper still the target.", - "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" - }, - "257349083882992098": { - "message": "updateWallpaperTokens requestedVisibility=%b on keyguardLocked=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" - }, - "7408402065665963407": { - "message": "Wallpaper at display %d - visibility: %b, keyguardLocked: %b", - "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" - }, - "-8598497865499265448": { - "message": "Wallpaper target=%s prev=%s", - "level": "DEBUG", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" - }, - "-5402010429724738603": { - "message": "Wallpaper should be visible but has not been drawn yet. mWallpaperDrawState=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" - }, - "4151327328872447804": { - "message": "New home screen wallpaper: %s, prev: %s", - "level": "DEBUG", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" - }, - "6943105284590482059": { - "message": "New lock\/shared screen wallpaper: %s, prev: %s", - "level": "DEBUG", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" - }, - "-7936547457136708587": { - "message": "Wallpaper token %s visible=%b", - "level": "DEBUG", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperWindowToken.java" - }, - "7214407534407465113": { - "message": "commitVisibility: %s: visible=%b mVisibleRequested=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/WallpaperWindowToken.java" - }, - "-5360147928134631656": { - "message": ">>> OPEN TRANSACTION animate", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowAnimator.java" - }, - "-3993586364046165922": { - "message": "<<< CLOSE TRANSACTION animate", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowAnimator.java" - }, - "-5231580410559054259": { - "message": "%s is requesting orientation %d (%s)", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowContainer.java" - }, - "6949303417875346627": { - "message": "Starting animation on %s: type=%d, anim=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowContainer.java" - }, - "-8730310387200541562": { - "message": "applyAnimation: transition animation is disabled or skipped. container=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/WindowContainer.java" - }, - "2363818604357955690": { - "message": "applyAnimation: transit=%s, enter=%b, wc=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/WindowContainer.java" - }, - "2262119454684034794": { - "message": "applyAnimation: container=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/WindowContainer.java" - }, - "5857165752965610762": { - "message": "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s surfaceInsets=%s", - "level": "DEBUG", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowContainer.java" - }, - "9017113545720281233": { - "message": "Loaded animation %s for %s, duration: %d, stack=%s", - "level": "INFO", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowContainer.java" - }, - "5272307326252759722": { - "message": "onSyncFinishedDrawing %s", - "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/WindowContainer.java" - }, - "-8311909671193661340": { - "message": "setSyncGroup #%d on %s", - "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/WindowContainer.java" - }, - "-3871009616397322067": { - "message": "finishSync cancel=%b for %s", - "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/WindowContainer.java" - }, - "-4267530270533009730": { - "message": "Error sending initial configuration change to WindowContainer overlay", - "level": "ERROR", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowContainer.java" - }, - "5179630990780610966": { - "message": "Error sending initial insets change to WindowContainer overlay", - "level": "ERROR", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowContainer.java" - }, - "-131600102855790053": { - "message": " THUMBNAIL %s: CREATE", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowContainerThumbnail.java" - }, - "2163930285157267092": { - "message": "The listener does not exist.", - "level": "INFO", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowContextListenerController.java" - }, - "6139364662459841509": { - "message": "Could not register window container listener token=%s, container=%s", - "level": "ERROR", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowContextListenerController.java" - }, - "3655576047584951173": { - "message": "Window Manager Crash %s", - "level": "WTF", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-3029436704707366221": { - "message": "Attempted to add window with a client %s that is dead. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-1303710477998542095": { - "message": "Attempted to add window to a display that does not exist: %d. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "8039410207325630747": { - "message": "Attempted to add window to a display for which the application does not have access: %d. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-3451016577701561221": { - "message": "Window %s is already added", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "7245919222637411747": { - "message": "Attempted to add window with token that is not a window: %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-8579305050440451727": { - "message": "Attempted to add window with token that is a sub-window: %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-1075040941127814341": { - "message": "Attempted to add private presentation window to a non-private display. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "7599690046549866326": { - "message": "Attempted to add presentation window to a non-suitable display. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-2546047231197102533": { - "message": "Trying to add window with invalid user=%d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "3713874359318494804": { - "message": "Attempted to add window with non-application token .%s Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-6507147599943157469": { - "message": "Attempted to add window with exiting application token .%s Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-1409483453189443362": { - "message": "Attempted to add starting window to token with already existing starting window", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-1806907994917883598": { - "message": "Attempted to add starting window to token but already cleaned", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-5450131464624918523": { - "message": "Attempted to add input method window with bad token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-6484128707849211138": { - "message": "Attempted to add voice interaction window with bad token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "7768591536609704658": { - "message": "Attempted to add wallpaper window with bad token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "7497077135474110999": { - "message": "Attempted to add Accessibility overlay window with bad token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "8957851092580119204": { - "message": "Attempted to add a toast window with bad token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-1945746969404688952": { - "message": "Attempted to add QS dialog window with bad token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "3419934373251134563": { - "message": "Non-null activity for system window of rootType=%d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-1161056447389155729": { - "message": "Adding more than one toast window for UID at a time.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-7518552252637236411": { - "message": "Window types in WindowContext and LayoutParams.type should match! Type from LayoutParams is %d, but type from WindowContext is %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-6055615852717459196": { - "message": "addWindow: %s startingWindow=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-2829980616540274784": { - "message": "addWindow: New client %s: window=%s Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-7315179333005789167": { - "message": "Attempted to add application window with unknown token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-7547709658889961930": { - "message": "Attempted to add input method window with unknown token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "3009864422591182484": { - "message": "Attempted to add voice interaction window with unknown token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-2639914438438144071": { - "message": "Attempted to add wallpaper window with unknown token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-7529563697886120786": { - "message": "Attempted to add QS dialog window with unknown token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "4253401518117961686": { - "message": "Attempted to add Accessibility overlay window with unknown token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "5834230650841873680": { - "message": "Attempted to add a toast window with unknown token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "5265273548711408921": { - "message": "postWindowRemoveCleanupLocked: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-3847568084407666790": { - "message": "Final remove of window: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_MOVEMENT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "1419572818243106725": { - "message": "Removing %s from %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "8312693933819247897": { - "message": "Relayout %s: oldVis=%d newVis=%d. %s", - "level": "INFO", - "group": "WM_DEBUG_SCREEN_ON", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "8319702790708803735": { - "message": "Exception thrown when creating surface for client %s (%s). %s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "212929172223901460": { - "message": "Relayout of %s: focusMayChange=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-255991894956556845": { - "message": "Set animatingExit: reason=startExitingAnimation\/%s win=%s", - "level": "DEBUG", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "6555160513135851764": { - "message": "OUT SURFACE %s: copied", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-196459205494031145": { - "message": "Failed to create surface control for %s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-5512006943172316333": { - "message": "finishDrawingWindow: %s mDrawState=%s", - "level": "DEBUG", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-2577785761087081584": { - "message": "Permission Denial: %s from pid=%d, uid=%d requires %s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "4547566763172245740": { - "message": "addWindowToken: Attempted to add token: %s for non-exiting displayId=%d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-972832559831959983": { - "message": "addWindowToken: Attempted to add binder token: %s for already created window token: %s displayId=%d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "8372202339190060748": { - "message": "attachWindowContextToDisplayArea: calling from non-existing process pid=%d uid=%d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "1904306629015452865": { - "message": "attachWindowContextToDisplayArea: trying to attach to a non-existing display:%d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-6845859096032432107": { - "message": "attachWindowContextToDisplayContent: calling from non-existing process pid=%d uid=%d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "1473791807245791604": { - "message": "attachWindowContextToWindowToken: calling from non-existing process pid=%d uid=%d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-2056866750160555704": { - "message": "Then token:%s is invalid. It might be removed", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-1045756671264607145": { - "message": "removeWindowToken: Attempted to remove token: %s for non-exiting displayId=%d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "874825105313641295": { - "message": "removeWindowToken: Attempted to remove non-existing token: %s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "5128669121055635771": { - "message": "moveWindowTokenToDisplay: Attempted to move token: %s to non-exiting displayId=%d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "6497954191906583839": { - "message": "moveWindowTokenToDisplay: Attempted to move non-existing token: %s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "2865882097969084039": { - "message": "moveWindowTokenToDisplay: Cannot move to the original display for token: %s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-886583195545553099": { - "message": "Not moving display (displayId=%d) to top. Top focused displayId=%d. Reason: FLAG_STEAL_TOP_FOCUS_DISABLED", - "level": "INFO", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-1557387535886241553": { - "message": "enableScreenAfterBoot: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s", - "level": "INFO", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-6467850045030187736": { - "message": "enableScreenIfNeededLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s", - "level": "INFO", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "179762478329442868": { - "message": "***** BOOT TIMEOUT: forcing display enabled", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-3417569256875279779": { - "message": "performEnableScreen: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s", - "level": "INFO", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-7516915153725082358": { - "message": "performEnableScreen: Waited %dms for all windows to be drawn", - "level": "INFO", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-1541244520024033685": { - "message": "performEnableScreen: Waiting for anim complete", - "level": "INFO", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "2670150656385758826": { - "message": "performEnableScreen: bootFinished() failed.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "530628508916855904": { - "message": "******************** ENABLING SCREEN!", - "level": "INFO", - "group": "WM_DEBUG_SCREEN_ON", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "5477889324043875194": { - "message": "Notified TransitionController that the display is ready.", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-2061779801633179448": { - "message": "checkBootAnimationComplete: Waiting for anim complete", - "level": "INFO", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-8177456840019985809": { - "message": "checkBootAnimationComplete: Animation complete!", - "level": "INFO", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-333924817004774456": { - "message": "showBootMessage: msg=%s always=%b mAllowBootMessages=%b mShowingBootMessages=%b mSystemBooted=%b. %s", - "level": "INFO", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "2994810644159608200": { - "message": "hideBootMessagesLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s", - "level": "INFO", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-6625203651195752178": { - "message": "freezeDisplayRotation: current rotation=%d, new rotation=%d, caller=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "8988910478484254861": { - "message": "thawRotation: mRotation=%d, caller=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "7261084872394224738": { - "message": "updateRotationUnchecked: alwaysSendConfiguration=%b forceRelayout=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "8664813170125714536": { - "message": "View server did not start", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-8019372496359375449": { - "message": "Could not send command %s with parameters %s. %s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "1893303527772009363": { - "message": "Devices still not ready after waiting %d milliseconds before attempting to detect safe mode.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-3652974372240081071": { - "message": "SAFE MODE ENABLED (menu=%d s=%d dpad=%d trackball=%d)", - "level": "INFO", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "4945624619344146947": { - "message": "SAFE MODE not enabled", - "level": "INFO", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-3428027271337724889": { - "message": "Focus changing: %s -> %s", - "level": "INFO", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "1624328195833150047": { - "message": "App freeze timeout expired.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "5830724144971462783": { - "message": "Timeout waiting for drawn: undrawn=%s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-2240705227895260140": { - "message": "CHECK_IF_BOOT_ANIMATION_FINISHED:", - "level": "INFO", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "8641557333789260779": { - "message": "FORCED DISPLAY SIZE: %dx%d", - "level": "INFO", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "3781141652793604337": { - "message": "FORCED DISPLAY SCALING DISABLED", - "level": "INFO", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "4117606810523219596": { - "message": "Failed looking up window session=%s callers=%s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "1233670725456443473": { - "message": "Changing surface while display frozen: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-1716033239040181528": { - "message": "Waiting for drawn %s: removed=%b visible=%b mHasSurface=%b drawState=%d", - "level": "INFO", - "group": "WM_DEBUG_SCREEN_ON", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-4609828204247499633": { - "message": "Aborted waiting for drawn: %s", - "level": "WARN", - "group": "WM_DEBUG_SCREEN_ON", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-7561054602203220590": { - "message": "Window drawn win=%s", - "level": "DEBUG", - "group": "WM_DEBUG_SCREEN_ON", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "2809030008663191766": { - "message": "All windows drawn!", - "level": "DEBUG", - "group": "WM_DEBUG_SCREEN_ON", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-1615905649072328410": { - "message": "startFreezingDisplayLocked: exitAnim=%d enterAnim=%d called by %s", - "level": "DEBUG", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "4565793239453546297": { - "message": "stopFreezingDisplayLocked: Returning waitingForConfig=%b, waitingForRemoteDisplayChange=%b, mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, mClientFreezingScreen=%b, mOpeningApps.size()=%d", - "level": "DEBUG", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-6877112251967196129": { - "message": "stopFreezingDisplayLocked: Unfreezing now", - "level": "DEBUG", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "721393258715103117": { - "message": "%s", - "level": "INFO", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-5706083447992207254": { - "message": "**** Dismissing screen rotation animation", - "level": "INFO", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "2233371241933584073": { - "message": "Performing post-rotate rotation", - "level": "DEBUG", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "1010635158502326025": { - "message": "unable to call receiver for empty keyboard shortcuts", - "level": "ERROR", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "1278715281433572858": { - "message": "Bad requesting window %s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-6186782212018913664": { - "message": "Invalid displayId for requestScrollCapture: %d", - "level": "ERROR", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "51378282333944649": { - "message": "requestScrollCapture: caught exception dispatching to window.token=%s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-8972916676375201577": { - "message": "requestScrollCapture: caught exception dispatching callback: %s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-1875125162673622728": { - "message": "Attempted to get windowing mode of a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "3938331948687900219": { - "message": "Attempted to set windowing mode to a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "4200292050699107329": { - "message": "Attempted to get remove mode of a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-5574580669790275797": { - "message": "Attempted to set remove mode to a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "525945815055875796": { - "message": "Attempted to get flag of a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "8186524992939307511": { - "message": "Attempted to set flag to a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-600035824255550632": { - "message": "Attempted to get system decors flag of a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "3056518663346732662": { - "message": "Attempted to set system decors flag to a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "5177195624625618567": { - "message": "Attempted to get IME policy of a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "3932627933834459400": { - "message": "Attempted to set IME policy to a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "5770211341769258866": { - "message": "setWallpaperShowWhenLocked: non-existent wallpaper token: %s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "698926505694016512": { - "message": "setWallpaperCropHints: non-existent wallpaper token: %s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-7428028317216329062": { - "message": "hideIme target: %s ", - "level": "DEBUG", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "1006302987953651112": { - "message": "hideIme Control target: %s ", - "level": "DEBUG", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "5213970642134448962": { - "message": "Attempted to get home support flag of a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-2065144681579661392": { - "message": "onPointerDownOutsideFocusLocked called on %s", - "level": "INFO", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-7394143854567081754": { - "message": "grantEmbeddedWindowFocus win=%s dropped focus so setting focus to null since no candidate was found", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-6056928081282320632": { - "message": "grantEmbeddedWindowFocus win=%s grantFocus=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "6110791601270766802": { - "message": "TaskFragmentTransaction changes are not collected in transition because there is an ongoing sync for applySyncTransaction().", - "level": "WARN", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowOrganizerController.java" - }, - "9200403125156001641": { - "message": "Apply window transaction, syncId=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/WindowOrganizerController.java" - }, - "433446585990132440": { - "message": "Set sync ready, syncId=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/WindowOrganizerController.java" - }, - "6552038620140878489": { - "message": "Transaction ready, syncId=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/WindowOrganizerController.java" - }, - "-4629255026637000251": { - "message": "Sending to proc %s new config %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/WindowProcessController.java" - }, - "-7237767461056267619": { - "message": "%s: Setting back callback %s", - "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "8135615413833185273": { - "message": "Adding %s to %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "8842744325264128950": { - "message": "Resize reasons for w=%s: %s configChanged=%b didFrameInsetsChange=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_RESIZE", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-8636590597069784069": { - "message": "Resizing window %s", - "level": "VERBOSE", - "group": "WM_DEBUG_RESIZE", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-2710188685736986208": { - "message": "Orientation not waiting for draw in %s, surfaceController %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "5236278969232209904": { - "message": "onMovedByResize: Moving %s", - "level": "DEBUG", - "group": "WM_DEBUG_RESIZE", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "7646042751617940718": { - "message": "Set animatingExit: reason=onAppVisibilityChanged win=%s", - "level": "DEBUG", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "1783521309242112490": { - "message": "onResize: Resizing %s", - "level": "DEBUG", - "group": "WM_DEBUG_RESIZE", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "1351053513466395411": { - "message": "WS.removeImmediately: %s Already removed...", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "3927343382258792268": { - "message": "removeIfPossible: %s callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-4831815184899821371": { - "message": "Starting window removed %s", - "level": "DEBUG", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-5803097884846965819": { - "message": "Remove client=%x, surfaceController=%s Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-2547748024041128829": { - "message": "Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b mHasSurface=%b surfaceShowing=%b animating=%b app-animation=%b mDisplayFrozen=%b callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "7789778354950913237": { - "message": "Set animatingExit: reason=remove\/applyAnimation win=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-4143841388126586338": { - "message": "Not removing %s due to exit animation", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "4419190702135590390": { - "message": "Set animatingExit: reason=remove\/isAnimating win=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-6167820560758523840": { - "message": "setAnimationLocked: setting mFocusMayChange true", - "level": "INFO", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-208079497999140637": { - "message": "WindowState.hideLw: setting mFocusMayChange true", - "level": "INFO", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "8812513438749898553": { - "message": "set mOrientationChanging of %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-2964267636425934067": { - "message": "win=%s destroySurfaces: appStopped=%b win.mWindowRemovalAllowed=%b win.mRemoveOnExit=%b", - "level": "ERROR", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "7336961102428192483": { - "message": "Clear animatingExit: reason=destroySurface win=%s", - "level": "DEBUG", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-6920306331987525705": { - "message": "Reporting new frame to %s: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_RESIZE", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "2714651498627020992": { - "message": "Resizing %s WITH DRAW PENDING", - "level": "INFO", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-5755338358883139945": { - "message": "Requested redraw for orientation change: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-5211036212243647844": { - "message": "notifyInsetsChanged for %s ", - "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_INSETS", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-3186229270467822891": { - "message": "notifyInsetsControlChanged for %s ", - "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_INSETS", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-7413136364930452718": { - "message": "performShowLocked: mDrawState=HAS_DRAWN in %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "7624470121297688739": { - "message": "shouldWaitAnimatingExit: isTransition: %s", - "level": "DEBUG", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "810267895099109466": { - "message": "shouldWaitAnimatingExit: isAnimating: %s", - "level": "DEBUG", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-1760879391350377377": { - "message": "shouldWaitAnimatingExit: isWallpaperTarget: %s", - "level": "DEBUG", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "272960397873328729": { - "message": "Clear window stuck on animatingExit status: %s", - "level": "WARN", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-1007526574020149845": { - "message": "onExitAnimationDone in %s: exiting=%b remove=%b selfAnimating=%b anim=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "1738645946553610841": { - "message": "Exit animation finished in %s: remove=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-7737516306844862315": { - "message": "Clear animatingExit: reason=exitAnimationDone win=%s", - "level": "DEBUG", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-3153130647145726082": { - "message": "Clear animatingExit: reason=clearAnimatingFlags win=%s", - "level": "DEBUG", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-5202247309108694583": { - "message": "Clear animatingExit: reason=relayoutVisibleWindow win=%s", - "level": "DEBUG", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "6291563604478341956": { - "message": "Setting move animation on %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-5774445199273871848": { - "message": "Preparing to sync a window that was already in the sync, so try dropping buffer. win=%s", - "level": "DEBUG", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "8097934579596343476": { - "message": "Got a buffer for request id=%d but latest request is id=%d. Since the buffer is out-of-date, drop it. win=%s", - "level": "DEBUG", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "8269653477215188641": { - "message": "SURFACE isSecure=%b: %s", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-1495677286613044867": { - "message": "Animation done in %s: exiting=%b, reportedVisible=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" - }, - "3436877176443058520": { - "message": "Finishing drawing window %s: mDrawState=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" - }, - "345647873457403698": { - "message": "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING %s in %s", - "level": "VERBOSE", - "group": "WM_DEBUG_DRAW", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" - }, - "-2385558637577093121": { - "message": "Draw state now committed in %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" - }, - "-3490933626936411542": { - "message": "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW %s", - "level": "INFO", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" - }, - "-6088246515441976339": { - "message": "createSurface %s: mDrawState=DRAW_PENDING", - "level": "INFO", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" - }, - "2353125758087345363": { - "message": " CREATE SURFACE %s IN SESSION %s: pid=%d format=%d flags=0x%x \/ %s", - "level": "INFO", - "group": "WM_SHOW_SURFACE_ALLOC", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" - }, - "-4491856282178275074": { - "message": "SURFACE DESTROY: %s. %s", - "level": "INFO", - "group": "WM_SHOW_SURFACE_ALLOC", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" - }, - "8602950884833508970": { - "message": "Orientation change skips hidden %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" - }, - "-5079712802591263622": { - "message": "SURFACE controller=%s alpha=%f HScale=%f, VScale=%f: %s", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" - }, - "-2824875917893878016": { - "message": "Orientation continue waiting for draw in %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" - }, - "7457181879495900576": { - "message": "Orientation change complete in %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" - }, - "-5668794009329913533": { - "message": "applyAnimation: win=%s anim=%d attr=0x%x a=%s transit=%d type=%d isEntrance=%b Callers %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" - }, - "-2055407587764455051": { - "message": "SURFACE HIDE ( %s ): %s", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowSurfaceController.java" - }, - "-5854683348829455340": { - "message": "Destroying surface %s called by %s", - "level": "INFO", - "group": "WM_SHOW_SURFACE_ALLOC", - "at": "com\/android\/server\/wm\/WindowSurfaceController.java" - }, - "7813672046338784579": { - "message": "SURFACE isOpaque=%b: %s", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowSurfaceController.java" - }, - "-8864150640874799238": { - "message": "SURFACE isColorSpaceAgnostic=%b: %s", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowSurfaceController.java" - }, - "-8398940245851553814": { - "message": "SURFACE SHOW (performLayout): %s", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowSurfaceController.java" - }, - "8174298531248485625": { - "message": "removeAllWindowsIfPossible: removing win=%s", - "level": "WARN", - "group": "WM_DEBUG_WINDOW_MOVEMENT", - "at": "com\/android\/server\/wm\/WindowToken.java" - }, - "2740931087734487464": { - "message": "addWindow: win=%s Callers=%s", - "level": "DEBUG", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/WindowToken.java" - }, - "2382798629637143561": { - "message": "Adding %s to %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowToken.java" - }, - "-7314975896738778749": { - "message": "setClientVisible: %s clientVisible=%b Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowToken.java" - } - }, - "groups": { - "WM_DEBUG_ADD_REMOVE": { - "tag": "WindowManager" - }, - "WM_DEBUG_ANIM": { - "tag": "WindowManager" - }, - "WM_DEBUG_APP_TRANSITIONS": { - "tag": "WindowManager" - }, - "WM_DEBUG_APP_TRANSITIONS_ANIM": { - "tag": "WindowManager" - }, - "WM_DEBUG_BACK_PREVIEW": { - "tag": "CoreBackPreview" - }, - "WM_DEBUG_BOOT": { - "tag": "WindowManager" - }, - "WM_DEBUG_CONFIGURATION": { - "tag": "WindowManager" - }, - "WM_DEBUG_CONTAINERS": { - "tag": "WindowManager" - }, - "WM_DEBUG_CONTENT_RECORDING": { - "tag": "WindowManager" - }, - "WM_DEBUG_DIMMER": { - "tag": "WindowManager" - }, - "WM_DEBUG_DRAW": { - "tag": "WindowManager" - }, - "WM_DEBUG_DREAM": { - "tag": "WindowManager" - }, - "WM_DEBUG_EMBEDDED_WINDOWS": { - "tag": "WindowManager" - }, - "WM_DEBUG_FOCUS": { - "tag": "WindowManager" - }, - "WM_DEBUG_FOCUS_LIGHT": { - "tag": "WindowManager" - }, - "WM_DEBUG_IME": { - "tag": "WindowManager" - }, - "WM_DEBUG_IMMERSIVE": { - "tag": "WindowManager" - }, - "WM_DEBUG_KEEP_SCREEN_ON": { - "tag": "WindowManager" - }, - "WM_DEBUG_LOCKTASK": { - "tag": "WindowManager" - }, - "WM_DEBUG_ORIENTATION": { - "tag": "WindowManager" - }, - "WM_DEBUG_RECENTS_ANIMATIONS": { - "tag": "WindowManager" - }, - "WM_DEBUG_REMOTE_ANIMATIONS": { - "tag": "WindowManager" - }, - "WM_DEBUG_RESIZE": { - "tag": "WindowManager" - }, - "WM_DEBUG_SCREEN_ON": { - "tag": "WindowManager" - }, - "WM_DEBUG_STARTING_WINDOW": { - "tag": "WindowManager" - }, - "WM_DEBUG_STATES": { - "tag": "WindowManager" - }, - "WM_DEBUG_SWITCH": { - "tag": "WindowManager" - }, - "WM_DEBUG_SYNC_ENGINE": { - "tag": "WindowManager" - }, - "WM_DEBUG_TASKS": { - "tag": "WindowManager" - }, - "WM_DEBUG_TPL": { - "tag": "WindowManager" - }, - "WM_DEBUG_WALLPAPER": { - "tag": "WindowManager" - }, - "WM_DEBUG_WINDOW_INSETS": { - "tag": "WindowManager" - }, - "WM_DEBUG_WINDOW_MOVEMENT": { - "tag": "WindowManager" - }, - "WM_DEBUG_WINDOW_ORGANIZER": { - "tag": "WindowManager" - }, - "WM_DEBUG_WINDOW_TRANSITIONS": { - "tag": "WindowManager" - }, - "WM_DEBUG_WINDOW_TRANSITIONS_MIN": { - "tag": "WindowManager" - }, - "WM_ERROR": { - "tag": "WindowManager" - }, - "WM_SHOW_SURFACE_ALLOC": { - "tag": "WindowManager" - }, - "WM_SHOW_TRANSACTIONS": { - "tag": "WindowManager" - } - } -} diff --git a/keystore/OWNERS b/keystore/OWNERS index 913f65586cd6..689177715711 100644 --- a/keystore/OWNERS +++ b/keystore/OWNERS @@ -1,4 +1,5 @@ # Bug component: 189335 +drysdale@google.com eranm@google.com jbires@google.com swillden@google.com diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java index e8f01c273550..94c281fa9fac 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java @@ -16,6 +16,9 @@ package androidx.window.extensions.embedding; +import static android.content.pm.ActivityInfo.CONFIG_DENSITY; +import static android.content.pm.ActivityInfo.CONFIG_LAYOUT_DIRECTION; +import static android.content.pm.ActivityInfo.CONFIG_WINDOW_CONFIGURATION; import static android.util.TypedValue.COMPLEX_UNIT_DIP; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; @@ -40,7 +43,6 @@ import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityThread; import android.content.Context; -import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Color; import android.graphics.PixelFormat; @@ -683,46 +685,53 @@ class DividerPresenter implements View.OnTouchListener { ? taskBounds.width() - mProperties.mDividerWidthPx : taskBounds.height() - mProperties.mDividerWidthPx; - if (isDraggingToFullscreenAllowed(mProperties.mDividerAttributes)) { - final float displayDensity = getDisplayDensity(); - return dividerPositionWithDraggingToFullscreenAllowed( - dividerPosition, - minPosition, - maxPosition, - fullyExpandedPosition, - velocity, - displayDensity); - } - return Math.clamp(dividerPosition, minPosition, maxPosition); + final float displayDensity = getDisplayDensity(); + final boolean isDraggingToFullscreenAllowed = + isDraggingToFullscreenAllowed(mProperties.mDividerAttributes); + return dividerPositionWithPositionOptions( + dividerPosition, + minPosition, + maxPosition, + fullyExpandedPosition, + velocity, + displayDensity, + isDraggingToFullscreenAllowed); } /** - * Returns the divider position given a set of position options. A snap algorithm is used to - * adjust the ending position to either fully expand one container or move the divider back to - * the specified min/max ratio depending on the dragging velocity. + * Returns the divider position given a set of position options. A snap algorithm can adjust + * the ending position to either fully expand one container or move the divider back to + * the specified min/max ratio depending on the dragging velocity and if dragging to fullscreen + * is allowed. */ @VisibleForTesting - static int dividerPositionWithDraggingToFullscreenAllowed(int dividerPosition, int minPosition, - int maxPosition, int fullyExpandedPosition, float velocity, float displayDensity) { - final float minDismissVelocityPxPerSecond = - MIN_DISMISS_VELOCITY_DP_PER_SECOND * displayDensity; + static int dividerPositionWithPositionOptions(int dividerPosition, int minPosition, + int maxPosition, int fullyExpandedPosition, float velocity, float displayDensity, + boolean isDraggingToFullscreenAllowed) { + if (isDraggingToFullscreenAllowed) { + final float minDismissVelocityPxPerSecond = + MIN_DISMISS_VELOCITY_DP_PER_SECOND * displayDensity; + if (dividerPosition < minPosition && velocity < -minDismissVelocityPxPerSecond) { + return 0; + } + if (dividerPosition > maxPosition && velocity > minDismissVelocityPxPerSecond) { + return fullyExpandedPosition; + } + } final float minFlingVelocityPxPerSecond = MIN_FLING_VELOCITY_DP_PER_SECOND * displayDensity; - if (dividerPosition < minPosition && velocity < -minDismissVelocityPxPerSecond) { - return 0; + if (Math.abs(velocity) >= minFlingVelocityPxPerSecond) { + return dividerPositionForFling( + dividerPosition, minPosition, maxPosition, velocity); } - if (dividerPosition > maxPosition && velocity > minDismissVelocityPxPerSecond) { - return fullyExpandedPosition; + if (dividerPosition >= minPosition && dividerPosition <= maxPosition) { + return dividerPosition; } - if (Math.abs(velocity) < minFlingVelocityPxPerSecond) { - if (dividerPosition >= minPosition && dividerPosition <= maxPosition) { - return dividerPosition; - } - final int[] snapPositions = {0, minPosition, maxPosition, fullyExpandedPosition}; - return snap(dividerPosition, snapPositions); - } - return dividerPositionForFling( - dividerPosition, minPosition, maxPosition, velocity); + return snap( + dividerPosition, + isDraggingToFullscreenAllowed + ? new int[] {0, minPosition, maxPosition, fullyExpandedPosition} + : new int[] {minPosition, maxPosition}); } /** @@ -959,7 +968,7 @@ class DividerPresenter implements View.OnTouchListener { @VisibleForTesting static class Properties { private static final int CONFIGURATION_MASK_FOR_DIVIDER = - ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_WINDOW_CONFIGURATION; + CONFIG_DENSITY | CONFIG_WINDOW_CONFIGURATION | CONFIG_LAYOUT_DIRECTION; @NonNull private final Configuration mConfiguration; @NonNull @@ -1228,6 +1237,12 @@ class DividerPresenter implements View.OnTouchListener { FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL | FLAG_SLIPPERY, PixelFormat.TRANSLUCENT); lp.setTitle(WINDOW_NAME); + + // Ensure that the divider layout is always LTR regardless of the locale, because we + // already considered the locale when determining the split layout direction and the + // computed divider line position always starts from the left. This only affects the + // horizontal layout and does not have any effect on the top-to-bottom layout. + mDividerLayout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR); mViewHost.setView(mDividerLayout, lp); mViewHost.relayout(lp); } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java index eade86e50659..d888fa9d6feb 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java @@ -658,27 +658,28 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { } /** - * Returns the expanded bounds if the {@code bounds} violate minimum dimension or are not fully - * covered by the task bounds. Otherwise, returns {@code bounds}. + * Returns the expanded bounds if the {@code relBounds} violate minimum dimension or are not + * fully covered by the task bounds. Otherwise, returns {@code relBounds}. */ @NonNull - static Rect sanitizeBounds(@NonNull Rect bounds, @Nullable Size minDimension, + static Rect sanitizeBounds(@NonNull Rect relBounds, @Nullable Size minDimension, @NonNull TaskFragmentContainer container) { - if (bounds.isEmpty()) { + if (relBounds.isEmpty()) { // Don't need to check if the bounds follows the task bounds. - return bounds; + return relBounds; } - if (boundsSmallerThanMinDimensions(bounds, minDimension)) { + if (boundsSmallerThanMinDimensions(relBounds, minDimension)) { // Expand the bounds if the bounds are smaller than minimum dimensions. return new Rect(); } final TaskContainer taskContainer = container.getTaskContainer(); - final Rect taskBounds = taskContainer.getBounds(); - if (!taskBounds.contains(bounds)) { + final Rect relTaskBounds = new Rect(taskContainer.getBounds()); + relTaskBounds.offsetTo(0, 0); + if (!relTaskBounds.contains(relBounds)) { // Expand the bounds if the bounds exceed the task bounds. return new Rect(); } - return bounds; + return relBounds; } @Override diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java index af3c4dac5d67..4f51815ed05d 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java @@ -660,108 +660,241 @@ public class DividerPresenterTest { // Divider position is less than minPosition and the velocity is enough to be dismissed assertEquals( 0, // Closed position - DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed( + DividerPresenter.dividerPositionWithPositionOptions( 10 /* dividerPosition */, 30 /* minPosition */, 900 /* maxPosition */, 1200 /* fullyExpandedPosition */, -dismissVelocity, - displayDensity)); + displayDensity, + true /* isDraggingToFullscreenAllowed */)); // Divider position is greater than maxPosition and the velocity is enough to be dismissed assertEquals( 1200, // Fully expanded position - DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed( + DividerPresenter.dividerPositionWithPositionOptions( 1000 /* dividerPosition */, 30 /* minPosition */, 900 /* maxPosition */, 1200 /* fullyExpandedPosition */, dismissVelocity, - displayDensity)); + displayDensity, + true /* isDraggingToFullscreenAllowed */)); // Divider position is returned when the velocity is not fast enough for fling and is in // between minPosition and maxPosition assertEquals( 500, // dividerPosition is not snapped - DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed( + DividerPresenter.dividerPositionWithPositionOptions( 500 /* dividerPosition */, 30 /* minPosition */, 900 /* maxPosition */, 1200 /* fullyExpandedPosition */, nonFlingVelocity, - displayDensity)); + displayDensity, + true /* isDraggingToFullscreenAllowed */)); // Divider position is snapped when the velocity is not fast enough for fling and larger // than maxPosition assertEquals( 900, // Closest position is maxPosition - DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed( + DividerPresenter.dividerPositionWithPositionOptions( 950 /* dividerPosition */, 30 /* minPosition */, 900 /* maxPosition */, 1200 /* fullyExpandedPosition */, nonFlingVelocity, - displayDensity)); + displayDensity, + true /* isDraggingToFullscreenAllowed */)); // Divider position is snapped when the velocity is not fast enough for fling and smaller // than minPosition assertEquals( 30, // Closest position is minPosition - DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed( + DividerPresenter.dividerPositionWithPositionOptions( 20 /* dividerPosition */, 30 /* minPosition */, 900 /* maxPosition */, 1200 /* fullyExpandedPosition */, nonFlingVelocity, - displayDensity)); + displayDensity, + true /* isDraggingToFullscreenAllowed */)); // Divider position is in the closed to maxPosition bounds and the velocity is enough for // backward fling assertEquals( 2000, // maxPosition - DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed( + DividerPresenter.dividerPositionWithPositionOptions( 2200 /* dividerPosition */, 1000 /* minPosition */, 2000 /* maxPosition */, 2500 /* fullyExpandedPosition */, -flingVelocity, - displayDensity)); + displayDensity, + true /* isDraggingToFullscreenAllowed */)); // Divider position is not in the closed to maxPosition bounds and the velocity is enough // for backward fling assertEquals( 1000, // minPosition - DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed( + DividerPresenter.dividerPositionWithPositionOptions( 1200 /* dividerPosition */, 1000 /* minPosition */, 2000 /* maxPosition */, 2500 /* fullyExpandedPosition */, -flingVelocity, - displayDensity)); + displayDensity, + true /* isDraggingToFullscreenAllowed */)); // Divider position is in the closed to minPosition bounds and the velocity is enough for // forward fling assertEquals( 1000, // minPosition - DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed( + DividerPresenter.dividerPositionWithPositionOptions( 500 /* dividerPosition */, 1000 /* minPosition */, 2000 /* maxPosition */, 2500 /* fullyExpandedPosition */, flingVelocity, - displayDensity)); + displayDensity, + true /* isDraggingToFullscreenAllowed */)); // Divider position is not in the closed to minPosition bounds and the velocity is enough // for forward fling assertEquals( 2000, // maxPosition - DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed( + DividerPresenter.dividerPositionWithPositionOptions( 1200 /* dividerPosition */, 1000 /* minPosition */, 2000 /* maxPosition */, 2500 /* fullyExpandedPosition */, flingVelocity, - displayDensity)); + displayDensity, + true /* isDraggingToFullscreenAllowed */)); + } + + @Test + public void testDividerPositionWithDraggingToFullscreenNotAllowed() { + final float displayDensity = 600F; + final float nonFlingVelocity = MIN_FLING_VELOCITY_DP_PER_SECOND * displayDensity - 10f; + final float flingVelocity = MIN_FLING_VELOCITY_DP_PER_SECOND * displayDensity + 10f; + + // Divider position is returned when the velocity is not fast enough for fling and is in + // between minPosition and maxPosition + assertEquals( + 500, // dividerPosition is not snapped + DividerPresenter.dividerPositionWithPositionOptions( + 500 /* dividerPosition */, + 30 /* minPosition */, + 900 /* maxPosition */, + 1200 /* fullyExpandedPosition */, + nonFlingVelocity, + displayDensity, + false /* isDraggingToFullscreenAllowed */)); + + // Divider position is snapped when the velocity is not fast enough for fling and larger + // than maxPosition + assertEquals( + 900, // Closest position is maxPosition + DividerPresenter.dividerPositionWithPositionOptions( + 950 /* dividerPosition */, + 30 /* minPosition */, + 900 /* maxPosition */, + 1200 /* fullyExpandedPosition */, + nonFlingVelocity, + displayDensity, + false /* isDraggingToFullscreenAllowed */)); + + // Divider position is snapped when the velocity is not fast enough for fling and smaller + // than minPosition + assertEquals( + 30, // Closest position is minPosition + DividerPresenter.dividerPositionWithPositionOptions( + 20 /* dividerPosition */, + 30 /* minPosition */, + 900 /* maxPosition */, + 1200 /* fullyExpandedPosition */, + nonFlingVelocity, + displayDensity, + false /* isDraggingToFullscreenAllowed */)); + + // Divider position is snapped when the velocity is not fast enough for fling and at the + // closed position + assertEquals( + 30, // Closest position is minPosition + DividerPresenter.dividerPositionWithPositionOptions( + 0 /* dividerPosition */, + 30 /* minPosition */, + 900 /* maxPosition */, + 1200 /* fullyExpandedPosition */, + nonFlingVelocity, + displayDensity, + false /* isDraggingToFullscreenAllowed */)); + + // Divider position is snapped when the velocity is not fast enough for fling and at the + // fully expanded position + assertEquals( + 900, // Closest position is maxPosition + DividerPresenter.dividerPositionWithPositionOptions( + 1200 /* dividerPosition */, + 30 /* minPosition */, + 900 /* maxPosition */, + 1200 /* fullyExpandedPosition */, + nonFlingVelocity, + displayDensity, + false /* isDraggingToFullscreenAllowed */)); + + // Divider position is in the closed to maxPosition bounds and the velocity is enough for + // backward fling + assertEquals( + 2000, // maxPosition + DividerPresenter.dividerPositionWithPositionOptions( + 2200 /* dividerPosition */, + 1000 /* minPosition */, + 2000 /* maxPosition */, + 2500 /* fullyExpandedPosition */, + -flingVelocity, + displayDensity, + false /* isDraggingToFullscreenAllowed */)); + + // Divider position is not in the closed to maxPosition bounds and the velocity is enough + // for backward fling + assertEquals( + 1000, // minPosition + DividerPresenter.dividerPositionWithPositionOptions( + 1200 /* dividerPosition */, + 1000 /* minPosition */, + 2000 /* maxPosition */, + 2500 /* fullyExpandedPosition */, + -flingVelocity, + displayDensity, + false /* isDraggingToFullscreenAllowed */)); + + // Divider position is in the closed to minPosition bounds and the velocity is enough for + // forward fling + assertEquals( + 1000, // minPosition + DividerPresenter.dividerPositionWithPositionOptions( + 500 /* dividerPosition */, + 1000 /* minPosition */, + 2000 /* maxPosition */, + 2500 /* fullyExpandedPosition */, + flingVelocity, + displayDensity, + false /* isDraggingToFullscreenAllowed */)); + + // Divider position is not in the closed to minPosition bounds and the velocity is enough + // for forward fling + assertEquals( + 2000, // maxPosition + DividerPresenter.dividerPositionWithPositionOptions( + 1200 /* dividerPosition */, + 1000 /* minPosition */, + 2000 /* maxPosition */, + 2500 /* fullyExpandedPosition */, + flingVelocity, + displayDensity, + false /* isDraggingToFullscreenAllowed */)); } private TaskFragmentContainer createMockTaskFragmentContainer( diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java index 0972d40f33e3..7a0b9a0ece6b 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java @@ -409,6 +409,22 @@ public class OverlayPresentationTest { } @Test + public void testSanitizeBounds_taskInSplitScreen() { + final TaskFragmentContainer overlayContainer = + createTestOverlayContainer(TASK_ID, "test1"); + TaskContainer taskContainer = overlayContainer.getTaskContainer(); + spyOn(taskContainer); + doReturn(new Rect(TASK_BOUNDS.left + TASK_BOUNDS.width() / 2, TASK_BOUNDS.top, + TASK_BOUNDS.right, TASK_BOUNDS.bottom)).when(taskContainer).getBounds(); + final Rect taskBounds = taskContainer.getBounds(); + final Rect bounds = new Rect(taskBounds.width() / 2, 0, taskBounds.width(), + taskBounds.height()); + + assertThat(sanitizeBounds(bounds, null, overlayContainer) + .isEmpty()).isFalse(); + } + + @Test public void testCreateOrUpdateOverlayTaskFragmentIfNeeded_createOverlay() { final Rect bounds = new Rect(0, 0, 100, 100); mSplitController.setActivityStackAttributesCalculator(params -> diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt index 0efdbdc9376c..327e2059557c 100644 --- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt @@ -456,5 +456,7 @@ class BubbleStackViewTest { override fun isStackExpanded(): Boolean = false override fun isShowingAsBubbleBar(): Boolean = false + + override fun hideCurrentInputMethod() {} } } diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml index bcdc2a9c8539..7b91559e9179 100644 --- a/libs/WindowManager/Shell/res/values-de/strings.xml +++ b/libs/WindowManager/Shell/res/values-de/strings.xml @@ -48,8 +48,8 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % oben"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30 % oben"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Vollbild unten"</string> - <string name="accessibility_split_left" msgid="1713683765575562458">"Links teilen"</string> - <string name="accessibility_split_right" msgid="8441001008181296837">"Rechts teilen"</string> + <string name="accessibility_split_left" msgid="1713683765575562458">"Links positionieren"</string> + <string name="accessibility_split_right" msgid="8441001008181296837">"Rechts positionieren"</string> <string name="accessibility_split_top" msgid="2789329702027147146">"Oben teilen"</string> <string name="accessibility_split_bottom" msgid="8694551025220868191">"Unten teilen"</string> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Einhandmodus wird verwendet"</string> diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml index e8b5522838b7..caa114fd6f88 100644 --- a/libs/WindowManager/Shell/res/values-ko/strings.xml +++ b/libs/WindowManager/Shell/res/values-ko/strings.xml @@ -95,7 +95,7 @@ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"앱 위치를 조정하려면 앱 외부를 두 번 탭합니다."</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"확인"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"추가 정보는 펼쳐서 확인하세요."</string> - <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"화면에 맞게 보도록 다시 시작할까요?"</string> + <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"화면에 맞게 보이도록 다시 시작할까요?"</string> <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"앱을 다시 시작하면 화면에 더 잘 맞게 볼 수는 있지만 진행 상황 또는 저장되지 않은 변경사항을 잃을 수도 있습니다."</string> <string name="letterbox_restart_cancel" msgid="1342209132692537805">"취소"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"다시 시작"</string> diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java index 8d8655addc65..4876f327a650 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java @@ -67,6 +67,10 @@ public class DesktopModeStatus { private static final boolean ENFORCE_DEVICE_RESTRICTIONS = SystemProperties.getBoolean( "persist.wm.debug.desktop_mode_enforce_device_restrictions", true); + /** Whether the desktop density override is enabled. */ + public static final boolean DESKTOP_DENSITY_OVERRIDE_ENABLED = + SystemProperties.getBoolean("persist.wm.debug.desktop_mode_density_enabled", false); + /** Override density for tasks when they're inside the desktop. */ public static final int DESKTOP_DENSITY_OVERRIDE = SystemProperties.getInt("persist.wm.debug.desktop_mode_density", 284); @@ -157,9 +161,23 @@ public class DesktopModeStatus { } /** - * Return {@code true} if the override desktop density is set. + * Return {@code true} if the override desktop density is enabled and valid. + */ + public static boolean useDesktopOverrideDensity() { + return isDesktopDensityOverrideEnabled() && isValidDesktopDensityOverrideSet(); + } + + /** + * Return {@code true} if the override desktop density is enabled. + */ + private static boolean isDesktopDensityOverrideEnabled() { + return DESKTOP_DENSITY_OVERRIDE_ENABLED; + } + + /** + * Return {@code true} if the override desktop density is set and within a valid range. */ - public static boolean isDesktopDensityOverrideSet() { + private static boolean isValidDesktopDensityOverrideSet() { return DESKTOP_DENSITY_OVERRIDE >= DESKTOP_DENSITY_MIN && DESKTOP_DENSITY_OVERRIDE <= DESKTOP_DENSITY_MAX; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java index 5600664a8f47..0119289cb0da 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java @@ -18,7 +18,6 @@ package com.android.wm.shell.back; import static com.android.internal.jank.InteractionJankMonitor.CUJ_PREDICTIVE_BACK_HOME; import static com.android.window.flags.Flags.predictiveBackSystemAnims; -import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW; import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION; @@ -41,7 +40,6 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings.Global; -import android.util.DisplayMetrics; import android.util.Log; import android.view.IRemoteAnimationRunner; import android.view.InputDevice; @@ -63,7 +61,6 @@ import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.LatencyTracker; import com.android.internal.view.AppearanceRegion; import com.android.wm.shell.R; -import com.android.wm.shell.animation.FlingAnimationUtils; import com.android.wm.shell.common.ExternalInterfaceBinder; import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; @@ -88,15 +85,6 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont public static final boolean IS_ENABLED = SystemProperties.getInt("persist.wm.debug.predictive_back", SETTING_VALUE_ON) == SETTING_VALUE_ON; - public static final float FLING_MAX_LENGTH_SECONDS = 0.1f; // 100ms - public static final float FLING_SPEED_UP_FACTOR = 0.6f; - - /** - * The maximum additional progress in case of fling gesture. - * The end animation starts after the user lifts the finger from the screen, we continue to - * fire {@link BackEvent}s until the velocity reaches 0. - */ - private static final float MAX_FLING_PROGRESS = 0.3f; /* 30% of the screen */ /** Predictive back animation developer option */ private final AtomicBoolean mEnableAnimations = new AtomicBoolean(false); @@ -119,8 +107,6 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont private boolean mPointersPilfered = false; private final boolean mRequirePointerPilfer; - private final FlingAnimationUtils mFlingAnimationUtils; - /** Registry for the back animations */ private final ShellBackAnimationRegistry mShellBackAnimationRegistry; @@ -233,11 +219,6 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont mBgHandler = bgHandler; shellInit.addInitCallback(this::onInit, this); mAnimationBackground = backAnimationBackground; - DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); - mFlingAnimationUtils = new FlingAnimationUtils.Builder(displayMetrics) - .setMaxLengthSeconds(FLING_MAX_LENGTH_SECONDS) - .setSpeedUpFactor(FLING_SPEED_UP_FACTOR) - .build(); mShellBackAnimationRegistry = shellBackAnimationRegistry; mLatencyTracker = LatencyTracker.getInstance(mContext); mShellCommandHandler = shellCommandHandler; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java index da530d740d48..1279fc42c066 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java @@ -305,6 +305,7 @@ public class Bubble implements BubbleViewProvider { getUser().getIdentifier(), getPackageName(), getTitle(), + getAppName(), isImportantConversation()); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index 317e00a44bce..644907361cd7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -518,7 +518,7 @@ public class BubbleController implements ConfigurationChangeListener, } private ExternalInterfaceBinder createExternalInterface() { - return new BubbleController.IBubblesImpl(this); + return new IBubblesImpl(this); } @VisibleForTesting @@ -592,11 +592,12 @@ public class BubbleController implements ConfigurationChangeListener, * Hides the current input method, wherever it may be focused, via InputMethodManagerInternal. */ void hideCurrentInputMethod() { + mBubblePositioner.setImeVisible(false /* visible */, 0 /* height */); int displayId = mWindowManager.getDefaultDisplay().getDisplayId(); try { mBarService.hideCurrentInputMethodForBubbles(displayId); } catch (RemoteException e) { - e.printStackTrace(); + Log.e(TAG, "Failed to hide IME", e); } } @@ -1457,8 +1458,9 @@ public class BubbleController implements ConfigurationChangeListener, SynchronousScreenCaptureListener screenCaptureListener) { try { ScreenCapture.CaptureArgs args = null; - if (mStackView != null) { - ViewRootImpl viewRoot = mStackView.getViewRootImpl(); + View viewToUse = mStackView != null ? mStackView : mLayerView; + if (viewToUse != null) { + ViewRootImpl viewRoot = viewToUse.getViewRootImpl(); if (viewRoot != null) { SurfaceControl bubbleLayer = viewRoot.getSurfaceControl(); if (bubbleLayer != null) { @@ -1550,6 +1552,12 @@ public class BubbleController implements ConfigurationChangeListener, Log.w(TAG, "Tried to add a bubble to the stack but the stack is null"); } }; + } else if (mBubbleData.isExpanded() && mBubbleData.getSelectedBubble() != null) { + callback = b -> { + if (b.getKey().equals(mBubbleData.getSelectedBubbleKey())) { + mLayerView.showExpandedView(b); + } + }; } for (int i = mBubbleData.getBubbles().size() - 1; i >= 0; i--) { Bubble bubble = mBubbleData.getBubbles().get(i); @@ -2354,6 +2362,8 @@ public class BubbleController implements ConfigurationChangeListener, @Override public void invalidate() { mController = null; + // Unregister the listeners to ensure any binder death recipients are unlinked + mListener.unregister(); } @Override @@ -2531,17 +2541,6 @@ public class BubbleController implements ConfigurationChangeListener, private CachedState mCachedState = new CachedState(); - private IBubblesImpl mIBubbles; - - @Override - public IBubbles createExternalInterface() { - if (mIBubbles != null) { - mIBubbles.invalidate(); - } - mIBubbles = new IBubblesImpl(BubbleController.this); - return mIBubbles; - } - @Override public boolean isBubbleNotificationSuppressedFromShade(String key, String groupKey) { return mCachedState.isBubbleNotificationSuppressedFromShade(key, groupKey); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java index 874102c20925..32873d96e76c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java @@ -256,11 +256,15 @@ public class BubbleData { } /** - * Returns a bubble bar update populated with the current list of active bubbles. + * Returns a bubble bar update populated with the current list of active bubbles, expanded, + * and selected state. */ public BubbleBarUpdate getInitialStateForBubbleBar() { BubbleBarUpdate initialState = mStateChange.getInitialState(); initialState.bubbleBarLocation = mPositioner.getBubbleBarLocation(); + initialState.expanded = mExpanded; + initialState.expandedChanged = mExpanded; // only matters if we're expanded + initialState.selectedBubbleKey = getSelectedBubbleKey(); return initialState; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java index 4e8afccee40f..c7ccd50af550 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java @@ -482,31 +482,38 @@ public class BubbleExpandedView extends LinearLayout { mPointerWidth, mPointerHeight, true /* pointLeft */)); mRightPointer = new ShapeDrawable(TriangleShape.createHorizontal( mPointerWidth, mPointerHeight, false /* pointLeft */)); - if (mPointerView != null) { - updatePointerView(); - } + updatePointerViewIfExists(); + updateManageButtonIfExists(); + } - if (mManageButton != null) { - int visibility = mManageButton.getVisibility(); - removeView(mManageButton); - ContextThemeWrapper ctw = new ContextThemeWrapper(getContext(), - com.android.internal.R.style.Theme_DeviceDefault_DayNight); - mManageButton = (AlphaOptimizedButton) LayoutInflater.from(ctw).inflate( - R.layout.bubble_manage_button, this /* parent */, false /* attach */); - addView(mManageButton); - mManageButton.setVisibility(visibility); - post(() -> { - int touchAreaHeight = - getResources().getDimensionPixelSize( - R.dimen.bubble_manage_button_touch_area_height); - Rect r = new Rect(); - mManageButton.getHitRect(r); - int extraTouchArea = (touchAreaHeight - r.height()) / 2; - r.top -= extraTouchArea; - r.bottom += extraTouchArea; - setTouchDelegate(new TouchDelegate(r, mManageButton)); - }); + + /** + * Reinflate manage button if {@link #mManageButton} is initialized. + * Does nothing otherwise. + */ + private void updateManageButtonIfExists() { + if (mManageButton == null) { + return; } + int visibility = mManageButton.getVisibility(); + removeView(mManageButton); + ContextThemeWrapper ctw = new ContextThemeWrapper(getContext(), + com.android.internal.R.style.Theme_DeviceDefault_DayNight); + mManageButton = (AlphaOptimizedButton) LayoutInflater.from(ctw).inflate( + R.layout.bubble_manage_button, this /* parent */, false /* attach */); + addView(mManageButton); + mManageButton.setVisibility(visibility); + post(() -> { + int touchAreaHeight = + getResources().getDimensionPixelSize( + R.dimen.bubble_manage_button_touch_area_height); + Rect r = new Rect(); + mManageButton.getHitRect(r); + int extraTouchArea = (touchAreaHeight - r.height()) / 2; + r.top -= extraTouchArea; + r.bottom += extraTouchArea; + setTouchDelegate(new TouchDelegate(r, mManageButton)); + }); } void updateFontSize() { @@ -548,11 +555,18 @@ public class BubbleExpandedView extends LinearLayout { if (mTaskView != null) { mTaskView.setCornerRadius(mCornerRadius); } - updatePointerView(); + updatePointerViewIfExists(); + updateManageButtonIfExists(); } - /** Updates the size and visuals of the pointer. **/ - private void updatePointerView() { + /** + * Updates the size and visuals of the pointer if {@link #mPointerView} is initialized. + * Does nothing otherwise. + */ + private void updatePointerViewIfExists() { + if (mPointerView == null) { + return; + } LayoutParams lp = (LayoutParams) mPointerView.getLayoutParams(); if (mCurrentPointer == mLeftPointer || mCurrentPointer == mRightPointer) { lp.width = mPointerHeight; @@ -1055,7 +1069,7 @@ public class BubbleExpandedView extends LinearLayout { // Post because we need the width of the view post(() -> { mCurrentPointer = showVertically ? onLeft ? mLeftPointer : mRightPointer : mTopPointer; - updatePointerView(); + updatePointerViewIfExists(); if (showVertically) { mPointerPos.y = bubbleCenter - (mPointerWidth / 2f); if (!isRtl) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedViewManager.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedViewManager.kt index b0d3cc4a5d5c..3d9bf032c1b0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedViewManager.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedViewManager.kt @@ -29,6 +29,7 @@ interface BubbleExpandedViewManager { fun setAppBubbleTaskId(key: String, taskId: Int) fun isStackExpanded(): Boolean fun isShowingAsBubbleBar(): Boolean + fun hideCurrentInputMethod() companion object { /** @@ -73,6 +74,10 @@ interface BubbleExpandedViewManager { override fun isStackExpanded(): Boolean = controller.isStackExpanded override fun isShowingAsBubbleBar(): Boolean = controller.isShowingAsBubbleBar + + override fun hideCurrentInputMethod() { + controller.hideCurrentInputMethod() + } } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index fac9bf6e2a4b..ed904e2ff766 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -2324,7 +2324,6 @@ public class BubbleStackView extends FrameLayout * not. */ void hideCurrentInputMethod() { - mPositioner.setImeVisible(false, 0); mManager.hideCurrentInputMethod(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java index 21b70b8e32da..0b66bcb6930e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java @@ -161,6 +161,11 @@ public class BubbleTaskViewHelper { // The taskId is saved to use for removeTask, preventing appearance in recent tasks. mTaskId = taskId; + if (mBubble != null && mBubble.isAppBubble()) { + // Let the controller know sooner what the taskId is. + mExpandedViewManager.setAppBubbleTaskId(mBubble.getKey(), mTaskId); + } + // With the task org, the taskAppeared callback will only happen once the task has // already drawn mListener.onTaskCreated(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java index 271fb9abce6a..a7da07d013c1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java @@ -82,6 +82,7 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView private static final int INVALID_TASK_ID = -1; private BubbleExpandedViewManager mManager; + private BubblePositioner mPositioner; private boolean mIsOverflow; private BubbleTaskViewHelper mBubbleTaskViewHelper; private BubbleBarMenuViewController mMenuViewController; @@ -160,6 +161,7 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView boolean isOverflow, @Nullable BubbleTaskView bubbleTaskView) { mManager = expandedViewManager; + mPositioner = positioner; mIsOverflow = isOverflow; if (mIsOverflow) { @@ -290,15 +292,27 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView } /** - * Hides the current modal menu view or collapses the bubble stack. - * Called from {@link BubbleBarLayerView} + * Hides the current modal menu if it is visible + * @return {@code true} if menu was visible and is hidden */ - public void hideMenuOrCollapse() { + public boolean hideMenuIfVisible() { if (mMenuViewController.isMenuVisible()) { - mMenuViewController.hideMenu(/* animated = */ true); - } else { - mManager.collapseStack(); + mMenuViewController.hideMenu(true /* animated */); + return true; + } + return false; + } + + /** + * Hides the IME if it is visible + * @return {@code true} if IME was visible + */ + public boolean hideImeIfVisible() { + if (mPositioner.isImeVisible()) { + mManager.hideCurrentInputMethod(); + return true; } + return false; } /** Updates the bubble shown in the expanded view. */ 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 123cc7e9d488..badc40997902 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 @@ -132,7 +132,7 @@ public class BubbleBarLayerView extends FrameLayout } }); - setOnClickListener(view -> hideMenuOrCollapse()); + setOnClickListener(view -> hideModalOrCollapse()); } @Override @@ -217,7 +217,7 @@ public class BubbleBarLayerView extends FrameLayout @Override public void onBackPressed() { - hideMenuOrCollapse(); + hideModalOrCollapse(); } }); @@ -344,15 +344,23 @@ public class BubbleBarLayerView extends FrameLayout addView(mDismissView); } - /** Hides the current modal education/menu view, expanded view or collapses the bubble stack */ - private void hideMenuOrCollapse() { + /** Hides the current modal education/menu view, IME or collapses the expanded view */ + private void hideModalOrCollapse() { if (mEducationViewController.isEducationVisible()) { mEducationViewController.hideEducation(/* animated = */ true); - } else if (isExpanded() && mExpandedView != null) { - mExpandedView.hideMenuOrCollapse(); - } else { - mBubbleController.collapseStack(); + return; + } + if (isExpanded() && mExpandedView != null) { + boolean menuHidden = mExpandedView.hideMenuIfVisible(); + if (menuHidden) { + return; + } + boolean imeHidden = mExpandedView.hideImeIfVisible(); + if (imeHidden) { + return; + } } + mBubbleController.collapseStack(); } /** Updates the expanded view size and position. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExecutorUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExecutorUtils.java deleted file mode 100644 index b29058b1f204..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExecutorUtils.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.common; - -import android.Manifest; -import android.util.Slog; - -import java.util.function.Consumer; - -/** - * Helpers for working with executors - */ -public class ExecutorUtils { - - /** - * Checks that the caller has the MANAGE_ACTIVITY_TASKS permission and executes the given - * callback. - */ - public static <T> void executeRemoteCallWithTaskPermission(RemoteCallable<T> controllerInstance, - String log, Consumer<T> callback) { - executeRemoteCallWithTaskPermission(controllerInstance, log, callback, - false /* blocking */); - } - - /** - * Checks that the caller has the MANAGE_ACTIVITY_TASKS permission and executes the given - * callback. - */ - public static <T> void executeRemoteCallWithTaskPermission(RemoteCallable<T> controllerInstance, - String log, Consumer<T> callback, boolean blocking) { - if (controllerInstance == null) return; - - final RemoteCallable<T> controller = controllerInstance; - controllerInstance.getContext().enforceCallingPermission( - Manifest.permission.MANAGE_ACTIVITY_TASKS, log); - if (blocking) { - try { - controllerInstance.getRemoteCallExecutor().executeBlocking(() -> { - callback.accept((T) controller); - }); - } catch (InterruptedException e) { - Slog.e("ExecutorUtils", "Remote call failed", e); - } - } else { - controllerInstance.getRemoteCallExecutor().execute(() -> { - callback.accept((T) controller); - }); - } - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExternalInterfaceBinder.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExternalInterfaceBinder.java index aa5b0cb628e1..d6f4d81b44f3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExternalInterfaceBinder.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExternalInterfaceBinder.java @@ -16,7 +16,11 @@ package com.android.wm.shell.common; +import android.Manifest; import android.os.IBinder; +import android.util.Slog; + +import java.util.function.Consumer; /** * An interface for binders which can be registered to be sent to other processes. @@ -31,4 +35,40 @@ public interface ExternalInterfaceBinder { * Returns the IBinder to send. */ IBinder asBinder(); + + /** + * Checks that the caller has the MANAGE_ACTIVITY_TASKS permission and executes the given + * callback. + */ + default <T> void executeRemoteCallWithTaskPermission(RemoteCallable<T> controllerInstance, + String log, Consumer<T> callback) { + executeRemoteCallWithTaskPermission(controllerInstance, log, callback, + false /* blocking */); + } + + /** + * Checks that the caller has the MANAGE_ACTIVITY_TASKS permission and executes the given + * callback. + */ + default <T> void executeRemoteCallWithTaskPermission(RemoteCallable<T> controllerInstance, + String log, Consumer<T> callback, boolean blocking) { + if (controllerInstance == null) return; + + final RemoteCallable<T> controller = controllerInstance; + controllerInstance.getContext().enforceCallingPermission( + Manifest.permission.MANAGE_ACTIVITY_TASKS, log); + if (blocking) { + try { + controllerInstance.getRemoteCallExecutor().executeBlocking(() -> { + callback.accept((T) controller); + }); + } catch (InterruptedException e) { + Slog.e("ExternalInterfaceBinder", "Remote call failed", e); + } + } else { + controllerInstance.getRemoteCallExecutor().execute(() -> { + callback.accept((T) controller); + }); + } + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java index 30f535ba940c..0d90fb7e60fb 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java @@ -19,7 +19,7 @@ package com.android.wm.shell.common; import android.content.Context; /** - * An interface for controllers that can receive remote calls. + * An interface for controllers (of type T) that can receive remote calls. */ public interface RemoteCallable<T> { /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java index 24608d651d06..829af08e612a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java @@ -45,10 +45,12 @@ public class BubbleInfo implements Parcelable { private Icon mIcon; @Nullable private String mTitle; + @Nullable + private String mAppName; private boolean mIsImportantConversation; public BubbleInfo(String key, int flags, @Nullable String shortcutId, @Nullable Icon icon, - int userId, String packageName, @Nullable String title, + int userId, String packageName, @Nullable String title, @Nullable String appName, boolean isImportantConversation) { mKey = key; mFlags = flags; @@ -57,6 +59,7 @@ public class BubbleInfo implements Parcelable { mUserId = userId; mPackageName = packageName; mTitle = title; + mAppName = appName; mIsImportantConversation = isImportantConversation; } @@ -68,6 +71,7 @@ public class BubbleInfo implements Parcelable { mUserId = source.readInt(); mPackageName = source.readString(); mTitle = source.readString(); + mAppName = source.readString(); mIsImportantConversation = source.readBoolean(); } @@ -102,6 +106,11 @@ public class BubbleInfo implements Parcelable { return mTitle; } + @Nullable + public String getAppName() { + return mAppName; + } + public boolean isImportantConversation() { return mIsImportantConversation; } @@ -161,6 +170,7 @@ public class BubbleInfo implements Parcelable { parcel.writeInt(mUserId); parcel.writeString(mPackageName); parcel.writeString(mTitle); + parcel.writeString(mAppName); parcel.writeBoolean(mIsImportantConversation); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java index 8fb9bda539a0..5d121c23c6e1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java @@ -143,6 +143,8 @@ public final class SplitWindowManager extends WindowlessWindowManager { /** * Releases the surface control of the current {@link DividerView} and tear down the view * hierarchy. + * @param t If supplied, the surface removal will be bundled with this Transaction. If + * called with null, removes the surface immediately. */ void release(@Nullable SurfaceControl.Transaction t) { if (mDividerView != null) { 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 14c9999a2fef..0807f7555c09 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 @@ -54,7 +54,6 @@ import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayLayout -import com.android.wm.shell.common.ExecutorUtils import com.android.wm.shell.common.ExternalInterfaceBinder import com.android.wm.shell.common.LaunchAdjacentController import com.android.wm.shell.common.MultiInstanceHelper @@ -76,7 +75,7 @@ import com.android.wm.shell.recents.RecentsTransitionHandler import com.android.wm.shell.recents.RecentsTransitionStateListener import com.android.wm.shell.shared.DesktopModeStatus import com.android.wm.shell.shared.DesktopModeStatus.DESKTOP_DENSITY_OVERRIDE -import com.android.wm.shell.shared.DesktopModeStatus.isDesktopDensityOverrideSet +import com.android.wm.shell.shared.DesktopModeStatus.useDesktopOverrideDensity import com.android.wm.shell.shared.annotations.ExternalThread import com.android.wm.shell.shared.annotations.ShellMainThread import com.android.wm.shell.splitscreen.SplitScreenController @@ -961,7 +960,7 @@ class DesktopTasksController( } } val wct = WindowContainerTransaction() - if (isDesktopDensityOverrideSet()) { + if (useDesktopOverrideDensity()) { wct.setDensityDpi(task.token, DESKTOP_DENSITY_OVERRIDE) } // Desktop Mode is showing and we're launching a new Task - we might need to minimize @@ -1036,7 +1035,7 @@ class DesktopTasksController( } wct.setWindowingMode(taskInfo.token, targetWindowingMode) wct.reorder(taskInfo.token, true /* onTop */) - if (isDesktopDensityOverrideSet()) { + if (useDesktopOverrideDensity()) { wct.setDensityDpi(taskInfo.token, DESKTOP_DENSITY_OVERRIDE) } } @@ -1056,7 +1055,7 @@ class DesktopTasksController( } wct.setWindowingMode(taskInfo.token, targetWindowingMode) wct.setBounds(taskInfo.token, Rect()) - if (isDesktopDensityOverrideSet()) { + if (useDesktopOverrideDensity()) { wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi()) } } @@ -1471,13 +1470,13 @@ class DesktopTasksController( } override fun showDesktopApps(displayId: Int, remoteTransition: RemoteTransition?) { - ExecutorUtils.executeRemoteCallWithTaskPermission(controller, "showDesktopApps") { c -> + executeRemoteCallWithTaskPermission(controller, "showDesktopApps") { c -> c.showDesktopApps(displayId, remoteTransition) } } override fun showDesktopApp(taskId: Int) { - ExecutorUtils.executeRemoteCallWithTaskPermission(controller, "showDesktopApp") { c -> + executeRemoteCallWithTaskPermission(controller, "showDesktopApp") { c -> c.moveTaskToFront(taskId) } } @@ -1495,7 +1494,7 @@ class DesktopTasksController( override fun getVisibleTaskCount(displayId: Int): Int { val result = IntArray(1) - ExecutorUtils.executeRemoteCallWithTaskPermission( + executeRemoteCallWithTaskPermission( controller, "getVisibleTaskCount", { controller -> result[0] = controller.getVisibleTaskCount(displayId) }, @@ -1505,7 +1504,7 @@ class DesktopTasksController( } override fun onDesktopSplitSelectAnimComplete(taskInfo: RunningTaskInfo) { - ExecutorUtils.executeRemoteCallWithTaskPermission( + executeRemoteCallWithTaskPermission( controller, "onDesktopSplitSelectAnimComplete" ) { c -> @@ -1519,13 +1518,13 @@ class DesktopTasksController( "IDesktopModeImpl: set task listener=%s", listener ?: "null" ) - ExecutorUtils.executeRemoteCallWithTaskPermission(controller, "setTaskListener") { _ -> + executeRemoteCallWithTaskPermission(controller, "setTaskListener") { _ -> listener?.let { remoteListener.register(it) } ?: remoteListener.unregister() } } override fun moveToDesktop(taskId: Int, transitionSource: DesktopModeTransitionSource) { - ExecutorUtils.executeRemoteCallWithTaskPermission(controller, "moveToDesktop") { c -> + executeRemoteCallWithTaskPermission(controller, "moveToDesktop") { c -> c.moveToDesktop(taskId, transitionSource = transitionSource) } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/changes.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/changes.md index 9aa5f4ffcd78..0acc7df98d1c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/changes.md +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/changes.md @@ -54,8 +54,8 @@ Specifically, to support calling into a controller from an external process (lik extend `ExternalInterfaceBinder` and implement `invalidate()` to ensure it doesn't hold long references to the outer controller - Make the controller implement `RemoteCallable<T>`, and have all incoming calls use one of - the `ExecutorUtils.executeRemoteCallWithTaskPermission()` calls to verify the caller's identity - and ensure the call happens on the main shell thread and not the binder thread + the `executeRemoteCallWithTaskPermission()` calls to verify the caller's identity and ensure the + call happens on the main shell thread and not the binder thread - Inject `ShellController` and add the instance of the implementation as external interface - In Launcher, update `TouchInteractionService` to pass the interface to `SystemUIProxy`, and then call the SystemUIProxy method as needed in that code diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java index 7e70d6a3debe..c374eb8e8f03 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java @@ -32,7 +32,6 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; -import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DRAG_AND_DROP; import android.app.ActivityManager; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java index 39b9000856f2..962309f7c534 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java @@ -19,7 +19,6 @@ package com.android.wm.shell.onehanded; import static android.os.UserHandle.myUserId; import static android.view.Display.DEFAULT_DISPLAY; -import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; import static com.android.wm.shell.onehanded.OneHandedState.STATE_ACTIVE; import static com.android.wm.shell.onehanded.OneHandedState.STATE_ENTERING; import static com.android.wm.shell.onehanded.OneHandedState.STATE_EXITING; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java index eb845db409e3..57c07323d1bb 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java @@ -583,7 +583,7 @@ public class PipAnimationController { } static PipTransitionAnimator<Rect> ofBounds(TaskInfo taskInfo, SurfaceControl leash, - Rect baseValue, Rect startValue, Rect endValue, Rect sourceHintRect, + Rect baseValue, Rect startValue, Rect endValue, Rect sourceRectHint, @PipAnimationController.TransitionDirection int direction, float startingAngle, @Surface.Rotation int rotationDelta) { final boolean isOutPipDirection = isOutPipDirection(direction); @@ -613,14 +613,36 @@ public class PipAnimationController { initialContainerRect = initialSourceValue; } - final Rect sourceHintRectInsets; - if (sourceHintRect == null) { - sourceHintRectInsets = null; + final Rect adjustedSourceRectHint = new Rect(); + if (sourceRectHint == null || sourceRectHint.isEmpty()) { + // Crop a Rect matches the aspect ratio and pivots at the center point. + // This is done for entering case only. + if (isInPipDirection(direction)) { + final float aspectRatio = endValue.width() / (float) endValue.height(); + if ((startValue.width() / (float) startValue.height()) > aspectRatio) { + // use the full height. + adjustedSourceRectHint.set(0, 0, + (int) (startValue.height() * aspectRatio), startValue.height()); + adjustedSourceRectHint.offset( + (startValue.width() - adjustedSourceRectHint.width()) / 2, 0); + } else { + // use the full width. + adjustedSourceRectHint.set(0, 0, + startValue.width(), (int) (startValue.width() / aspectRatio)); + adjustedSourceRectHint.offset( + 0, (startValue.height() - adjustedSourceRectHint.height()) / 2); + } + } } else { - sourceHintRectInsets = new Rect(sourceHintRect.left - initialContainerRect.left, - sourceHintRect.top - initialContainerRect.top, - initialContainerRect.right - sourceHintRect.right, - initialContainerRect.bottom - sourceHintRect.bottom); + adjustedSourceRectHint.set(sourceRectHint); + } + final Rect sourceHintRectInsets = new Rect(); + if (!adjustedSourceRectHint.isEmpty()) { + sourceHintRectInsets.set( + adjustedSourceRectHint.left - initialContainerRect.left, + adjustedSourceRectHint.top - initialContainerRect.top, + initialContainerRect.right - adjustedSourceRectHint.right, + initialContainerRect.bottom - adjustedSourceRectHint.bottom); } final Rect zeroInsets = new Rect(0, 0, 0, 0); @@ -648,7 +670,7 @@ public class PipAnimationController { } float angle = (1.0f - fraction) * startingAngle; setCurrentValue(bounds); - if (inScaleTransition() || sourceHintRect == null) { + if (inScaleTransition() || adjustedSourceRectHint.isEmpty()) { if (isOutPipDirection) { getSurfaceTransactionHelper().crop(tx, leash, end) .scale(tx, leash, end, bounds); @@ -661,7 +683,7 @@ public class PipAnimationController { } else { final Rect insets = computeInsets(fraction); getSurfaceTransactionHelper().scaleAndCrop(tx, leash, - sourceHintRect, initialSourceValue, bounds, insets, + adjustedSourceRectHint, initialSourceValue, bounds, insets, isInPipDirection, fraction); if (shouldApplyCornerRadius()) { final Rect sourceBounds = new Rect(initialContainerRect); @@ -729,9 +751,6 @@ public class PipAnimationController { } private Rect computeInsets(float fraction) { - if (sourceHintRectInsets == null) { - return zeroInsets; - } final Rect startRect = isOutPipDirection ? sourceHintRectInsets : zeroInsets; final Rect endRect = isOutPipDirection ? zeroInsets : sourceHintRectInsets; return mInsetsEvaluator.evaluate(fraction, startRect, endRect); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java index e11e8596a7fe..ff2d46e11107 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java @@ -226,11 +226,10 @@ public abstract class PipContentOverlay { appBoundsCenterX - mOverlayHalfSize, appBoundsCenterY - mOverlayHalfSize); // Scale back the bitmap with the pivot point at center. - mTmpTransform.postScale( + final float scale = Math.min( (float) mAppBounds.width() / currentBounds.width(), - (float) mAppBounds.height() / currentBounds.height(), - appBoundsCenterX, - appBoundsCenterY); + (float) mAppBounds.height() / currentBounds.height()); + mTmpTransform.postScale(scale, scale, appBoundsCenterX, appBoundsCenterY); atomicTx.setMatrix(mLeash, mTmpTransform, mTmpFloat9) .setAlpha(mLeash, fraction < 0.5f ? 0 : (fraction - 0.5f) * 2); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java index a58d94ecd19b..202f60dad842 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java @@ -137,7 +137,7 @@ public class PipSurfaceTransactionHelper { mTmpDestinationRect.inset(insets); // Scale to the bounds no smaller than the destination and offset such that the top/left // of the scaled inset source rect aligns with the top/left of the destination bounds - final float scale; + final float scale, left, top; if (isInPipDirection && sourceRectHint != null && sourceRectHint.width() < sourceBounds.width()) { // scale by sourceRectHint if it's not edge-to-edge, for entering PiP transition only. @@ -148,12 +148,15 @@ public class PipSurfaceTransactionHelper { ? (float) destinationBounds.width() / sourceBounds.width() : (float) destinationBounds.height() / sourceBounds.height(); scale = (1 - fraction) * startScale + fraction * endScale; + left = destinationBounds.left - insets.left * scale; + top = destinationBounds.top - insets.top * scale; } else { scale = Math.max((float) destinationBounds.width() / sourceBounds.width(), (float) destinationBounds.height() / sourceBounds.height()); + // Work around the rounding error by fix the position at very beginning. + left = scale == 1 ? 0 : destinationBounds.left - insets.left * scale; + top = scale == 1 ? 0 : destinationBounds.top - insets.top * scale; } - final float left = destinationBounds.left - insets.left * scale; - final float top = destinationBounds.top - insets.top * scale; mTmpTransform.setScale(scale, scale); tx.setMatrix(leash, mTmpTransform, mTmpFloat9) .setCrop(leash, mTmpDestinationRect) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index e1657f99639d..04dd0eff5d68 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -603,6 +603,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, // the end of the enter animation and reschedule exitPip to run after enter-PiP // has finished its transition and allowed the client to draw in PiP mode. mPipTransitionController.end(() -> { + // TODO(341627042): force set to entered state to avoid potential stack overflow. + mPipTransitionState.setTransitionState(PipTransitionState.ENTERED_PIP); exitPip(animationDurationMs, requestEnterSplit); }); return; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java index b52b0d8dee74..5ee6f6bb0e1f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java @@ -200,9 +200,6 @@ public class PipTransition extends PipTransitionController { animator.cancel(); } mExitTransition = mTransitions.startTransition(type, out, this); - if (mPipOrganizer.getOutPipWindowingMode() == WINDOWING_MODE_UNDEFINED) { - mHomeTransitionObserver.notifyHomeVisibilityChanged(false /* isVisible */); - } } @Override @@ -659,6 +656,9 @@ public class PipTransition extends PipTransitionController { startTransaction.remove(mPipOrganizer.mPipOverlay); mPipOrganizer.clearContentOverlay(); } + if (mPipOrganizer.getOutPipWindowingMode() == WINDOWING_MODE_UNDEFINED) { + mHomeTransitionObserver.notifyHomeVisibilityChanged(false /* isVisible */); + } if (pipChange == null) { ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: No window of exiting PIP is found. Can't play expand animation", TAG); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index 85f9194ac804..de105c00edfa 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -22,7 +22,6 @@ import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; import static android.view.WindowManager.INPUT_CONSUMER_PIP; import static com.android.internal.jank.InteractionJankMonitor.CUJ_PIP_TRANSITION; -import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java index f5afeea3eaef..1846720c9b89 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java @@ -19,7 +19,6 @@ package com.android.wm.shell.pip2.phone; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; -import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_PIP; import android.app.ActivityManager; @@ -391,6 +390,7 @@ public class PipController implements ConfigurationChangeListener, @Override public void invalidate() { mController = null; + // Unregister the listener to ensure any registered binder death recipients are unlinked mListener.unregister(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/OWNERS new file mode 100644 index 000000000000..3f3308cfc75a --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/OWNERS @@ -0,0 +1 @@ +include platform/development:/tools/winscope/OWNERS diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java index 19af3d544b36..497c3f704c82 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java @@ -18,6 +18,8 @@ package com.android.wm.shell.protolog; import com.android.internal.protolog.common.IProtoLogGroup; +import java.util.UUID; + /** * Defines logging groups for ProtoLog. * @@ -116,6 +118,11 @@ public enum ShellProtoLogGroup implements IProtoLogGroup { this.mLogToLogcat = logToLogcat; } + @Override + public int getId() { + return Consts.START_ID + this.ordinal(); + } + private static class Consts { private static final String TAG_WM_SHELL = "WindowManagerShell"; private static final String TAG_WM_STARTING_WINDOW = "ShellStartingWindow"; @@ -124,5 +131,9 @@ public enum ShellProtoLogGroup implements IProtoLogGroup { private static final boolean ENABLE_DEBUG = true; private static final boolean ENABLE_LOG_TO_PROTO_DEBUG = true; + + private static final int START_ID = (int) ( + UUID.nameUUIDFromBytes(ShellProtoLogGroup.class.getName().getBytes()) + .getMostSignificantBits() % Integer.MAX_VALUE); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java index 863202d5e1c3..9d162462830f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java @@ -20,7 +20,6 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.content.pm.PackageManager.FEATURE_PC; import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps; -import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS; import android.app.ActivityManager; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index b9d70e1a599d..dd219d32bbaa 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -24,7 +24,6 @@ import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.RemoteAnimationTarget.MODE_OPENING; -import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; import static com.android.wm.shell.common.MultiInstanceHelper.getComponent; import static com.android.wm.shell.common.MultiInstanceHelper.getShortcutComponent; import static com.android.wm.shell.common.MultiInstanceHelper.samePackage; @@ -1241,8 +1240,9 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, @Override public void invalidate() { mController = null; - // Unregister the listener to ensure any registered binder death recipients are unlinked + // Unregister the listeners to ensure any binder death recipients are unlinked mListener.unregister(); + mSelectListener.unregister(); } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 82ef422f829a..cc995eaf4192 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -1846,7 +1846,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, void finishEnterSplitScreen(SurfaceControl.Transaction finishT) { ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "finishEnterSplitScreen"); - mSplitLayout.update(finishT, true /* resetImePosition */); + mSplitLayout.update(null, true /* resetImePosition */); mMainStage.getSplitDecorManager().inflate(mContext, mMainStage.mRootLeash); mSideStage.getSplitDecorManager().inflate(mContext, mSideStage.mRootLeash); setDividerVisibility(true, finishT); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java index bec4ba3bf0d1..fa084c585a59 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java @@ -23,7 +23,6 @@ import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SOLID_COLOR import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_WINDOWLESS; -import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_STARTING_WINDOW; import android.app.ActivityManager.RunningTaskInfo; 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 b1a1e5999aa9..299da136a5b4 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 @@ -133,5 +133,7 @@ public class HomeTransitionObserver implements TransitionObserver, */ public void invalidate(Transitions transitions) { transitions.unregisterObserver(this); + // Unregister the listener to ensure any registered binder death recipients are unlinked + mListener.unregister(); } } 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 b056c18cc9f3..f257e207673d 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 @@ -35,7 +35,6 @@ import static android.window.TransitionInfo.FLAG_NO_ANIMATION; import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT; import static com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary; -import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; import static com.android.wm.shell.shared.TransitionUtil.isClosingType; import static com.android.wm.shell.shared.TransitionUtil.isOpeningType; import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SHELL_TRANSITIONS; @@ -54,6 +53,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.SystemProperties; import android.provider.Settings; +import android.util.ArrayMap; import android.util.Log; import android.util.Pair; import android.view.SurfaceControl; @@ -227,7 +227,8 @@ public class Transitions implements RemoteCallable<Transitions>, private boolean mDisableForceSync = false; private static final class ActiveTransition { - IBinder mToken; + final IBinder mToken; + TransitionHandler mHandler; boolean mAborted; TransitionInfo mInfo; @@ -237,6 +238,10 @@ public class Transitions implements RemoteCallable<Transitions>, /** Ordered list of transitions which have been merged into this one. */ private ArrayList<ActiveTransition> mMerged; + ActiveTransition(IBinder token) { + mToken = token; + } + boolean isSync() { return (mInfo.getFlags() & TransitionInfo.FLAG_SYNC) != 0; } @@ -266,6 +271,9 @@ public class Transitions implements RemoteCallable<Transitions>, } } + /** All transitions that we have created, but not yet finished. */ + private final ArrayMap<IBinder, ActiveTransition> mKnownTransitions = new ArrayMap<>(); + /** Keeps track of transitions which have been started, but aren't ready yet. */ private final ArrayList<ActiveTransition> mPendingTransitions = new ArrayList<>(); @@ -690,7 +698,7 @@ public class Transitions implements RemoteCallable<Transitions>, info.getDebugId(), transitionToken, info); int activeIdx = findByToken(mPendingTransitions, transitionToken); if (activeIdx < 0) { - final ActiveTransition existing = getKnownTransition(transitionToken); + final ActiveTransition existing = mKnownTransitions.get(transitionToken); if (existing != null) { Log.e(TAG, "Got duplicate transitionReady for " + transitionToken); // The transition is already somewhere else in the pipeline, so just return here. @@ -705,8 +713,8 @@ public class Transitions implements RemoteCallable<Transitions>, + transitionToken + ". expecting one of " + Arrays.toString(mPendingTransitions.stream().map( activeTransition -> activeTransition.mToken).toArray())); - final ActiveTransition fallback = new ActiveTransition(); - fallback.mToken = transitionToken; + final ActiveTransition fallback = new ActiveTransition(transitionToken); + mKnownTransitions.put(transitionToken, fallback); mPendingTransitions.add(fallback); activeIdx = mPendingTransitions.size() - 1; } @@ -746,7 +754,7 @@ public class Transitions implements RemoteCallable<Transitions>, // Sleep starts a process of forcing all prior transitions to finish immediately ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Start finish-for-sync track %d", i); - finishForSync(active, i, null /* forceFinish */); + finishForSync(active.mToken, i, null /* forceFinish */); } if (hadPreceding) { return false; @@ -864,6 +872,7 @@ public class Transitions implements RemoteCallable<Transitions>, } else if (mPendingTransitions.isEmpty()) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "All active transition " + "animations finished"); + mKnownTransitions.clear(); // Run all runnables from the run-when-idle queue. for (int i = 0; i < mRunWhenIdleQueue.size(); i++) { mRunWhenIdleQueue.get(i).run(); @@ -884,7 +893,7 @@ public class Transitions implements RemoteCallable<Transitions>, ready.mStartT.apply(); } // finish now since there's nothing to animate. Calls back into processReadyQueue - onFinish(ready, null); + onFinish(ready.mToken, null); return; } playTransition(ready); @@ -943,8 +952,10 @@ public class Transitions implements RemoteCallable<Transitions>, private void playTransition(@NonNull ActiveTransition active) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Playing animation for %s", active); + final var token = active.mToken; + for (int i = 0; i < mObservers.size(); ++i) { - mObservers.get(i).onTransitionStarting(active.mToken); + mObservers.get(i).onTransitionStarting(token); } setupAnimHierarchy(active.mInfo, active.mStartT, active.mFinishT); @@ -953,8 +964,8 @@ public class Transitions implements RemoteCallable<Transitions>, if (active.mHandler != null) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " try firstHandler %s", active.mHandler); - boolean consumed = active.mHandler.startAnimation(active.mToken, active.mInfo, - active.mStartT, active.mFinishT, (wct) -> onFinish(active, wct)); + boolean consumed = active.mHandler.startAnimation(token, active.mInfo, + active.mStartT, active.mFinishT, (wct) -> onFinish(token, wct)); if (consumed) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " animated by firstHandler"); mTransitionTracer.logDispatched(active.mInfo.getDebugId(), active.mHandler); @@ -962,8 +973,8 @@ public class Transitions implements RemoteCallable<Transitions>, } } // Otherwise give every other handler a chance - active.mHandler = dispatchTransition(active.mToken, active.mInfo, active.mStartT, - active.mFinishT, (wct) -> onFinish(active, wct), active.mHandler); + active.mHandler = dispatchTransition(token, active.mInfo, active.mStartT, + active.mFinishT, (wct) -> onFinish(token, wct), active.mHandler); } /** @@ -1039,10 +1050,15 @@ public class Transitions implements RemoteCallable<Transitions>, info.releaseAnimSurfaces(); } - private void onFinish(ActiveTransition active, + private void onFinish(IBinder token, @Nullable WindowContainerTransaction wct) { + final ActiveTransition active = mKnownTransitions.get(token); + if (active == null) { + Log.e(TAG, "Trying to finish a non-existent transition: " + token); + return; + } final Track track = mTracks.get(active.getTrack()); - if (track.mActiveTransition != active) { + if (track == null || track.mActiveTransition != active) { Log.e(TAG, "Trying to finish a non-running transition. Either remote crashed or " + " a handler didn't properly deal with a merge. " + active, new RuntimeException()); @@ -1095,54 +1111,25 @@ public class Transitions implements RemoteCallable<Transitions>, ActiveTransition merged = active.mMerged.get(iM); mOrganizer.finishTransition(merged.mToken, null /* wct */); releaseSurfaces(merged.mInfo); + mKnownTransitions.remove(merged.mToken); } active.mMerged.clear(); } + mKnownTransitions.remove(token); // Now that this is done, check the ready queue for more work. processReadyQueue(track); } - /** - * Checks to see if the transition specified by `token` is already known. If so, it will be - * returned. - */ - @Nullable - private ActiveTransition getKnownTransition(IBinder token) { - for (int i = 0; i < mPendingTransitions.size(); ++i) { - final ActiveTransition active = mPendingTransitions.get(i); - if (active.mToken == token) return active; - } - for (int i = 0; i < mReadyDuringSync.size(); ++i) { - final ActiveTransition active = mReadyDuringSync.get(i); - if (active.mToken == token) return active; - } - for (int t = 0; t < mTracks.size(); ++t) { - final Track tr = mTracks.get(t); - for (int i = 0; i < tr.mReadyTransitions.size(); ++i) { - final ActiveTransition active = tr.mReadyTransitions.get(i); - if (active.mToken == token) return active; - } - final ActiveTransition active = tr.mActiveTransition; - if (active == null) continue; - if (active.mToken == token) return active; - if (active.mMerged == null) continue; - for (int m = 0; m < active.mMerged.size(); ++m) { - final ActiveTransition merged = active.mMerged.get(m); - if (merged.mToken == token) return merged; - } - } - return null; - } - void requestStartTransition(@NonNull IBinder transitionToken, @Nullable TransitionRequestInfo request) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition requested (#%d): %s %s", request.getDebugId(), transitionToken, request); - if (getKnownTransition(transitionToken) != null) { + if (mKnownTransitions.containsKey(transitionToken)) { throw new RuntimeException("Transition already started " + transitionToken); } - final ActiveTransition active = new ActiveTransition(); + final ActiveTransition active = new ActiveTransition(transitionToken); + mKnownTransitions.put(transitionToken, active); WindowContainerTransaction wct = null; // If we have sleep, we use a special handler and we try to finish everything ASAP. @@ -1182,7 +1169,6 @@ public class Transitions implements RemoteCallable<Transitions>, wct.setBounds(request.getTriggerTask().token, null); } mOrganizer.startTransition(transitionToken, wct != null && wct.isEmpty() ? null : wct); - active.mToken = transitionToken; // Currently, WMCore only does one transition at a time. If it makes a requestStart, it // is already collecting that transition on core-side, so it will be the next one to // become ready. There may already be pending transitions added as part of direct @@ -1201,9 +1187,10 @@ public class Transitions implements RemoteCallable<Transitions>, @NonNull WindowContainerTransaction wct, @Nullable TransitionHandler handler) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Directly starting a new transition " + "type=%d wct=%s handler=%s", type, wct, handler); - final ActiveTransition active = new ActiveTransition(); + final ActiveTransition active = + new ActiveTransition(mOrganizer.startNewTransition(type, wct)); active.mHandler = handler; - active.mToken = mOrganizer.startNewTransition(type, wct); + mKnownTransitions.put(active.mToken, active); mPendingTransitions.add(active); return active.mToken; } @@ -1243,14 +1230,14 @@ public class Transitions implements RemoteCallable<Transitions>, * * This is then repeated until there are no more pending sleep transitions. * - * @param reason The SLEEP transition that triggered this round of finishes. We will continue - * looping round finishing transitions as long as this is still waiting. + * @param reason The token for the SLEEP transition that triggered this round of finishes. + * We will continue looping round finishing transitions until this is ready. * @param forceFinish When non-null, this is the transition that we last sent the SLEEP merge * signal to -- so it will be force-finished if it's still running. */ - private void finishForSync(ActiveTransition reason, + private void finishForSync(IBinder reason, int trackIdx, @Nullable ActiveTransition forceFinish) { - if (getKnownTransition(reason.mToken) == null) { + if (!mKnownTransitions.containsKey(reason)) { Log.d(TAG, "finishForSleep: already played sync transition " + reason); return; } @@ -1270,7 +1257,7 @@ public class Transitions implements RemoteCallable<Transitions>, forceFinish.mHandler.onTransitionConsumed( forceFinish.mToken, true /* aborted */, null /* finishTransaction */); } - onFinish(forceFinish, null); + onFinish(forceFinish.mToken, null); } } if (track.isIdle() || mReadyDuringSync.isEmpty()) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index d4524282afa2..eeb3662dd45a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -439,7 +439,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } else if (id == R.id.caption_handle || id == R.id.open_menu_button) { if (!decoration.isHandleMenuActive()) { moveTaskToFront(decoration.mTaskInfo); - decoration.createHandleMenu(); + decoration.createHandleMenu(mSplitScreenController); } else { decoration.closeHandleMenu(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index 644fd4ba5a54..a4ade1b676ec 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -68,6 +68,7 @@ import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.shared.DesktopModeStatus; +import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.windowdecor.extension.TaskInfoKt; import com.android.wm.shell.windowdecor.viewholder.AppHandleViewHolder; import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder; @@ -385,7 +386,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin // Should match the density of the task. The task may have had its density overridden // to be different that SysUI's. windowDecorConfig.setTo(taskInfo.configuration); - } else if (DesktopModeStatus.isDesktopDensityOverrideSet()) { + } else if (DesktopModeStatus.useDesktopOverrideDensity()) { // The task has had its density overridden, but keep using the system's density to // layout the header. windowDecorConfig.setTo(context.getResources().getConfiguration()); @@ -515,8 +516,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin private void createResizeVeilIfNeeded() { if (mResizeVeil != null) return; loadAppInfoIfNeeded(); - mResizeVeil = new ResizeVeil(mContext, mDisplayController, mResizeVeilBitmap, mTaskInfo, - mTaskSurface, mSurfaceControlTransactionSupplier); + mResizeVeil = new ResizeVeil(mContext, mDisplayController, mResizeVeilBitmap, + mTaskSurface, mSurfaceControlTransactionSupplier, mTaskInfo); } /** @@ -524,7 +525,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin */ public void showResizeVeil(Rect taskBounds) { createResizeVeilIfNeeded(); - mResizeVeil.showVeil(mTaskSurface, taskBounds); + mResizeVeil.showVeil(mTaskSurface, taskBounds, mTaskInfo); } /** @@ -532,7 +533,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin */ public void showResizeVeil(SurfaceControl.Transaction tx, Rect taskBounds) { createResizeVeilIfNeeded(); - mResizeVeil.showVeil(tx, mTaskSurface, taskBounds, false /* fadeIn */); + mResizeVeil.showVeil(tx, mTaskSurface, taskBounds, mTaskInfo, false /* fadeIn */); } /** @@ -650,7 +651,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin /** * Create and display handle menu window. */ - void createHandleMenu() { + void createHandleMenu(SplitScreenController splitScreenController) { loadAppInfoIfNeeded(); mHandleMenu = new HandleMenu.Builder(this) .setAppIcon(mAppIconBitmap) @@ -660,6 +661,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin .setLayoutId(mRelayoutParams.mLayoutResId) .setWindowingButtonsVisible(DesktopModeStatus.canEnterDesktopMode(mContext)) .setCaptionHeight(mResult.mCaptionHeight) + .setDisplayController(mDisplayController) + .setSplitScreenController(splitScreenController) .build(); mWindowDecorViewHolder.onHandleMenuOpened(); mHandleMenu.show(); @@ -815,11 +818,15 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin // We want handle to remain pressed if the pointer moves outside of it during a drag. handle.setPressed((inHandle && action == ACTION_DOWN) || (handle.isPressed() && action != ACTION_UP && action != ACTION_CANCEL)); - if (isHandleMenuActive()) { + if (isHandleMenuActive() && !isMenuAboveStatusBar()) { mHandleMenu.checkMotionEvent(ev); } } + private boolean isMenuAboveStatusBar() { + return Flags.enableAdditionalWindowsAboveStatusBar() && !mTaskInfo.isFreeform(); + } + private boolean pointInView(View v, float x, float y) { return v != null && v.getLeft() <= x && v.getRight() >= x && v.getTop() <= y && v.getBottom() >= y; @@ -868,6 +875,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin return exclusionRegion; } + int getCaptionX() { + return mResult.mCaptionX; + } + @Override int getCaptionHeightId(@WindowingMode int windowingMode) { return getCaptionHeightIdStatic(windowingMode); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java index badce6e93d67..635f96be3d70 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java @@ -285,6 +285,9 @@ class DragResizeInputListener implements AutoCloseable { private boolean mShouldHandleEvents; private int mLastCursorType = PointerIcon.TYPE_DEFAULT; private Rect mDragStartTaskBounds; + // The id of the particular pointer in a MotionEvent that we are listening to for drag + // resize events. For example, if multiple fingers are touching the screen, then each one + // has a separate pointer id, but we only accept drag input from one. private int mDragPointerId = -1; private TaskResizeInputEventReceiver(@NonNull Context context, @@ -395,6 +398,8 @@ class DragResizeInputListener implements AutoCloseable { mShouldHandleEvents = mDragResizeWindowGeometry.shouldHandleEvent(e, isTouch, new Point() /* offset */); if (mShouldHandleEvents) { + // Save the id of the pointer for this drag interaction; we will use the + // same pointer for all subsequent MotionEvents in this interaction. mDragPointerId = e.getPointerId(0); float x = e.getX(0); float y = e.getY(0); @@ -420,9 +425,16 @@ class DragResizeInputListener implements AutoCloseable { break; } mInputManager.pilferPointers(mInputChannel.getToken()); - int dragPointerIndex = e.findPointerIndex(mDragPointerId); - float rawX = e.getRawX(dragPointerIndex); - float rawY = e.getRawY(dragPointerIndex); + final int dragPointerIndex = e.findPointerIndex(mDragPointerId); + if (dragPointerIndex < 0) { + ProtoLog.d(WM_SHELL_DESKTOP_MODE, + "%s: Handling action move, but ignore event due to invalid " + + "pointer index", + TAG); + break; + } + final float rawX = e.getRawX(dragPointerIndex); + final float rawY = e.getRawY(dragPointerIndex); final Rect taskBounds = mCallback.onDragPositioningMove(rawX, rawY); updateInputSinkRegionForDrag(taskBounds); result = true; @@ -431,7 +443,14 @@ class DragResizeInputListener implements AutoCloseable { case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { if (mShouldHandleEvents) { - int dragPointerIndex = e.findPointerIndex(mDragPointerId); + final int dragPointerIndex = e.findPointerIndex(mDragPointerId); + if (dragPointerIndex < 0) { + ProtoLog.d(WM_SHELL_DESKTOP_MODE, + "%s: Handling action %d, but ignore event due to invalid " + + "pointer index", + TAG, e.getActionMasked()); + break; + } final Rect taskBounds = mCallback.onDragPositioningEnd( e.getRawX(dragPointerIndex), e.getRawY(dragPointerIndex)); // If taskBounds has changed, setGeometry will be called and update the diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java index c22b621f2111..bfc4e0dbb8b6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java @@ -23,6 +23,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_UP; +import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager.RunningTaskInfo; @@ -34,6 +36,7 @@ import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.PointF; +import android.graphics.Rect; import android.view.MotionEvent; import android.view.SurfaceControl; import android.view.View; @@ -42,7 +45,15 @@ import android.widget.ImageView; import android.widget.TextView; import android.window.SurfaceSyncGroup; +import androidx.annotation.VisibleForTesting; + +import com.android.window.flags.Flags; import com.android.wm.shell.R; +import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.splitscreen.SplitScreenController; +import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer; +import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer; /** * Handle menu opened when the appropriate button is clicked on. @@ -56,15 +67,19 @@ class HandleMenu { private static final String TAG = "HandleMenu"; private static final boolean SHOULD_SHOW_MORE_ACTIONS_PILL = false; private final Context mContext; - private final WindowDecoration mParentDecor; - private WindowDecoration.AdditionalWindow mHandleMenuWindow; - private final PointF mHandleMenuPosition = new PointF(); + private final DesktopModeWindowDecoration mParentDecor; + @VisibleForTesting + AdditionalViewContainer mHandleMenuViewContainer; + @VisibleForTesting + final PointF mHandleMenuPosition = new PointF(); private final boolean mShouldShowWindowingPill; private final Bitmap mAppIconBitmap; private final CharSequence mAppName; private final View.OnClickListener mOnClickListener; private final View.OnTouchListener mOnTouchListener; private final RunningTaskInfo mTaskInfo; + private final DisplayController mDisplayController; + private final SplitScreenController mSplitScreenController; private final int mLayoutResId; private int mMarginMenuTop; private int mMarginMenuStart; @@ -74,12 +89,16 @@ class HandleMenu { private HandleMenuAnimator mHandleMenuAnimator; - HandleMenu(WindowDecoration parentDecor, int layoutResId, View.OnClickListener onClickListener, - View.OnTouchListener onTouchListener, Bitmap appIcon, CharSequence appName, - boolean shouldShowWindowingPill, int captionHeight) { + HandleMenu(DesktopModeWindowDecoration parentDecor, int layoutResId, + View.OnClickListener onClickListener, View.OnTouchListener onTouchListener, + Bitmap appIcon, CharSequence appName, DisplayController displayController, + SplitScreenController splitScreenController, boolean shouldShowWindowingPill, + int captionHeight) { mParentDecor = parentDecor; mContext = mParentDecor.mDecorWindowContext; mTaskInfo = mParentDecor.mTaskInfo; + mDisplayController = displayController; + mSplitScreenController = splitScreenController; mLayoutResId = layoutResId; mOnClickListener = onClickListener; mOnTouchListener = onTouchListener; @@ -95,20 +114,27 @@ class HandleMenu { final SurfaceSyncGroup ssg = new SurfaceSyncGroup(TAG); SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - createHandleMenuWindow(t, ssg); + createHandleMenuViewContainer(t, ssg); ssg.addTransaction(t); ssg.markSyncReady(); setupHandleMenu(); animateHandleMenu(); } - private void createHandleMenuWindow(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) { + private void createHandleMenuViewContainer(SurfaceControl.Transaction t, + SurfaceSyncGroup ssg) { final int x = (int) mHandleMenuPosition.x; final int y = (int) mHandleMenuPosition.y; - mHandleMenuWindow = mParentDecor.addWindow( - R.layout.desktop_mode_window_decor_handle_menu, "Handle Menu", - t, ssg, x, y, mMenuWidth, mMenuHeight); - final View handleMenuView = mHandleMenuWindow.mWindowViewHost.getView(); + if (!mTaskInfo.isFreeform() && Flags.enableAdditionalWindowsAboveStatusBar()) { + mHandleMenuViewContainer = new AdditionalSystemViewContainer(mContext, + R.layout.desktop_mode_window_decor_handle_menu, mTaskInfo.taskId, + x, y, mMenuWidth, mMenuHeight); + } else { + mHandleMenuViewContainer = mParentDecor.addWindow( + R.layout.desktop_mode_window_decor_handle_menu, "Handle Menu", + t, ssg, x, y, mMenuWidth, mMenuHeight); + } + final View handleMenuView = mHandleMenuViewContainer.getView(); mHandleMenuAnimator = new HandleMenuAnimator(handleMenuView, mMenuWidth, mCaptionHeight); } @@ -129,7 +155,7 @@ class HandleMenu { * pill. */ private void setupHandleMenu() { - final View handleMenu = mHandleMenuWindow.mWindowViewHost.getView(); + final View handleMenu = mHandleMenuViewContainer.getView(); handleMenu.setOnTouchListener(mOnTouchListener); setupAppInfoPill(handleMenu); if (mShouldShowWindowingPill) { @@ -147,6 +173,7 @@ class HandleMenu { final ImageView appIcon = handleMenu.findViewById(R.id.application_icon); final TextView appName = handleMenu.findViewById(R.id.application_name); collapseBtn.setOnClickListener(mOnClickListener); + collapseBtn.setTaskInfo(mTaskInfo); appIcon.setImageBitmap(mAppIconBitmap); appName.setText(mAppName); } @@ -215,32 +242,55 @@ class HandleMenu { * Updates handle menu's position variables to reflect its next position. */ private void updateHandleMenuPillPositions() { - final int menuX, menuY; - final int captionWidth = mTaskInfo.getConfiguration() - .windowConfiguration.getBounds().width(); + int menuX; + final int menuY; if (mLayoutResId == R.layout.desktop_mode_app_header) { - // Align the handle menu to the left of the caption. + // Align the handle menu to the left side of the caption. menuX = mMarginMenuStart; menuY = mMarginMenuTop; } else { - // Position the handle menu at the center of the caption. - menuX = (captionWidth / 2) - (mMenuWidth / 2); - menuY = mMarginMenuStart; + final int handleWidth = loadDimensionPixelSize(mContext.getResources(), + R.dimen.desktop_mode_fullscreen_decor_caption_width); + final int handleOffset = (mMenuWidth / 2) - (handleWidth / 2); + final int captionX = mParentDecor.getCaptionX(); + // TODO(b/343561161): This needs to be calculated differently if the task is in + // top/bottom split. + if (Flags.enableAdditionalWindowsAboveStatusBar()) { + final Rect leftOrTopStageBounds = new Rect(); + if (mSplitScreenController.getSplitPosition(mTaskInfo.taskId) + == SPLIT_POSITION_BOTTOM_OR_RIGHT) { + mSplitScreenController.getStageBounds(leftOrTopStageBounds, new Rect()); + } + // In a focused decor, we use global coordinates for handle menu. Therefore we + // need to account for other factors like split stage and menu/handle width to + // center the menu. + final DisplayLayout layout = mDisplayController + .getDisplayLayout(mTaskInfo.displayId); + menuX = captionX + handleOffset - (layout.width() / 2); + if (mSplitScreenController.getSplitPosition(mTaskInfo.taskId) + == SPLIT_POSITION_BOTTOM_OR_RIGHT && layout.isLandscape()) { + // If this task in the right stage, we need to offset by left stage's width + menuX += leftOrTopStageBounds.width(); + } + menuY = mMarginMenuStart - ((layout.height() - mMenuHeight) / 2); + } else { + final int captionWidth = mTaskInfo.getConfiguration() + .windowConfiguration.getBounds().width(); + menuX = (captionWidth / 2) - (mMenuWidth / 2); + menuY = mMarginMenuTop; + } } - // Handle Menu position setup. mHandleMenuPosition.set(menuX, menuY); - } /** * Update pill layout, in case task changes have caused positioning to change. */ void relayout(SurfaceControl.Transaction t) { - if (mHandleMenuWindow != null) { + if (mHandleMenuViewContainer != null) { updateHandleMenuPillPositions(); - t.setPosition(mHandleMenuWindow.mWindowSurface, - mHandleMenuPosition.x, mHandleMenuPosition.y); + mHandleMenuViewContainer.setPosition(t, mHandleMenuPosition.x, mHandleMenuPosition.y); } } @@ -252,7 +302,7 @@ class HandleMenu { * @param ev the MotionEvent to compare against. */ void checkMotionEvent(MotionEvent ev) { - final View handleMenu = mHandleMenuWindow.mWindowViewHost.getView(); + final View handleMenu = mHandleMenuViewContainer.getView(); final HandleMenuImageButton collapse = handleMenu.findViewById(R.id.collapse_menu_button); final PointF inputPoint = translateInputToLocalSpace(ev); final boolean inputInCollapseButton = pointInView(collapse, inputPoint.x, inputPoint.y); @@ -280,7 +330,7 @@ class HandleMenu { boolean isValidMenuInput(PointF inputPoint) { if (!viewsLaidOut()) return true; return pointInView( - mHandleMenuWindow.mWindowViewHost.getView(), + mHandleMenuViewContainer.getView(), inputPoint.x - mHandleMenuPosition.x, inputPoint.y - mHandleMenuPosition.y); } @@ -294,7 +344,7 @@ class HandleMenu { * Check if the views for handle menu can be seen. */ private boolean viewsLaidOut() { - return mHandleMenuWindow.mWindowViewHost.getView().isLaidOut(); + return mHandleMenuViewContainer.getView().isLaidOut(); } private void loadHandleMenuDimensions() { @@ -333,8 +383,8 @@ class HandleMenu { void close() { final Runnable after = () -> { - mHandleMenuWindow.releaseView(); - mHandleMenuWindow = null; + mHandleMenuViewContainer.releaseView(); + mHandleMenuViewContainer = null; }; if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN || mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) { @@ -345,7 +395,7 @@ class HandleMenu { } static final class Builder { - private final WindowDecoration mParent; + private final DesktopModeWindowDecoration mParent; private CharSequence mName; private Bitmap mAppIcon; private View.OnClickListener mOnClickListener; @@ -353,9 +403,10 @@ class HandleMenu { private int mLayoutId; private boolean mShowWindowingPill; private int mCaptionHeight; + private DisplayController mDisplayController; + private SplitScreenController mSplitScreenController; - - Builder(@NonNull WindowDecoration parent) { + Builder(@NonNull DesktopModeWindowDecoration parent) { mParent = parent; } @@ -394,9 +445,20 @@ class HandleMenu { return this; } + Builder setDisplayController(DisplayController displayController) { + mDisplayController = displayController; + return this; + } + + Builder setSplitScreenController(SplitScreenController splitScreenController) { + mSplitScreenController = splitScreenController; + return this; + } + HandleMenu build() { - return new HandleMenu(mParent, mLayoutId, mOnClickListener, mOnTouchListener, - mAppIcon, mName, mShowWindowingPill, mCaptionHeight); + return new HandleMenu(mParent, mLayoutId, mOnClickListener, + mOnTouchListener, mAppIcon, mName, mDisplayController, mSplitScreenController, + mShowWindowingPill, mCaptionHeight); } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuImageButton.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuImageButton.kt index 7898567b70e9..18757ef6ff40 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuImageButton.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuImageButton.kt @@ -15,6 +15,10 @@ */ package com.android.wm.shell.windowdecor +import android.app.ActivityManager.RunningTaskInfo +import com.android.window.flags.Flags +import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer + import android.content.Context import android.util.AttributeSet import android.view.MotionEvent @@ -25,10 +29,20 @@ import android.widget.ImageButton * This is due to the hover events being handled by [DesktopModeWindowDecorViewModel] * in order to take the status bar layer into account. Handling it in both classes results in a * flicker when the hover moves from outside to inside status bar layer. + * TODO(b/342229481): Remove this and all uses of it once [AdditionalSystemViewContainer] is no longer + * guarded by a flag. */ -class HandleMenuImageButton(context: Context?, attrs: AttributeSet?) : - ImageButton(context, attrs) { +class HandleMenuImageButton( + context: Context?, + attrs: AttributeSet? +) : ImageButton(context, attrs) { + lateinit var taskInfo: RunningTaskInfo + override fun onHoverEvent(motionEvent: MotionEvent): Boolean { - return false + if (Flags.enableAdditionalWindowsAboveStatusBar() || taskInfo.isFreeform) { + return super.onHoverEvent(motionEvent) + } else { + return false + } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt index 22f0adc42f5d..c903d3b2a858 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt @@ -50,7 +50,7 @@ import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.animation.Interpolators.EMPHASIZED_DECELERATE import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.SyncTransactionQueue -import com.android.wm.shell.windowdecor.WindowDecoration.AdditionalWindow +import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer import java.util.function.Supplier @@ -70,7 +70,7 @@ class MaximizeMenu( private val menuPosition: PointF, private val transactionSupplier: Supplier<Transaction> = Supplier { Transaction() } ) { - private var maximizeMenu: AdditionalWindow? = null + private var maximizeMenu: AdditionalViewHostViewContainer? = null private lateinit var viewHost: SurfaceControlViewHost private lateinit var leash: SurfaceControl private val openMenuAnimatorSet = AnimatorSet() @@ -145,7 +145,8 @@ class MaximizeMenu( .setPosition(leash, menuPosition.x, menuPosition.y) .setCornerRadius(leash, cornerRadius) .show(leash) - maximizeMenu = AdditionalWindow(leash, viewHost, transactionSupplier) + maximizeMenu = + AdditionalViewHostViewContainer(leash, viewHost, transactionSupplier) syncQueue.runInSync { transaction -> transaction.merge(t) @@ -154,8 +155,7 @@ class MaximizeMenu( } private fun animateOpenMenu() { - val viewHost = maximizeMenu?.mWindowViewHost - val maximizeMenuView = viewHost?.view ?: return + val maximizeMenuView = maximizeMenu?.view ?: return val maximizeWindowText = maximizeMenuView.requireViewById<TextView>( R.id.maximize_menu_maximize_window_text) val snapWindowText = maximizeMenuView.requireViewById<TextView>( @@ -233,7 +233,7 @@ class MaximizeMenu( } private fun setupMaximizeMenu() { - val maximizeMenuView = maximizeMenu?.mWindowViewHost?.view ?: return + val maximizeMenuView = maximizeMenu?.view ?: return maximizeMenuView.setOnGenericMotionListener(onGenericMotionListener) maximizeMenuView.setOnTouchListener(onTouchListener) @@ -275,7 +275,7 @@ class MaximizeMenu( * Check if the views for maximize menu can be seen. */ private fun viewsLaidOut(): Boolean { - return maximizeMenu?.mWindowViewHost?.view?.isLaidOut ?: false + return maximizeMenu?.view?.isLaidOut ?: false } fun onMaximizeMenuHoverEnter(viewId: Int, ev: MotionEvent) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.kt index 4f2d945e49f9..cd2dac806a7f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.kt @@ -20,7 +20,6 @@ import android.animation.AnimatorListenerAdapter import android.animation.ValueAnimator import android.app.ActivityManager.RunningTaskInfo import android.content.Context -import android.content.res.Configuration import android.graphics.Bitmap import android.graphics.Color import android.graphics.PixelFormat @@ -36,10 +35,15 @@ import android.view.WindowManager import android.view.WindowlessWindowManager import android.widget.ImageView import android.window.TaskConstants +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.ui.graphics.toArgb import com.android.wm.shell.R import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayController.OnDisplaysChangedListener import com.android.wm.shell.windowdecor.WindowDecoration.SurfaceControlViewHostFactory +import com.android.wm.shell.windowdecor.common.DecorThemeUtil +import com.android.wm.shell.windowdecor.common.Theme import java.util.function.Supplier /** @@ -49,14 +53,18 @@ class ResizeVeil @JvmOverloads constructor( private val context: Context, private val displayController: DisplayController, private val appIcon: Bitmap, - private val taskInfo: RunningTaskInfo, private var parentSurface: SurfaceControl, private val surfaceControlTransactionSupplier: Supplier<SurfaceControl.Transaction>, private val surfaceControlBuilderFactory: SurfaceControlBuilderFactory = object : SurfaceControlBuilderFactory {}, private val surfaceControlViewHostFactory: SurfaceControlViewHostFactory = - object : SurfaceControlViewHostFactory {} + object : SurfaceControlViewHostFactory {}, + taskInfo: RunningTaskInfo, ) { + private val decorThemeUtil = DecorThemeUtil(context) + private val lightColors = dynamicLightColorScheme(context) + private val darkColors = dynamicDarkColorScheme(context) + private val surfaceSession = SurfaceSession() private lateinit var iconView: ImageView private var iconSize = 0 @@ -86,21 +94,10 @@ class ResizeVeil @JvmOverloads constructor( return } displayController.removeDisplayWindowListener(this) - setupResizeVeil() + setupResizeVeil(taskInfo) } } - private val backgroundColorId: Int - get() { - val configuration = context.resources.configuration - return if (configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK - == Configuration.UI_MODE_NIGHT_YES) { - R.color.desktop_mode_resize_veil_dark - } else { - R.color.desktop_mode_resize_veil_light - } - } - /** * Whether the resize veil is ready to be shown. */ @@ -108,14 +105,14 @@ class ResizeVeil @JvmOverloads constructor( get() = viewHost != null init { - setupResizeVeil() + setupResizeVeil(taskInfo) } /** * Create the veil in its default invisible state. */ - private fun setupResizeVeil() { - if (!obtainDisplayOrRegisterListener()) { + private fun setupResizeVeil(taskInfo: RunningTaskInfo) { + if (!obtainDisplayOrRegisterListener(taskInfo.displayId)) { // Display may not be available yet, skip this until then. return } @@ -162,8 +159,8 @@ class ResizeVeil @JvmOverloads constructor( Trace.endSection() } - private fun obtainDisplayOrRegisterListener(): Boolean { - display = displayController.getDisplay(taskInfo.displayId) + private fun obtainDisplayOrRegisterListener(displayId: Int): Boolean { + display = displayController.getDisplay(displayId) if (display == null) { displayController.addDisplayWindowListener(onDisplaysChangedListener) return false @@ -184,7 +181,8 @@ class ResizeVeil @JvmOverloads constructor( t: SurfaceControl.Transaction, parent: SurfaceControl, taskBounds: Rect, - fadeIn: Boolean + taskInfo: RunningTaskInfo, + fadeIn: Boolean, ) { if (!isReady || isVisible) { t.apply() @@ -202,13 +200,15 @@ class ResizeVeil @JvmOverloads constructor( parentSurface = parent } - + val backgroundColor = when (decorThemeUtil.getAppTheme(taskInfo)) { + Theme.LIGHT -> lightColors.surfaceContainer + Theme.DARK -> darkColors.surfaceContainer + } t.show(veil) .setLayer(veil, VEIL_CONTAINER_LAYER) .setLayer(icon, VEIL_ICON_LAYER) .setLayer(background, VEIL_BACKGROUND_LAYER) - .setColor(background, - Color.valueOf(context.getColor(backgroundColorId)).components) + .setColor(background, Color.valueOf(backgroundColor.toArgb()).components) relayout(taskBounds, t) if (fadeIn) { cancelAnimation() @@ -270,12 +270,12 @@ class ResizeVeil @JvmOverloads constructor( /** * Animate veil's alpha to 1, fading it in. */ - fun showVeil(parentSurface: SurfaceControl, taskBounds: Rect) { + fun showVeil(parentSurface: SurfaceControl, taskBounds: Rect, taskInfo: RunningTaskInfo) { if (!isReady || isVisible) { return } val t = surfaceControlTransactionSupplier.get() - showVeil(t, parentSurface, taskBounds, true /* fadeIn */) + showVeil(t, parentSurface, taskBounds, taskInfo, true /* fadeIn */) } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java index 2ae3cb9ef3c0..a08f97cde06f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java @@ -22,6 +22,7 @@ import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED; import static android.view.WindowInsets.Type.captionBar; import static android.view.WindowInsets.Type.mandatorySystemGestures; import static android.view.WindowInsets.Type.statusBars; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import android.annotation.NonNull; import android.annotation.Nullable; @@ -56,6 +57,7 @@ import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.shared.DesktopModeStatus; import com.android.wm.shell.windowdecor.WindowDecoration.RelayoutParams.OccludingCaptionElement; +import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer; import java.util.ArrayList; import java.util.Arrays; @@ -402,7 +404,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> mCaptionWindowManager.setConfiguration(taskConfig); final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(outResult.mCaptionWidth, outResult.mCaptionHeight, - WindowManager.LayoutParams.TYPE_APPLICATION, + TYPE_APPLICATION, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT); lp.setTitle("Caption of Task=" + mTaskInfo.taskId); lp.setTrustedOverlay(); @@ -569,10 +571,11 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> * @param yPos y position of new window * @param width width of new window * @param height height of new window - * @return the {@link AdditionalWindow} that was added. + * @return the {@link AdditionalViewHostViewContainer} that was added. */ - AdditionalWindow addWindow(int layoutId, String namePrefix, SurfaceControl.Transaction t, - SurfaceSyncGroup ssg, int xPos, int yPos, int width, int height) { + AdditionalViewHostViewContainer addWindow(int layoutId, String namePrefix, + SurfaceControl.Transaction t, SurfaceSyncGroup ssg, int xPos, int yPos, + int width, int height) { final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get(); SurfaceControl windowSurfaceControl = builder .setName(namePrefix + " of Task=" + mTaskInfo.taskId) @@ -586,9 +589,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .setWindowCrop(windowSurfaceControl, width, height) .show(windowSurfaceControl); final WindowManager.LayoutParams lp = - new WindowManager.LayoutParams(width, height, - WindowManager.LayoutParams.TYPE_APPLICATION, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT); + new WindowManager.LayoutParams(width, height, TYPE_APPLICATION, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + PixelFormat.TRANSPARENT); lp.setTitle("Additional window of Task=" + mTaskInfo.taskId); lp.setTrustedOverlay(); WindowlessWindowManager windowManager = new WindowlessWindowManager(mTaskInfo.configuration, @@ -596,7 +599,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> SurfaceControlViewHost viewHost = mSurfaceControlViewHostFactory .create(mDecorWindowContext, mDisplay, windowManager); ssg.add(viewHost.getSurfacePackage(), () -> viewHost.setView(v, lp)); - return new AdditionalWindow(windowSurfaceControl, viewHost, + return new AdditionalViewHostViewContainer(windowSurfaceControl, viewHost, mSurfaceControlTransactionSupplier); } @@ -739,41 +742,4 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> return Objects.hash(mToken, mOwner, mFrame, Arrays.hashCode(mBoundingRects)); } } - - /** - * Subclass for additional windows associated with this WindowDecoration - */ - static class AdditionalWindow { - SurfaceControl mWindowSurface; - SurfaceControlViewHost mWindowViewHost; - Supplier<SurfaceControl.Transaction> mTransactionSupplier; - - AdditionalWindow(SurfaceControl surfaceControl, - SurfaceControlViewHost surfaceControlViewHost, - Supplier<SurfaceControl.Transaction> transactionSupplier) { - mWindowSurface = surfaceControl; - mWindowViewHost = surfaceControlViewHost; - mTransactionSupplier = transactionSupplier; - } - - void releaseView() { - WindowlessWindowManager windowManager = mWindowViewHost.getWindowlessWM(); - - if (mWindowViewHost != null) { - mWindowViewHost.release(); - mWindowViewHost = null; - } - windowManager = null; - final SurfaceControl.Transaction t = mTransactionSupplier.get(); - boolean released = false; - if (mWindowSurface != null) { - t.remove(mWindowSurface); - mWindowSurface = null; - released = true; - } - if (released) { - t.apply(); - } - } - } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalSystemViewContainer.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalSystemViewContainer.kt new file mode 100644 index 000000000000..6c2c8fd46bc9 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalSystemViewContainer.kt @@ -0,0 +1,66 @@ +/* + * 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.wm.shell.windowdecor.additionalviewcontainer + +import android.content.Context +import android.graphics.PixelFormat +import android.view.LayoutInflater +import android.view.SurfaceControl +import android.view.View +import android.view.WindowManager + +/** + * An [AdditionalViewContainer] that uses the system [WindowManager] instance. Intended + * for view containers that should be above the status bar layer. + */ +class AdditionalSystemViewContainer( + private val context: Context, + layoutId: Int, + taskId: Int, + x: Int, + y: Int, + width: Int, + height: Int +) : AdditionalViewContainer() { + override val view: View + + init { + view = LayoutInflater.from(context).inflate(layoutId, null) + val lp = WindowManager.LayoutParams( + width, height, x, y, + WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + PixelFormat.TRANSPARENT + ) + lp.title = "Additional view container of Task=$taskId" + lp.setTrustedOverlay() + val wm: WindowManager? = context.getSystemService(WindowManager::class.java) + wm?.addView(view, lp) + } + + override fun releaseView() { + context.getSystemService(WindowManager::class.java)?.removeViewImmediate(view) + } + + override fun setPosition(t: SurfaceControl.Transaction, x: Float, y: Float) { + val lp = (view.layoutParams as WindowManager.LayoutParams).apply { + this.x = x.toInt() + this.y = y.toInt() + } + view.layoutParams = lp + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalViewContainer.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalViewContainer.kt new file mode 100644 index 000000000000..2650648a2cde --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalViewContainer.kt @@ -0,0 +1,35 @@ +/* + * 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.wm.shell.windowdecor.additionalviewcontainer + +import android.view.SurfaceControl +import android.view.View +import com.android.wm.shell.windowdecor.WindowDecoration + +/** + * Class for additional view containers associated with a [WindowDecoration]. + */ +abstract class AdditionalViewContainer internal constructor( +) { + abstract val view: View? + + /** Release the view associated with this container and perform needed cleanup. */ + abstract fun releaseView() + + /** Reposition the view container using provided coordinates. */ + abstract fun setPosition(t: SurfaceControl.Transaction, x: Float, y: Float) +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalViewHostViewContainer.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalViewHostViewContainer.kt new file mode 100644 index 000000000000..222761260289 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalViewHostViewContainer.kt @@ -0,0 +1,46 @@ +/* + * 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.wm.shell.windowdecor.additionalviewcontainer + +import android.view.SurfaceControl +import android.view.SurfaceControlViewHost +import java.util.function.Supplier + +/** + * An [AdditionalViewContainer] that uses a [SurfaceControlViewHost] to show the window. + * Intended for view containers in freeform tasks that do not extend beyond task bounds. + */ +class AdditionalViewHostViewContainer( + private val windowSurface: SurfaceControl, + private val windowViewHost: SurfaceControlViewHost, + private val transactionSupplier: Supplier<SurfaceControl.Transaction>, +) : AdditionalViewContainer() { + + override val view + get() = windowViewHost.view + + override fun releaseView() { + windowViewHost.release() + val t = transactionSupplier.get() + t.remove(windowSurface) + t.apply() + } + + override fun setPosition(t: SurfaceControl.Transaction, x: Float, y: Float) { + t.setPosition(windowSurface, x, y) + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java index 8932e60048e6..4d0348b4f470 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java @@ -19,6 +19,7 @@ package com.android.wm.shell.back; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import android.os.Handler; import android.os.Looper; @@ -95,16 +96,33 @@ public class BackProgressAnimatorTest { // Trigger animation cancel, the target progress should be 0. mTargetProgress = 0; mTargetProgressCalled = new CountDownLatch(1); - CountDownLatch cancelCallbackCalled = new CountDownLatch(1); + CountDownLatch finishCallbackCalled = new CountDownLatch(1); mMainThreadHandler.post( - () -> mProgressAnimator.onBackCancelled(() -> cancelCallbackCalled.countDown())); - cancelCallbackCalled.await(1, TimeUnit.SECONDS); + () -> mProgressAnimator.onBackCancelled(finishCallbackCalled::countDown)); + finishCallbackCalled.await(1, TimeUnit.SECONDS); mTargetProgressCalled.await(1, TimeUnit.SECONDS); assertNotNull(mReceivedBackEvent); assertEquals(mReceivedBackEvent.getProgress(), mTargetProgress, 0 /* delta */); } @Test + public void testBackInvoked() throws InterruptedException { + // Give the animator some progress. + final BackMotionEvent backEvent = backMotionEventFrom(100, mTargetProgress); + mMainThreadHandler.post( + () -> mProgressAnimator.onBackProgressed(backEvent)); + mTargetProgressCalled.await(1, TimeUnit.SECONDS); + assertNotNull(mReceivedBackEvent); + + // Trigger back invoked animation + CountDownLatch finishCallbackCalled = new CountDownLatch(1); + mMainThreadHandler.post( + () -> mProgressAnimator.onBackInvoked(finishCallbackCalled::countDown)); + assertTrue("onBackInvoked finishCallback never called", + finishCallbackCalled.await(1, TimeUnit.SECONDS)); + } + + @Test public void testResetCallsCancelCallbackImmediately() throws InterruptedException { // Give the animator some progress. final BackMotionEvent backEvent = backMotionEventFrom(100, mTargetProgress); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java index 0f433770777e..f55c96cb1769 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java @@ -1203,6 +1203,25 @@ public class BubbleDataTest extends ShellTestCase { assertThat(update.currentBubbleList.get(0).getKey()).isEqualTo(mEntryA2.getKey()); assertThat(update.currentBubbleList.get(1).getKey()).isEqualTo(mEntryA1.getKey()); assertThat(update.bubbleBarLocation).isEqualTo(BubbleBarLocation.LEFT); + assertThat(update.expandedChanged).isFalse(); + assertThat(update.selectedBubbleKey).isEqualTo(mEntryA2.getKey()); + } + + @Test + public void test_getInitialStateForBubbleBar_includesExpandedState() { + sendUpdatedEntryAtTime(mEntryA1, 1000); + sendUpdatedEntryAtTime(mEntryA2, 2000); + mPositioner.setBubbleBarLocation(BubbleBarLocation.LEFT); + mBubbleData.setExpanded(true); + + BubbleBarUpdate update = mBubbleData.getInitialStateForBubbleBar(); + assertThat(update.currentBubbleList).hasSize(2); + assertThat(update.currentBubbleList.get(0).getKey()).isEqualTo(mEntryA2.getKey()); + assertThat(update.currentBubbleList.get(1).getKey()).isEqualTo(mEntryA1.getKey()); + assertThat(update.bubbleBarLocation).isEqualTo(BubbleBarLocation.LEFT); + assertThat(update.expandedChanged).isTrue(); + assertThat(update.expanded).isTrue(); + assertThat(update.selectedBubbleKey).isEqualTo(mEntryA2.getKey()); } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/bubbles/BubbleInfoTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/bubbles/BubbleInfoTest.kt index 432909f18813..5b22eddcb6ee 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/bubbles/BubbleInfoTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/bubbles/BubbleInfoTest.kt @@ -32,7 +32,17 @@ class BubbleInfoTest : ShellTestCase() { @Test fun bubbleInfo() { val bubbleInfo = - BubbleInfo("key", 0, "shortcut id", null, 6, "com.some.package", "title", true) + BubbleInfo( + "key", + 0, + "shortcut id", + null, + 6, + "com.some.package", + "title", + "Some app", + true + ) val parcel = Parcel.obtain() bubbleInfo.writeToParcel(parcel, PARCELABLE_WRITE_RETURN_VALUE) parcel.setDataPosition(0) @@ -46,6 +56,7 @@ class BubbleInfoTest : ShellTestCase() { assertThat(bubbleInfo.userId).isEqualTo(bubbleInfoFromParcel.userId) assertThat(bubbleInfo.packageName).isEqualTo(bubbleInfoFromParcel.packageName) assertThat(bubbleInfo.title).isEqualTo(bubbleInfoFromParcel.title) + assertThat(bubbleInfo.appName).isEqualTo(bubbleInfoFromParcel.appName) assertThat(bubbleInfo.isImportantConversation) .isEqualTo(bubbleInfoFromParcel.isImportantConversation) } 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 ae05bf5b9c48..748ad3182393 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 @@ -1114,7 +1114,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test fun handleRequest_freeformTask_alreadyInDesktop_noOverrideDensity_noConfigDensityChange() { assumeTrue(ENABLE_SHELL_TRANSITIONS) - whenever(DesktopModeStatus.isDesktopDensityOverrideSet()).thenReturn(false) + whenever(DesktopModeStatus.useDesktopOverrideDensity()).thenReturn(false) val freeformTask1 = setUpFreeformTask() markTaskVisible(freeformTask1) @@ -1128,7 +1128,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test fun handleRequest_freeformTask_alreadyInDesktop_overrideDensity_hasConfigDensityChange() { assumeTrue(ENABLE_SHELL_TRANSITIONS) - whenever(DesktopModeStatus.isDesktopDensityOverrideSet()).thenReturn(true) + whenever(DesktopModeStatus.useDesktopOverrideDensity()).thenReturn(true) val freeformTask1 = setUpFreeformTask() markTaskVisible(freeformTask1) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java index a731e5394bdf..1b223cf2bd59 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java @@ -22,6 +22,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; import static android.view.WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.any; @@ -54,6 +56,7 @@ import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; +import com.android.dx.mockito.inline.extended.StaticMockitoSession; import com.android.internal.R; import com.android.window.flags.Flags; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; @@ -62,14 +65,17 @@ import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.TestRunningTaskInfoBuilder; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.SyncTransactionQueue; +import com.android.wm.shell.shared.DesktopModeStatus; import com.android.wm.shell.windowdecor.WindowDecoration.RelayoutParams; +import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.quality.Strictness; import java.util.function.Supplier; @@ -118,6 +124,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { private final Configuration mConfiguration = new Configuration(); + private StaticMockitoSession mMockitoSession; private TestableContext mTestableContext; /** Set up run before test class. */ @@ -131,6 +138,11 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { @Before public void setUp() { + mMockitoSession = mockitoSession() + .strictness(Strictness.LENIENT) + .spyStatic(DesktopModeStatus.class) + .startMocking(); + when(DesktopModeStatus.useDesktopOverrideDensity()).thenReturn(false); doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory).create( any(), any(), any()); doReturn(mMockTransaction).when(mMockTransactionSupplier).get(); @@ -138,6 +150,11 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { mTestableContext.ensureTestableResources(); } + @After + public void tearDown() { + mMockitoSession.finishMocking(); + } + @Test public void testMenusClosedWhenTaskIsInvisible() { doReturn(mMockTransaction).when(mMockTransaction).hide(any()); @@ -206,6 +223,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { @Test @DisableFlags(Flags.FLAG_ENABLE_APP_HEADER_WITH_TASK_DENSITY) public void updateRelayoutParams_appHeader_usesSystemDensity() { + when(DesktopModeStatus.useDesktopOverrideDensity()).thenReturn(true); final int systemDensity = mTestableContext.getOrCreateTestableResources().getResources() .getConfiguration().densityDpi; final int customTaskDensity = systemDensity + 300; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt new file mode 100644 index 000000000000..5582e0f46321 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt @@ -0,0 +1,212 @@ +/* + * 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.wm.shell.windowdecor + +import android.app.ActivityManager +import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM +import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN +import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW +import android.graphics.Bitmap +import android.graphics.Color +import android.graphics.Rect +import android.platform.test.annotations.RequiresFlagsEnabled +import android.platform.test.flag.junit.CheckFlagsRule +import android.platform.test.flag.junit.DeviceFlagsValueProvider +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.view.Display +import android.view.LayoutInflater +import android.view.SurfaceControl +import android.view.SurfaceControlViewHost +import android.view.View +import androidx.test.filters.SmallTest +import com.android.window.flags.Flags +import com.android.wm.shell.R +import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.TestRunningTaskInfoBuilder +import com.android.wm.shell.common.DisplayController +import com.android.wm.shell.common.DisplayLayout +import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT +import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT +import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED +import com.android.wm.shell.splitscreen.SplitScreenController +import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer +import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.Mock +import org.mockito.Mockito.mock +import org.mockito.kotlin.any +import org.mockito.kotlin.whenever + +/** + * Tests for [HandleMenu]. + * + * Build/Install/Run: + * atest WMShellUnitTests:HandleMenuTest + */ +@SmallTest +@TestableLooper.RunWithLooper +@RunWith(AndroidTestingRunner::class) +class HandleMenuTest : ShellTestCase() { + @JvmField + @Rule + val mCheckFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + + @Mock + private lateinit var mockDesktopWindowDecoration: DesktopModeWindowDecoration + @Mock + private lateinit var onClickListener: View.OnClickListener + @Mock + private lateinit var onTouchListener: View.OnTouchListener + @Mock + private lateinit var appIcon: Bitmap + @Mock + private lateinit var appName: CharSequence + @Mock + private lateinit var displayController: DisplayController + @Mock + private lateinit var splitScreenController: SplitScreenController + @Mock + private lateinit var displayLayout: DisplayLayout + @Mock + private lateinit var mockSurfaceControlViewHost: SurfaceControlViewHost + + private lateinit var handleMenu: HandleMenu + + @Before + fun setUp() { + val mockAdditionalViewHostViewContainer = AdditionalViewHostViewContainer( + mock(SurfaceControl::class.java), + mockSurfaceControlViewHost, + ) { + SurfaceControl.Transaction() + } + val menuView = LayoutInflater.from(context).inflate( + R.layout.desktop_mode_window_decor_handle_menu, null) + whenever(mockDesktopWindowDecoration.addWindow( + anyInt(), any(), any(), any(), anyInt(), anyInt(), anyInt(), anyInt()) + ).thenReturn(mockAdditionalViewHostViewContainer) + whenever(mockAdditionalViewHostViewContainer.view).thenReturn(menuView) + whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout) + whenever(displayLayout.width()).thenReturn(DISPLAY_BOUNDS.width()) + whenever(displayLayout.height()).thenReturn(DISPLAY_BOUNDS.height()) + whenever(displayLayout.isLandscape).thenReturn(true) + mockDesktopWindowDecoration.mDecorWindowContext = context + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR) + fun testFullscreenMenuUsesSystemViewContainer() { + createTaskInfo(WINDOWING_MODE_FULLSCREEN, SPLIT_POSITION_UNDEFINED) + val handleMenu = createAndShowHandleMenu() + assertTrue(handleMenu.mHandleMenuViewContainer is AdditionalSystemViewContainer) + // Verify menu is created at coordinates that, when added to WindowManager, + // show at the top-center of display. + assertTrue(handleMenu.mHandleMenuPosition.equals(16f, -512f)) + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR) + fun testFreeformMenu_usesViewHostViewContainer() { + createTaskInfo(WINDOWING_MODE_FREEFORM, SPLIT_POSITION_UNDEFINED) + handleMenu = createAndShowHandleMenu() + assertTrue(handleMenu.mHandleMenuViewContainer is AdditionalViewHostViewContainer) + // Verify menu is created near top-left of task. + assertTrue(handleMenu.mHandleMenuPosition.equals(12f, 8f)) + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR) + fun testSplitLeftMenu_usesSystemViewContainer() { + createTaskInfo(WINDOWING_MODE_MULTI_WINDOW, SPLIT_POSITION_TOP_OR_LEFT) + handleMenu = createAndShowHandleMenu() + assertTrue(handleMenu.mHandleMenuViewContainer is AdditionalSystemViewContainer) + // Verify menu is created at coordinates that, when added to WindowManager, + // show at the top of split left task. + assertTrue(handleMenu.mHandleMenuPosition.equals(-624f, -512f)) + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR) + fun testSplitRightMenu_usesSystemViewContainer() { + createTaskInfo(WINDOWING_MODE_MULTI_WINDOW, SPLIT_POSITION_BOTTOM_OR_RIGHT) + handleMenu = createAndShowHandleMenu() + assertTrue(handleMenu.mHandleMenuViewContainer is AdditionalSystemViewContainer) + // Verify menu is created at coordinates that, when added to WindowManager, + // show at the top of split right task. + assertTrue(handleMenu.mHandleMenuPosition.equals(656f, -512f)) + } + + private fun createTaskInfo(windowingMode: Int, splitPosition: Int) { + val taskDescriptionBuilder = ActivityManager.TaskDescription.Builder() + .setBackgroundColor(Color.YELLOW) + val bounds = when (windowingMode) { + WINDOWING_MODE_FULLSCREEN -> DISPLAY_BOUNDS + WINDOWING_MODE_FREEFORM -> FREEFORM_BOUNDS + WINDOWING_MODE_MULTI_WINDOW -> { + if (splitPosition == SPLIT_POSITION_TOP_OR_LEFT) { + SPLIT_LEFT_BOUNDS + } else { + SPLIT_RIGHT_BOUNDS + } + } + else -> error("Unsupported windowing mode") + } + mockDesktopWindowDecoration.mTaskInfo = TestRunningTaskInfoBuilder() + .setDisplayId(Display.DEFAULT_DISPLAY) + .setTaskDescriptionBuilder(taskDescriptionBuilder) + .setWindowingMode(windowingMode) + .setBounds(bounds) + .setVisible(true) + .build() + // Calculate captionX similar to how WindowDecoration calculates it. + whenever(mockDesktopWindowDecoration.captionX).thenReturn( + (mockDesktopWindowDecoration.mTaskInfo.configuration.windowConfiguration + .bounds.width() - context.resources.getDimensionPixelSize( + R.dimen.desktop_mode_fullscreen_decor_caption_width)) / 2) + whenever(splitScreenController.getSplitPosition(any())).thenReturn(splitPosition) + whenever(splitScreenController.getStageBounds(any(), any())).thenAnswer { + (it.arguments.first() as Rect).set(SPLIT_LEFT_BOUNDS) + } + } + + private fun createAndShowHandleMenu(): HandleMenu { + val layoutId = if (mockDesktopWindowDecoration.mTaskInfo.isFreeform) { + R.layout.desktop_mode_app_header + } else { + R.layout.desktop_mode_app_header + } + val handleMenu = HandleMenu(mockDesktopWindowDecoration, layoutId, + onClickListener, onTouchListener, appIcon, appName, displayController, + splitScreenController, true /* shouldShowWindowingPill */, + 50 /* captionHeight */ ) + handleMenu.show() + return handleMenu + } + + companion object { + private val DISPLAY_BOUNDS = Rect(0, 0, 2560, 1600) + private val FREEFORM_BOUNDS = Rect(500, 500, 2000, 1200) + private val SPLIT_LEFT_BOUNDS = Rect(0, 0, 1280, 1600) + private val SPLIT_RIGHT_BOUNDS = Rect(1280, 0, 2560, 1600) + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeVeilTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeVeilTest.kt index 5da57c50e6c1..a07be79579eb 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeVeilTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeVeilTest.kt @@ -150,7 +150,7 @@ class ResizeVeilTest : ShellTestCase() { fun showVeil() { val veil = createResizeVeil() - veil.showVeil(mockTransaction, mock(), Rect(0, 0, 100, 100), false /* fadeIn */) + veil.showVeil(mockTransaction, mock(), Rect(0, 0, 100, 100), taskInfo, false /* fadeIn */) verify(mockTransaction).show(mockResizeVeilSurface) verify(mockTransaction).show(mockBackgroundSurface) @@ -162,7 +162,7 @@ class ResizeVeilTest : ShellTestCase() { fun showVeil_displayUnavailable_doesNotShow() { val veil = createResizeVeil(withDisplayAvailable = false) - veil.showVeil(mockTransaction, mock(), Rect(0, 0, 100, 100), false /* fadeIn */) + veil.showVeil(mockTransaction, mock(), Rect(0, 0, 100, 100), taskInfo, false /* fadeIn */) verify(mockTransaction, never()).show(mockResizeVeilSurface) verify(mockTransaction, never()).show(mockBackgroundSurface) @@ -174,8 +174,8 @@ class ResizeVeilTest : ShellTestCase() { fun showVeil_alreadyVisible_doesNotShowAgain() { val veil = createResizeVeil() - veil.showVeil(mockTransaction, mock(), Rect(0, 0, 100, 100), false /* fadeIn */) - veil.showVeil(mockTransaction, mock(), Rect(0, 0, 100, 100), false /* fadeIn */) + veil.showVeil(mockTransaction, mock(), Rect(0, 0, 100, 100), taskInfo, false /* fadeIn */) + veil.showVeil(mockTransaction, mock(), Rect(0, 0, 100, 100), taskInfo, false /* fadeIn */) verify(mockTransaction, times(1)).show(mockResizeVeilSurface) verify(mockTransaction, times(1)).show(mockBackgroundSurface) @@ -188,7 +188,13 @@ class ResizeVeilTest : ShellTestCase() { val veil = createResizeVeil(parent = mock()) val newParent = mock<SurfaceControl>() - veil.showVeil(mockTransaction, newParent, Rect(0, 0, 100, 100), false /* fadeIn */) + veil.showVeil( + mockTransaction, + newParent, + Rect(0, 0, 100, 100), + taskInfo, + false /* fadeIn */ + ) verify(mockTransaction).reparent(mockResizeVeilSurface, newParent) } @@ -212,11 +218,11 @@ class ResizeVeilTest : ShellTestCase() { context, mockDisplayController, mockAppIcon, - taskInfo, parent, { mockTransaction }, mockSurfaceControlBuilderFactory, - mockSurfaceControlViewHostFactory + mockSurfaceControlViewHostFactory, + taskInfo ) } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java index 48310810e8c9..e73069ab52a7 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java @@ -76,6 +76,7 @@ import com.android.wm.shell.TestRunningTaskInfoBuilder; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.shared.DesktopModeStatus; import com.android.wm.shell.tests.R; +import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer; import org.junit.Before; import org.junit.Test; @@ -371,7 +372,7 @@ public class WindowDecorationTests extends ShellTestCase { } @Test - public void testAddWindow() { + public void testAddViewHostViewContainer() { final Display defaultDisplay = mock(Display.class); doReturn(defaultDisplay).when(mMockDisplayController) .getDisplay(Display.DEFAULT_DISPLAY); @@ -393,6 +394,7 @@ public class WindowDecorationTests extends ShellTestCase { final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder() .setDisplayId(Display.DEFAULT_DISPLAY) .setTaskDescriptionBuilder(taskDescriptionBuilder) + .setWindowingMode(WINDOWING_MODE_FREEFORM) .setBounds(TASK_BOUNDS) .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y) .setVisible(true) @@ -407,7 +409,7 @@ public class WindowDecorationTests extends ShellTestCase { createMockSurfaceControlBuilder(additionalWindowSurface); mMockSurfaceControlBuilders.add(additionalWindowSurfaceBuilder); - WindowDecoration.AdditionalWindow additionalWindow = windowDecor.addTestWindow(); + windowDecor.addTestViewContainer(); verify(additionalWindowSurfaceBuilder).setContainerLayer(); verify(additionalWindowSurfaceBuilder).setParent(decorContainerSurface); @@ -421,12 +423,6 @@ public class WindowDecorationTests extends ShellTestCase { verify(mMockSurfaceControlAddWindowT).show(additionalWindowSurface); verify(mMockSurfaceControlViewHostFactory, Mockito.times(2)) .create(any(), eq(defaultDisplay), any()); - assertThat(additionalWindow.mWindowViewHost).isNotNull(); - - additionalWindow.releaseView(); - - assertThat(additionalWindow.mWindowViewHost).isNull(); - assertThat(additionalWindow.mWindowSurface).isNull(); } @Test @@ -905,16 +901,16 @@ public class WindowDecorationTests extends ShellTestCase { mMockWindowContainerTransaction, mMockView, mRelayoutResult); } - private WindowDecoration.AdditionalWindow addTestWindow() { + private AdditionalViewContainer addTestViewContainer() { final Resources resources = mDecorWindowContext.getResources(); - int width = loadDimensionPixelSize(resources, mCaptionMenuWidthId); - int height = loadDimensionPixelSize(resources, mRelayoutParams.mCaptionHeightId); - String name = "Test Window"; - WindowDecoration.AdditionalWindow additionalWindow = + final int width = loadDimensionPixelSize(resources, mCaptionMenuWidthId); + final int height = loadDimensionPixelSize(resources, mRelayoutParams.mCaptionHeightId); + final String name = "Test Window"; + final AdditionalViewContainer additionalViewContainer = addWindow(R.layout.desktop_mode_window_decor_handle_menu, name, mMockSurfaceControlAddWindowT, mMockSurfaceSyncGroup, 0 /* x */, 0 /* y */, width, height); - return additionalWindow; + return additionalViewContainer; } } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalSystemViewContainerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalSystemViewContainerTest.kt new file mode 100644 index 000000000000..d3e996b12e1f --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalSystemViewContainerTest.kt @@ -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 com.android.wm.shell.windowdecor.additionalviewcontainer + +import android.content.Context +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.view.LayoutInflater +import android.view.View +import android.view.WindowManager +import androidx.test.filters.SmallTest +import com.android.wm.shell.R +import com.android.wm.shell.ShellTestCase +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.kotlin.any +import org.mockito.kotlin.eq +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +/** + * Tests for [AdditionalSystemViewContainer]. + * + * Build/Install/Run: + * atest WMShellUnitTests:AdditionalSystemViewContainerTest + */ +@SmallTest +@TestableLooper.RunWithLooper +@RunWith(AndroidTestingRunner::class) +class AdditionalSystemViewContainerTest : ShellTestCase() { + @Mock + private lateinit var mockView: View + @Mock + private lateinit var mockLayoutInflater: LayoutInflater + @Mock + private lateinit var mockContext: Context + @Mock + private lateinit var mockWindowManager: WindowManager + private lateinit var viewContainer: AdditionalSystemViewContainer + + @Before + fun setUp() { + whenever(mockContext.getSystemService(WindowManager::class.java)) + .thenReturn(mockWindowManager) + whenever(mockContext.getSystemService(Context + .LAYOUT_INFLATER_SERVICE)).thenReturn(mockLayoutInflater) + whenever(mockLayoutInflater.inflate( + R.layout.desktop_mode_window_decor_handle_menu, null)).thenReturn(mockView) + } + + @Test + fun testReleaseView_ViewRemoved() { + viewContainer = AdditionalSystemViewContainer( + mockContext, + R.layout.desktop_mode_window_decor_handle_menu, + TASK_ID, + X, + Y, + WIDTH, + HEIGHT + ) + verify(mockWindowManager).addView(eq(mockView), any()) + viewContainer.releaseView() + verify(mockWindowManager).removeViewImmediate(mockView) + } + + companion object { + private const val X = 500 + private const val Y = 50 + private const val WIDTH = 400 + private const val HEIGHT = 600 + private const val TASK_ID = 5 + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalViewHostViewContainerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalViewHostViewContainerTest.kt new file mode 100644 index 000000000000..82d557a28f52 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalViewHostViewContainerTest.kt @@ -0,0 +1,68 @@ +/* + * 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.wm.shell.windowdecor.additionalviewcontainer + +import android.testing.AndroidTestingRunner +import android.view.SurfaceControl +import android.view.SurfaceControlViewHost +import androidx.test.filters.SmallTest +import com.android.wm.shell.ShellTestCase +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever +import java.util.function.Supplier + +/** + * Tests for [AdditionalViewHostViewContainer]. + * + * Build/Install/Run: + * atest WMShellUnitTests:AdditionalViewHostViewContainerTest + */ +@SmallTest +@RunWith(AndroidTestingRunner::class) +class AdditionalViewHostViewContainerTest : ShellTestCase() { + @Mock + private lateinit var mockTransactionSupplier: Supplier<SurfaceControl.Transaction> + @Mock + private lateinit var mockTransaction: SurfaceControl.Transaction + @Mock + private lateinit var mockSurface: SurfaceControl + @Mock + private lateinit var mockViewHost: SurfaceControlViewHost + private lateinit var viewContainer: AdditionalViewHostViewContainer + + @Before + fun setUp() { + whenever(mockTransactionSupplier.get()).thenReturn(mockTransaction) + } + + @Test + fun testReleaseView_ViewRemoved() { + viewContainer = AdditionalViewHostViewContainer( + mockSurface, + mockViewHost, + mockTransactionSupplier + ) + viewContainer.releaseView() + verify(mockViewHost).release() + verify(mockTransaction).remove(mockSurface) + verify(mockTransaction).apply() + } +} diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 68befffecf2f..e6182454ad8a 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -926,8 +926,8 @@ Asset* AssetManager::openAssetFromZipLocked(const ZipFileRO* pZipFile, //printf("USING Zip '%s'\n", pEntry->getFileName()); - if (!pZipFile->getEntryInfo(entry, &method, &uncompressedLen, NULL, NULL, - NULL, NULL)) + if (!pZipFile->getEntryInfo(entry, &method, &uncompressedLen, nullptr, nullptr, + nullptr, nullptr, nullptr)) { ALOGW("getEntryInfo failed\n"); return NULL; diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp index 839c7b6fef37..10651cdaff33 100644 --- a/libs/androidfw/ZipFileRO.cpp +++ b/libs/androidfw/ZipFileRO.cpp @@ -119,14 +119,6 @@ ZipEntryRO ZipFileRO::findEntryByName(const char* entryName) const * appear to be bogus. */ bool ZipFileRO::getEntryInfo(ZipEntryRO entry, uint16_t* pMethod, - uint32_t* pUncompLen, uint32_t* pCompLen, off64_t* pOffset, - uint32_t* pModWhen, uint32_t* pCrc32) const -{ - return getEntryInfo(entry, pMethod, pUncompLen, pCompLen, pOffset, pModWhen, - pCrc32, nullptr); -} - -bool ZipFileRO::getEntryInfo(ZipEntryRO entry, uint16_t* pMethod, uint32_t* pUncompLen, uint32_t* pCompLen, off64_t* pOffset, uint32_t* pModWhen, uint32_t* pCrc32, uint16_t* pExtraFieldSize) const { diff --git a/libs/androidfw/include/androidfw/ZipFileRO.h b/libs/androidfw/include/androidfw/ZipFileRO.h index f7c5007c80d2..0f3f19c91ed1 100644 --- a/libs/androidfw/include/androidfw/ZipFileRO.h +++ b/libs/androidfw/include/androidfw/ZipFileRO.h @@ -147,10 +147,6 @@ public: * Returns "false" if "entry" is bogus or if the data in the Zip file * appears to be bad. */ - bool getEntryInfo(ZipEntryRO entry, uint16_t* pMethod, uint32_t* pUncompLen, - uint32_t* pCompLen, off64_t* pOffset, uint32_t* pModWhen, - uint32_t* pCrc32) const; - bool getEntryInfo(ZipEntryRO entry, uint16_t* pMethod, uint32_t* pUncompLen, uint32_t* pCompLen, off64_t* pOffset, uint32_t* pModWhen, uint32_t* pCrc32, uint16_t* pExtraFieldSize) const; diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 7c1c5b4e7e5f..341599e79662 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -115,6 +115,7 @@ cc_defaults { "libharfbuzz_ng", "libminikin", "server_configurable_flags", + "libaconfig_storage_read_api_cc" ], static_libs: [ diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index 325bdd63ab22..5d3bc89b40dd 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -39,6 +39,9 @@ constexpr bool clip_surfaceviews() { constexpr bool hdr_10bit_plus() { return false; } +constexpr bool initialize_gl_always() { + return false; +} } // namespace hwui_flags #endif @@ -257,5 +260,9 @@ bool Properties::isDrawingEnabled() { return drawingEnabled == DrawingEnabled::On; } +bool Properties::initializeGlAlways() { + return base::GetBoolProperty(PROPERTY_INITIALIZE_GL_ALWAYS, hwui_flags::initialize_gl_always()); +} + } // namespace uirenderer } // namespace android diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index c1510d96461f..d3176f6879d2 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -229,6 +229,11 @@ enum DebugLevel { #define PROPERTY_8BIT_HDR_HEADROOM "debug.hwui.8bit_hdr_headroom" +/** + * Whether to initialize GL even when HWUI is running Vulkan. + */ +#define PROPERTY_INITIALIZE_GL_ALWAYS "debug.hwui.initialize_gl_always" + /////////////////////////////////////////////////////////////////////////////// // Misc /////////////////////////////////////////////////////////////////////////////// @@ -368,6 +373,8 @@ public: static bool isDrawingEnabled(); static void setDrawingEnabled(bool enable); + static bool initializeGlAlways(); + private: static StretchEffectBehavior stretchEffectBehavior; static ProfileType sProfileType; diff --git a/libs/hwui/aconfig/hwui_flags.aconfig b/libs/hwui/aconfig/hwui_flags.aconfig index 50f8b3929e1e..cd3ae5342f4e 100644 --- a/libs/hwui/aconfig/hwui_flags.aconfig +++ b/libs/hwui/aconfig/hwui_flags.aconfig @@ -90,3 +90,10 @@ flag { description: "Add canvas#drawRegion API" bug: "318612129" } + +flag { + name: "initialize_gl_always" + namespace: "core_graphics" + description: "Initialize GL even when HWUI is set to use Vulkan. This improves app startup time for apps using GL." + bug: "335172671" +} diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp index 6ace3967ecf3..15b2bac50c79 100644 --- a/libs/hwui/apex/jni_runtime.cpp +++ b/libs/hwui/apex/jni_runtime.cpp @@ -192,5 +192,14 @@ void zygote_preload_graphics() { // Preload Vulkan driver if HWUI renders with Vulkan backend. uint32_t apiVersion; vkEnumerateInstanceVersion(&apiVersion); + + if (Properties::initializeGlAlways()) { + // Even though HWUI is rendering with Vulkan, some apps still use + // GL. Preload GL driver just in case. Since this happens prior to + // forking from the zygote, apps that do not use GL are unaffected. + // Any memory that (E)GL uses for this call is in shared memory, + // and this call only happens once. + eglGetDisplay(EGL_DEFAULT_DISPLAY); + } } } diff --git a/libs/hwui/effects/GainmapRenderer.cpp b/libs/hwui/effects/GainmapRenderer.cpp index 0a30c6c14c4c..eac03609d72f 100644 --- a/libs/hwui/effects/GainmapRenderer.cpp +++ b/libs/hwui/effects/GainmapRenderer.cpp @@ -96,6 +96,7 @@ void DrawGainmapBitmap(SkCanvas* c, const sk_sp<const SkImage>& image, const SkR #ifdef __ANDROID__ static constexpr char gGainmapSKSL[] = R"SKSL( + uniform shader linearBase; uniform shader base; uniform shader gainmap; uniform colorFilter workingSpaceToLinearSrgb; @@ -117,7 +118,11 @@ static constexpr char gGainmapSKSL[] = R"SKSL( } half4 main(float2 coord) { - half4 S = base.eval(coord); + if (W == 0.0) { + return base.eval(coord); + } + + half4 S = linearBase.eval(coord); half4 G = gainmap.eval(coord); if (gainmapIsAlpha == 1) { G = half4(G.a, G.a, G.a, 1.0); @@ -186,8 +191,10 @@ private: SkColorFilterPriv::MakeColorSpaceXform(baseColorSpace, gainmapMathColorSpace); // The base image shader will convert into the color space in which the gainmap is applied. - auto baseImageShader = baseImage->makeRawShader(tileModeX, tileModeY, samplingOptions) - ->makeWithColorFilter(colorXformSdrToGainmap); + auto linearBaseImageShader = baseImage->makeRawShader(tileModeX, tileModeY, samplingOptions) + ->makeWithColorFilter(colorXformSdrToGainmap); + + auto baseImageShader = baseImage->makeShader(tileModeX, tileModeY, samplingOptions); // The gainmap image shader will ignore any color space that the gainmap has. const SkMatrix gainmapRectToDstRect = @@ -201,6 +208,7 @@ private: auto colorXformGainmapToDst = SkColorFilterPriv::MakeColorSpaceXform( gainmapMathColorSpace, SkColorSpace::MakeSRGBLinear()); + mBuilder.child("linearBase") = std::move(linearBaseImageShader); mBuilder.child("base") = std::move(baseImageShader); mBuilder.child("gainmap") = std::move(gainmapImageShader); mBuilder.child("workingSpaceToLinearSrgb") = std::move(colorXformGainmapToDst); diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 7b7ccf51aa1a..7a82938435af 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -46,7 +46,6 @@ cc_library_shared { "liblog", "libutils", "libgui", - "libui", "libinput", ], diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl index efbf8da6d17c..eeb4853afadc 100644 --- a/media/java/android/media/IMediaRouterService.aidl +++ b/media/java/android/media/IMediaRouterService.aidl @@ -52,6 +52,7 @@ interface IMediaRouterService { // Methods for MediaRouter2 List<MediaRoute2Info> getSystemRoutes(String callerPackageName, boolean isProxyRouter); RoutingSessionInfo getSystemSessionInfo(); + boolean showMediaOutputSwitcherWithRouter2(String packageName); void registerRouter2(IMediaRouter2 router, String packageName); void unregisterRouter2(IMediaRouter2 router); @@ -97,5 +98,5 @@ interface IMediaRouterService { void setSessionVolumeWithManager(IMediaRouter2Manager manager, int requestId, String sessionId, int volume); void releaseSessionWithManager(IMediaRouter2Manager manager, int requestId, String sessionId); - boolean showMediaOutputSwitcher(String packageName); + boolean showMediaOutputSwitcherWithProxyRouter(IMediaRouter2Manager manager); } diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java index 5672cd54e369..0667bfda7596 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -2666,8 +2666,11 @@ public final class MediaRouter2 { @Override public boolean showSystemOutputSwitcher() { - throw new UnsupportedOperationException( - "Cannot show system output switcher from a privileged router."); + try { + return mMediaRouterService.showMediaOutputSwitcherWithProxyRouter(mClient); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } } /** Gets the list of all discovered routes. */ @@ -3539,7 +3542,7 @@ public final class MediaRouter2 { public boolean showSystemOutputSwitcher() { synchronized (mLock) { try { - return mMediaRouterService.showMediaOutputSwitcher(mImpl.getPackageName()); + return mMediaRouterService.showMediaOutputSwitcherWithRouter2(mPackageName); } catch (RemoteException ex) { ex.rethrowFromSystemServer(); } diff --git a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java index a470f93db0c6..3cf0a4dc4873 100644 --- a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java +++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java @@ -412,7 +412,7 @@ public final class ApduServiceInfo implements Parcelable { false); if (!mOnHost && !autoTransact) { Log.e(TAG, "Ignoring polling-loop-filter " + plf - + " for offhost service that isn't autoTranact"); + + " for offhost service that isn't autoTransact"); } else { mAutoTransact.put(plf, autoTransact); } @@ -429,7 +429,7 @@ public final class ApduServiceInfo implements Parcelable { false); if (!mOnHost && !autoTransact) { Log.e(TAG, "Ignoring polling-loop-filter " + plf - + " for offhost service that isn't autoTranact"); + + " for offhost service that isn't autoTransact"); } else { mAutoTransactPatterns.put(Pattern.compile(plf), autoTransact); } @@ -1028,6 +1028,9 @@ public final class ApduServiceInfo implements Parcelable { pw.println(" Settings Activity: " + mSettingsActivityName); pw.println(" Requires Device Unlock: " + mRequiresDeviceUnlock); pw.println(" Requires Device ScreenOn: " + mRequiresDeviceScreenOn); + pw.println(" Should Default to Observe Mode: " + mShouldDefaultToObserveMode); + pw.println(" Auto-Transact Mapping: " + mAutoTransact); + pw.println(" Auto-Transact Patterns: " + mAutoTransactPatterns); } @@ -1081,6 +1084,27 @@ public final class ApduServiceInfo implements Parcelable { proto.end(token); } proto.write(ApduServiceInfoProto.SETTINGS_ACTIVITY_NAME, mSettingsActivityName); + proto.write(ApduServiceInfoProto.SHOULD_DEFAULT_TO_OBSERVE_MODE, + mShouldDefaultToObserveMode); + { + long token = proto.start(ApduServiceInfoProto.AUTO_TRANSACT_MAPPING); + for (Map.Entry<String, Boolean> entry : mAutoTransact.entrySet()) { + proto.write(ApduServiceInfoProto.AutoTransactMapping.AID, entry.getKey()); + proto.write(ApduServiceInfoProto.AutoTransactMapping.SHOULD_AUTO_TRANSACT, + entry.getValue()); + } + proto.end(token); + } + { + long token = proto.start(ApduServiceInfoProto.AUTO_TRANSACT_PATTERNS); + for (Map.Entry<Pattern, Boolean> entry : mAutoTransactPatterns.entrySet()) { + proto.write(ApduServiceInfoProto.AutoTransactPattern.REGEXP_PATTERN, + entry.getKey().pattern()); + proto.write(ApduServiceInfoProto.AutoTransactPattern.SHOULD_AUTO_TRANSACT, + entry.getValue()); + } + proto.end(token); + } } private static final Pattern AID_PATTERN = Pattern.compile("[0-9A-Fa-f]{10,32}\\*?\\#?"); diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml index 40d3be55ca71..3575ff31cdfc 100644 --- a/packages/CompanionDeviceManager/res/values-it/strings.xml +++ b/packages/CompanionDeviceManager/res/values-it/strings.xml @@ -59,7 +59,7 @@ <string name="permission_microphone" msgid="2152206421428732949">"Microfono"</string> <string name="permission_call_logs" msgid="5546761417694586041">"Registri chiamate"</string> <string name="permission_nearby_devices" msgid="7530973297737123481">"Dispositivi nelle vicinanze"</string> - <string name="permission_media_routing_control" msgid="5498639511586715253">"Cambia uscita conten. multim."</string> + <string name="permission_media_routing_control" msgid="5498639511586715253">"Cambia uscita multimediale"</string> <string name="permission_storage" msgid="6831099350839392343">"Foto e contenuti multimediali"</string> <string name="permission_notifications" msgid="4099418516590632909">"Notifiche"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"App"</string> diff --git a/packages/CredentialManager/res/values-kn/strings.xml b/packages/CredentialManager/res/values-kn/strings.xml index bfc31a1b11c2..897f444af2c5 100644 --- a/packages/CredentialManager/res/values-kn/strings.xml +++ b/packages/CredentialManager/res/values-kn/strings.xml @@ -20,7 +20,7 @@ <string name="app_name" msgid="4539824758261855508">"ರುಜುವಾತು ನಿರ್ವಾಹಕ"</string> <string name="string_cancel" msgid="6369133483981306063">"ರದ್ದುಗೊಳಿಸಿ"</string> <string name="string_continue" msgid="1346732695941131882">"ಮುಂದುವರಿಸಿ"</string> - <string name="string_more_options" msgid="2763852250269945472">"ಬೇರೆ ವಿಧಾನದಲ್ಲಿ ಉಳಿಸಿ"</string> + <string name="string_more_options" msgid="2763852250269945472">"ಬೇರೆ ವಿಧಾನದಲ್ಲಿ ಸೇವ್ ಮಾಡಿ"</string> <string name="string_learn_more" msgid="4541600451688392447">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string> <string name="content_description_show_password" msgid="3283502010388521607">"ಪಾಸ್ವರ್ಡ್ ತೋರಿಸಿ"</string> <string name="content_description_hide_password" msgid="6841375971631767996">"ಪಾಸ್ವರ್ಡ್ ಅನ್ನು ಮರೆಮಾಡಿ"</string> @@ -48,7 +48,7 @@ <string name="passwords" msgid="5419394230391253816">"ಪಾಸ್ವರ್ಡ್ಗಳು"</string> <string name="sign_ins" msgid="4710739369149469208">"ಸೈನ್-ಇನ್ಗಳು"</string> <string name="sign_in_info" msgid="2627704710674232328">"ಸೈನ್-ಇನ್ ಮಾಹಿತಿ"</string> - <string name="save_credential_to_title" msgid="3172811692275634301">"ಇಲ್ಲಿಗೆ <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> ಅನ್ನು ಉಳಿಸಿ"</string> + <string name="save_credential_to_title" msgid="3172811692275634301">"ಇಲ್ಲಿಗೆ <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> ಅನ್ನು ಸೇವ್ ಮಾಡಿ"</string> <string name="create_passkey_in_other_device_title" msgid="2360053098931886245">"ಇನ್ನೊಂದು ಸಾಧನದಲ್ಲಿ ಪಾಸ್ಕೀ ಅನ್ನು ರಚಿಸಬೇಕೆ?"</string> <string name="save_password_on_other_device_title" msgid="5829084591948321207">"ಇನ್ನೊಂದು ಸಾಧನದಲ್ಲಿ ಪಾಸ್ವರ್ಡ್ ಉಳಿಸಬೇಕೆ?"</string> <string name="save_sign_in_on_other_device_title" msgid="2827990118560134692">"ಮತ್ತೊಂದು ಸಾಧನದಲ್ಲಿ ಸೈನ್-ಇನ್ ಅನ್ನು ಉಳಿಸಬೇಕೆ?"</string> diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt index c477f30a1d2f..08846f0fed96 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt @@ -45,8 +45,8 @@ import androidx.credentials.CreateCredentialRequest import androidx.credentials.CreateCustomCredentialRequest import androidx.credentials.CreatePasswordRequest import androidx.credentials.CreatePublicKeyCredentialRequest +import androidx.credentials.CredentialOption import androidx.credentials.PasswordCredential -import androidx.credentials.PriorityHints import androidx.credentials.PublicKeyCredential import androidx.credentials.provider.CreateEntry import androidx.credentials.provider.RemoteEntry @@ -177,9 +177,9 @@ class GetFlowUtils { "androidx.credentials.BUNDLE_KEY_TYPE_PRIORITY_VALUE", when (option.type) { PasswordCredential.TYPE_PASSWORD_CREDENTIAL -> - PriorityHints.PRIORITY_PASSWORD_OR_SIMILAR + CredentialOption.PRIORITY_PASSWORD_OR_SIMILAR PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL -> 100 - else -> PriorityHints.PRIORITY_DEFAULT + else -> CredentialOption.PRIORITY_DEFAULT } ) typePriorityMap[option.type] = priority @@ -349,8 +349,8 @@ class CreateFlowUtils { } is CreateCustomCredentialRequest -> { // TODO: directly use the display info once made public - val displayInfo = CreateCredentialRequest.DisplayInfo - .parseFromCredentialDataBundle(createCredentialRequest.credentialData) + val displayInfo = CreateCredentialRequest.DisplayInfo.createFrom( + createCredentialRequest.credentialData) ?: return null RequestDisplayInfo( title = displayInfo.userId.toString(), diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt index 19f5a99f46fa..314cc0547b89 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt @@ -19,7 +19,7 @@ package com.android.credentialmanager.getflow import android.credentials.flags.Flags.selectorUiImprovementsEnabled import android.credentials.flags.Flags.credmanBiometricApiEnabled import android.graphics.drawable.Drawable -import androidx.credentials.PriorityHints +import androidx.credentials.CredentialOption import com.android.credentialmanager.R import com.android.credentialmanager.model.CredentialType import com.android.credentialmanager.model.get.ProviderInfo @@ -322,10 +322,10 @@ internal class CredentialEntryInfoComparatorByTypeThenTimestamp( // First rank by priorities of each credential type. if (p0.rawCredentialType != p1.rawCredentialType) { val p0Priority = typePriorityMap.getOrDefault( - p0.rawCredentialType, PriorityHints.PRIORITY_DEFAULT + p0.rawCredentialType, CredentialOption.PRIORITY_DEFAULT ) val p1Priority = typePriorityMap.getOrDefault( - p1.rawCredentialType, PriorityHints.PRIORITY_DEFAULT + p1.rawCredentialType, CredentialOption.PRIORITY_DEFAULT ) if (p0Priority < p1Priority) { return -1 diff --git a/packages/EasterEgg/AndroidManifest.xml b/packages/EasterEgg/AndroidManifest.xml index d1db237966d5..1500583a7677 100644 --- a/packages/EasterEgg/AndroidManifest.xml +++ b/packages/EasterEgg/AndroidManifest.xml @@ -36,8 +36,28 @@ android:icon="@drawable/android14_patch_adaptive" android:label="@string/app_name"> - <!-- Android U easter egg --> + <!-- Android V easter egg: Daydream version of Landroid + (must be enabled by unlocking the egg) --> + <service + android:name=".landroid.DreamUniverse" + android:exported="true" + android:icon="@drawable/android14_patch_adaptive" + android:label="@string/v_egg_name" + android:description="@string/dream_description" + android:enabled="false" + android:permission="android.permission.BIND_DREAM_SERVICE" + > + <intent-filter> + <action android:name="android.service.dreams.DreamService" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + <meta-data + android:name="android.service.dream" + android:resource="@xml/landroid_dream"/> + </service> + + <!-- Android U easter egg --> <activity android:name=".landroid.MainActivity" android:exported="true" @@ -52,7 +72,6 @@ </intent-filter> </activity> - <!-- Android Q easter egg --> <activity android:name=".quares.QuaresActivity" diff --git a/packages/EasterEgg/res/values/landroid_strings.xml b/packages/EasterEgg/res/values/landroid_strings.xml index 1394f2f55868..1bbfcca9d899 100644 --- a/packages/EasterEgg/res/values/landroid_strings.xml +++ b/packages/EasterEgg/res/values/landroid_strings.xml @@ -1,21 +1,13 @@ -<?xml version="1.0" encoding="utf-8"?><!-- - 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. ---> - +<?xml version="1.0" encoding="utf-8"?> <resources> - <string name="u_egg_name" translatable="false">Android 14 Easter Egg</string> + + <!-- No Android's Sky --> + <!-- Char Star Field --> + <!-- V-leet: Harmless --> + <!-- Contemplating My Orbital Mechanics --> + <string name="u_egg_name" translatable="false">Landroid</string> + <string name="v_egg_name" translatable="false">Landroid</string> + <string name="dream_description" translatable="false">---- AUTOPILOT ENGAGED ----</string> <string-array name="planet_descriptors" translatable="false"> <item>earthy</item> @@ -365,7 +357,64 @@ <item>relaxed</item> <item>skunky</item> <item>breezy</item> - <item>soup </item> + <item>soup</item> + </string-array> + + <string-array name="fauna_generic_plurals" translatable="false"> + <item>fauna</item> + <item>animals</item> + <item>locals</item> + <item>creatures</item> + <item>critters</item> + <item>wildlife</item> + <item>specimens</item> + <item>life</item> + <item>cells</item> + </string-array> + + <string-array name="flora_generic_plurals" translatable="false"> + <item>flora</item> + <item>plants</item> + <item>flowers</item> + <item>trees</item> + <item>mosses</item> + <item>specimens</item> + <item>life</item> + <item>cells</item> + </string-array> + + <string-array name="atmo_generic_plurals" translatable="false"> + <item>air</item> + <item>atmosphere</item> + <item>clouds</item> + <item>atmo</item> + <item>gases</item> + </string-array> + + <string-array name="activities" translatable="false"> + <item>refueling</item> + <item>sightseeing</item> + <item>vacationing</item> + <item>luncheoning</item> + <item>recharging</item> + <item>taking up space</item> + <item>reticulating space splines</item> + <item>using facilities</item> + <item>spelunking</item> + <item>repairing</item> + <item>herding {fauna}</item> + <item>taming {fauna}</item> + <item>breeding {fauna}</item> + <item>singing lullabies to {fauna}</item> + <item>singing lullabies to {flora}</item> + <item>singing lullabies to the {planet}</item> + <item>gardening {flora}</item> + <item>collecting {flora}</item> + <item>surveying the {planet}</item> + <item>mapping the {planet}</item> + <item>breathing {atmo}</item> + <item>reprocessing {atmo}</item> + <item>bottling {atmo}</item> </string-array> </resources> diff --git a/packages/EasterEgg/res/xml/landroid_dream.xml b/packages/EasterEgg/res/xml/landroid_dream.xml new file mode 100644 index 000000000000..adf82bd9a4cc --- /dev/null +++ b/packages/EasterEgg/res/xml/landroid_dream.xml @@ -0,0 +1,18 @@ +<?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. +--> +<dream xmlns:android="http://schemas.android.com/apk/res/android" + android:previewImage="@*android:drawable/platlogo" /> diff --git a/packages/EasterEgg/src/com/android/egg/ComponentActivationActivity.java b/packages/EasterEgg/src/com/android/egg/ComponentActivationActivity.java index 5820b5a75894..30320d6a8861 100644 --- a/packages/EasterEgg/src/com/android/egg/ComponentActivationActivity.java +++ b/packages/EasterEgg/src/com/android/egg/ComponentActivationActivity.java @@ -18,11 +18,14 @@ package com.android.egg; import android.app.Activity; import android.content.ComponentName; +import android.content.Context; import android.content.pm.PackageManager; import android.provider.Settings; import android.util.Log; import android.widget.Toast; +import com.android.egg.flags.Flags; +import com.android.egg.landroid.DreamUniverse; import com.android.egg.neko.NekoControlsService; import com.android.egg.widget.PaintChipsActivity; import com.android.egg.widget.PaintChipsWidget; @@ -33,7 +36,9 @@ import com.android.egg.widget.PaintChipsWidget; public class ComponentActivationActivity extends Activity { private static final String TAG = "EasterEgg"; + // check PlatLogoActivity.java for these private static final String S_EGG_UNLOCK_SETTING = "egg_mode_s"; + private static final String V_EGG_UNLOCK_SETTING = "egg_mode_v"; private void toastUp(String s) { Toast toast = Toast.makeText(this, s, Toast.LENGTH_SHORT); @@ -44,14 +49,39 @@ public class ComponentActivationActivity extends Activity { public void onStart() { super.onStart(); - final PackageManager pm = getPackageManager(); - final ComponentName[] cns = new ComponentName[] { - new ComponentName(this, NekoControlsService.class), - new ComponentName(this, PaintChipsActivity.class), - new ComponentName(this, PaintChipsWidget.class) - }; - final long unlockValue = Settings.System.getLong(getContentResolver(), - S_EGG_UNLOCK_SETTING, 0); + lockUnlockComponents(this); + + finish(); + } + + /** + * Check easter egg unlock state and update unlockable components to match. + */ + public static void lockUnlockComponents(Context context) { + final PackageManager pm = context.getPackageManager(); + final ComponentName[] cns; + final String unlockSettingsKey; + final boolean shouldReLock; + final long unlockValue; + if (Flags.flagFlag()) { + unlockSettingsKey = V_EGG_UNLOCK_SETTING; + unlockValue = 1; // since we're not toggling we actually don't need to check the setting + shouldReLock = false; + cns = new ComponentName[]{ + new ComponentName(context, DreamUniverse.class) + }; + } else { + unlockSettingsKey = S_EGG_UNLOCK_SETTING; + unlockValue = Settings.System.getLong(context.getContentResolver(), + unlockSettingsKey, 0); + shouldReLock = true; + cns = new ComponentName[]{ + new ComponentName(context, NekoControlsService.class), + new ComponentName(context, PaintChipsActivity.class), + new ComponentName(context, PaintChipsWidget.class), + new ComponentName(context, DreamUniverse.class) + }; + } for (ComponentName cn : cns) { final boolean componentEnabled = pm.getComponentEnabledSetting(cn) == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; @@ -77,7 +107,5 @@ public class ComponentActivationActivity extends Activity { } } } - - finish(); } } diff --git a/packages/EasterEgg/src/com/android/egg/landroid/Autopilot.kt b/packages/EasterEgg/src/com/android/egg/landroid/Autopilot.kt new file mode 100644 index 000000000000..f71abee6fb43 --- /dev/null +++ b/packages/EasterEgg/src/com/android/egg/landroid/Autopilot.kt @@ -0,0 +1,164 @@ +/* + * 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.egg.landroid + +import kotlin.math.min +import kotlin.math.sign + +class Autopilot(val ship: Spacecraft, val universe: Universe) : Entity { + val BRAKING_TIME = 5f + val SIGHTSEEING_TIME = 10f + val STRATEGY_MIN_TIME = 0.5f + + var enabled = false + + var target: Planet? = null + + var landingAltitude = 0f + + var nextStrategyTime = 0f + + var brakingDistance = 0f + + // used by rendering + var leadingPos = Vec2.Zero + var leadingVector = Vec2.Zero + + val telemetry: String + get() = + listOf( + "---- AUTOPILOT ENGAGED ----", + "TGT: " + (target?.name?.toUpperCase() ?: "SELECTING..."), + "EXE: $strategy" + if (debug.isNotEmpty()) " ($debug)" else "", + ) + .joinToString("\n") + + private var strategy: String = "NONE" + private var debug: String = "" + + override fun update(sim: Simulator, dt: Float) { + if (!enabled) return + + if (sim.now < nextStrategyTime) { + return + } + + val currentStrategy = strategy + + if (ship.landing != null) { + if (target != null) { + strategy = "LANDED" + debug = "" + // we just got here. see the sights. + target = null + landingAltitude = 0f + nextStrategyTime = sim.now + SIGHTSEEING_TIME + } else { + // full power until we blast off + ship.thrust = Vec2.makeWithAngleMag(ship.angle, 1f) + + strategy = "LAUNCHING" + debug = "" + nextStrategyTime = sim.now + 2f + } + } else { + // select new target + + if (target == null) { + // testing: target the first planet + // target = universe.planets[0] + + // target the nearest unexplored planet + target = + universe.planets + .sortedBy { (it.pos - ship.pos).mag() } + .firstOrNull { !it.explored } + brakingDistance = 0f + + // if we've explored them all, pick one at random + if (target == null) target = universe.planets.random() + } + + target?.let { target -> // should be nonnull + val shipV = ship.velocity + val targetV = target.velocity + val targetVector = (target.pos - ship.pos) + val altitude = targetVector.mag() - target.radius + + landingAltitude = min(target.radius, 100f) + + // the following is in the moving reference frame of the target + val relativeV: Vec2 = shipV - targetV + val projection = relativeV.dot(targetVector / targetVector.mag()) + val relativeSpeed = relativeV.mag() * projection.sign + val timeToTarget = if (relativeSpeed != 0f) altitude / relativeSpeed else 1_000f + + val newBrakingDistance = + BRAKING_TIME * if (relativeSpeed > 0) relativeSpeed else MAIN_ENGINE_ACCEL + brakingDistance = + expSmooth(brakingDistance, newBrakingDistance, dt = sim.dt, speed = 5f) + + // We're going to aim at where the target will be, but we want to make sure to + // compute + leadingPos = + target.pos + + Vec2.makeWithAngleMag( + target.velocity.angle(), + min(altitude / 2, target.velocity.mag()) + ) + leadingVector = leadingPos - ship.pos + + if (altitude < landingAltitude) { + strategy = "LANDING" + // Strategy: zero thrust, face away, prepare for landing + + ship.angle = (ship.pos - target.pos).angle() // point away from ground + ship.thrust = Vec2.Zero + } else { + if (relativeSpeed < 0 || altitude > brakingDistance) { + strategy = "CHASING" + // Strategy: Make tracks. We are either a long way away, or falling behind. + ship.angle = leadingVector.angle() + + ship.thrust = Vec2.makeWithAngleMag(ship.angle, 1.0f) + } else { + strategy = "APPROACHING" + // Strategy: Just slow down. If we get caught in the gravity well, it will + // gradually start pulling us more in the direction of the planet, which + // will create a graceful deceleration + ship.angle = (-ship.velocity).angle() + + // We want to bleed off velocity over time. Specifically, relativeSpeed px/s + // over timeToTarget seconds. + val decel = relativeSpeed / timeToTarget + val decelThrust = + decel / MAIN_ENGINE_ACCEL * 0.9f // not quite slowing down enough + ship.thrust = Vec2.makeWithAngleMag(ship.angle, decelThrust) + } + } + debug = ("DV=%.0f D=%.0f T%+.1f").format(relativeSpeed, altitude, timeToTarget) + } + if (strategy != currentStrategy) { + nextStrategyTime = sim.now + STRATEGY_MIN_TIME + } + } + } + + override fun postUpdate(sim: Simulator, dt: Float) { + if (!enabled) return + } +} diff --git a/packages/EasterEgg/src/com/android/egg/landroid/Colors.kt b/packages/EasterEgg/src/com/android/egg/landroid/Colors.kt index f5657ae6c0c3..24c49754276a 100644 --- a/packages/EasterEgg/src/com/android/egg/landroid/Colors.kt +++ b/packages/EasterEgg/src/com/android/egg/landroid/Colors.kt @@ -19,11 +19,22 @@ package com.android.egg.landroid import androidx.compose.ui.graphics.Color /** Various UI colors. */ -object Colors { - val Eigengrau = Color(0xFF16161D) - val Eigengrau2 = Color(0xFF292936) - val Eigengrau3 = Color(0xFF3C3C4F) - val Eigengrau4 = Color(0xFFA7A7CA) +class Colors { + object Android { + val Green = Color(0xFF34A853) + val Blue = Color(0xFF4285F4) + val Mint = Color(0xFFE8F5E9) + val Chartreuse = Color(0xFFC6FF00) + } + companion object { + val Eigengrau = Color(0xFF16161D) + val Eigengrau2 = Color(0xFF292936) + val Eigengrau3 = Color(0xFF3C3C4F) + val Eigengrau4 = Color(0xFFA7A7CA) - val Console = Color(0xFFB7B7FF) + val Console = Color(0xFFB7B7FF) + val Autopilot = Android.Blue + val Track = Android.Green + val Flag = Android.Chartreuse + } } diff --git a/packages/EasterEgg/src/com/android/egg/landroid/DreamUniverse.kt b/packages/EasterEgg/src/com/android/egg/landroid/DreamUniverse.kt new file mode 100644 index 000000000000..8c87c5d4af7b --- /dev/null +++ b/packages/EasterEgg/src/com/android/egg/landroid/DreamUniverse.kt @@ -0,0 +1,120 @@ +/* + * 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.egg.landroid + +import android.service.dreams.DreamService +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.mutableStateOf +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.ComposeView +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleRegistry +import androidx.lifecycle.setViewTreeLifecycleOwner +import androidx.savedstate.SavedStateRegistryController +import androidx.savedstate.SavedStateRegistryOwner +import androidx.savedstate.setViewTreeSavedStateRegistryOwner +import androidx.window.layout.FoldingFeature +import kotlin.random.Random + +class DreamUniverse : DreamService() { + private var foldState = mutableStateOf<FoldingFeature?>(null) // unused + + private val lifecycleOwner = + object : SavedStateRegistryOwner { + override val lifecycle = LifecycleRegistry(this) + override val savedStateRegistry + get() = savedStateRegistryController.savedStateRegistry + + private val savedStateRegistryController = + SavedStateRegistryController.create(this).apply { performAttach() } + + fun onCreate() { + savedStateRegistryController.performRestore(null) + lifecycle.currentState = Lifecycle.State.CREATED + } + + fun onStart() { + lifecycle.currentState = Lifecycle.State.STARTED + } + + fun onStop() { + lifecycle.currentState = Lifecycle.State.CREATED + } + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + + val universe = VisibleUniverse(namer = Namer(resources), randomSeed = randomSeed()) + + isInteractive = false + + if (TEST_UNIVERSE) { + universe.initTest() + } else { + universe.initRandom() + + // We actually don't want the deterministic random position of the ship, we want + // true randomness to keep things interesting. So use Random (not universe.rng). + universe.ship.pos = + universe.star.pos + + Vec2.makeWithAngleMag( + Random.nextFloat() * PI2f, + Random.nextFloatInRange( + PLANET_ORBIT_RANGE.start, + PLANET_ORBIT_RANGE.endInclusive + ) + ) + } + + // enable autopilot in screensaver mode + val autopilot = Autopilot(universe.ship, universe) + universe.ship.autopilot = autopilot + universe.add(autopilot) + autopilot.enabled = true + + // much more visually interesting in a screensaver context + DYNAMIC_ZOOM = true + + val composeView = ComposeView(this) + composeView.setContent { + Spaaaace(modifier = Modifier.fillMaxSize(), u = universe, foldState = foldState) + DebugText(DEBUG_TEXT) + Telemetry(universe) + } + + composeView.setViewTreeLifecycleOwner(lifecycleOwner) + composeView.setViewTreeSavedStateRegistryOwner(lifecycleOwner) + + setContentView(composeView) + } + + override fun onCreate() { + super.onCreate() + lifecycleOwner.onCreate() + } + + override fun onDreamingStarted() { + super.onDreamingStarted() + lifecycleOwner.onStart() + } + + override fun onDreamingStopped() { + super.onDreamingStopped() + lifecycleOwner.onStop() + } +} diff --git a/packages/EasterEgg/src/com/android/egg/landroid/MainActivity.kt b/packages/EasterEgg/src/com/android/egg/landroid/MainActivity.kt index 5a9b8141bb40..79f8b5fc6ecd 100644 --- a/packages/EasterEgg/src/com/android/egg/landroid/MainActivity.kt +++ b/packages/EasterEgg/src/com/android/egg/landroid/MainActivity.kt @@ -21,12 +21,10 @@ import android.os.Bundle import android.util.Log import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.core.CubicBezierEasing import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.animation.core.tween import androidx.compose.animation.core.withInfiniteAnimationFrameNanos -import androidx.compose.animation.fadeIn import androidx.compose.foundation.Canvas import androidx.compose.foundation.border import androidx.compose.foundation.gestures.awaitFirstDown @@ -34,12 +32,14 @@ import androidx.compose.foundation.gestures.forEachGesture import androidx.compose.foundation.gestures.rememberTransformableState import androidx.compose.foundation.gestures.transformable import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ColumnScope -import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeContent +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -49,6 +49,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.AbsoluteAlignment.Left +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.geometry.Offset @@ -59,8 +60,10 @@ import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.drawscope.translate import androidx.compose.ui.input.pointer.PointerEvent import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.toUpperCase import androidx.compose.ui.tooling.preview.Devices import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -94,12 +97,12 @@ const val TEST_UNIVERSE = false val RANDOM_SEED_TYPE = RandomSeedType.Daily const val FIXED_RANDOM_SEED = 5038L -const val DEFAULT_CAMERA_ZOOM = 0.25f +const val DEFAULT_CAMERA_ZOOM = 1f const val MIN_CAMERA_ZOOM = 250f / UNIVERSE_RANGE // 0.0025f const val MAX_CAMERA_ZOOM = 5f -const val TOUCH_CAMERA_PAN = false -const val TOUCH_CAMERA_ZOOM = true -const val DYNAMIC_ZOOM = false // @@@ FIXME +var TOUCH_CAMERA_PAN = false +var TOUCH_CAMERA_ZOOM = false +var DYNAMIC_ZOOM = false fun dailySeed(): Long { val today = GregorianCalendar() @@ -134,38 +137,20 @@ fun DebugText(text: MutableState<String>) { } @Composable -fun ColumnScope.ConsoleText( - modifier: Modifier = Modifier, - visible: Boolean = true, - random: Random = Random.Default, - text: String -) { - AnimatedVisibility( - modifier = modifier, - visible = visible, - enter = - fadeIn( - animationSpec = - tween( - durationMillis = 1000, - easing = flickerFadeEasing(random) * CubicBezierEasing(0f, 1f, 1f, 0f) - ) - ) - ) { - Text( +fun Telemetry(universe: VisibleUniverse) { + var topVisible by remember { mutableStateOf(false) } + var bottomVisible by remember { mutableStateOf(false) } + + var catalogFontSize by remember { mutableStateOf(9.sp) } + + val textStyle = + TextStyle( fontFamily = FontFamily.Monospace, fontWeight = FontWeight.Medium, fontSize = 12.sp, - color = Color(0xFFFF8000), - text = text + letterSpacing = 1.sp, + lineHeight = 12.sp, ) - } -} - -@Composable -fun Telemetry(universe: VisibleUniverse) { - var topVisible by remember { mutableStateOf(false) } - var bottomVisible by remember { mutableStateOf(false) } LaunchedEffect("blah") { delay(1000) @@ -174,65 +159,109 @@ fun Telemetry(universe: VisibleUniverse) { topVisible = true } - Column(modifier = Modifier.fillMaxSize().padding(6.dp)) { - universe.triggerDraw.value // recompose on every frame - val explored = universe.planets.filter { it.explored } + universe.triggerDraw.value // recompose on every frame - AnimatedVisibility(modifier = Modifier, visible = topVisible, enter = flickerFadeIn) { - Text( - fontFamily = FontFamily.Monospace, - fontWeight = FontWeight.Medium, - fontSize = 12.sp, - color = Colors.Console, - modifier = Modifier.align(Left), - text = - with(universe.star) { - " STAR: $name (UDC-${universe.randomSeed % 100_000})\n" + - " CLASS: ${cls.name}\n" + - "RADIUS: ${radius.toInt()}\n" + - " MASS: %.3g\n".format(mass) + - "BODIES: ${explored.size} / ${universe.planets.size}\n" + - "\n" - } + - explored - .map { - " BODY: ${it.name}\n" + - " TYPE: ${it.description.capitalize()}\n" + - " ATMO: ${it.atmosphere.capitalize()}\n" + - " FAUNA: ${it.fauna.capitalize()}\n" + - " FLORA: ${it.flora.capitalize()}\n" - } - .joinToString("\n") + val explored = universe.planets.filter { it.explored } - // TODO: different colors, highlight latest discovery + BoxWithConstraints( + modifier = + Modifier.fillMaxSize().padding(6.dp).windowInsetsPadding(WindowInsets.safeContent), + ) { + val wide = maxWidth > maxHeight + Column( + modifier = + Modifier.align(if (wide) Alignment.BottomEnd else Alignment.BottomStart) + .fillMaxWidth(if (wide) 0.45f else 1.0f) + ) { + universe.ship.autopilot?.let { autopilot -> + if (autopilot.enabled) { + AnimatedVisibility( + modifier = Modifier, + visible = bottomVisible, + enter = flickerFadeIn + ) { + Text( + style = textStyle, + color = Colors.Autopilot, + modifier = Modifier.align(Left), + text = autopilot.telemetry + ) + } + } + } + + AnimatedVisibility( + modifier = Modifier, + visible = bottomVisible, + enter = flickerFadeIn + ) { + Text( + style = textStyle, + color = Colors.Console, + modifier = Modifier.align(Left), + text = + with(universe.ship) { + val closest = universe.closestPlanet() + val distToClosest = ((closest.pos - pos).mag() - closest.radius).toInt() + listOfNotNull( + landing?.let { + "LND: ${it.planet.name.toUpperCase()}\nJOB: ${it.text}" + } + ?: if (distToClosest < 10_000) { + "ALT: $distToClosest" + } else null, + "THR: %.0f%%".format(thrust.mag() * 100f), + "POS: %s".format(pos.str("%+7.0f")), + "VEL: %.0f".format(velocity.mag()) + ) + .joinToString("\n") + } ) + } } - Spacer(modifier = Modifier.weight(1f)) - - AnimatedVisibility(modifier = Modifier, visible = bottomVisible, enter = flickerFadeIn) { + AnimatedVisibility( + modifier = Modifier.align(Alignment.TopStart), + visible = topVisible, + enter = flickerFadeIn + ) { Text( - fontFamily = FontFamily.Monospace, - fontWeight = FontWeight.Medium, - fontSize = 12.sp, + style = textStyle, + fontSize = catalogFontSize, + lineHeight = catalogFontSize, + letterSpacing = 1.sp, color = Colors.Console, - modifier = Modifier.align(Left), + onTextLayout = { textLayoutResult -> + if (textLayoutResult.didOverflowHeight) { + catalogFontSize = 8.sp + } + }, text = - with(universe.ship) { - val closest = universe.closestPlanet() - val distToClosest = (closest.pos - pos).mag().toInt() - listOfNotNull( - landing?.let { "LND: ${it.planet.name}" } - ?: if (distToClosest < 10_000) { - "ALT: $distToClosest" - } else null, - if (thrust != Vec2.Zero) "THR: %.0f%%".format(thrust.mag() * 100f) - else null, - "POS: %s".format(pos.str("%+7.0f")), - "VEL: %.0f".format(velocity.mag()) + (with(universe.star) { + listOf( + " STAR: $name (UDC-${universe.randomSeed % 100_000})", + " CLASS: ${cls.name}", + "RADIUS: ${radius.toInt()}", + " MASS: %.3g".format(mass), + "BODIES: ${explored.size} / ${universe.planets.size}", + "" ) - .joinToString("\n") - } + } + + explored + .map { + listOf( + " BODY: ${it.name}", + " TYPE: ${it.description.capitalize()}", + " ATMO: ${it.atmosphere.capitalize()}", + " FAUNA: ${it.fauna.capitalize()}", + " FLORA: ${it.flora.capitalize()}", + "" + ) + } + .flatten()) + .joinToString("\n") + + // TODO: different colors, highlight latest discovery ) } } @@ -246,6 +275,8 @@ class MainActivity : ComponentActivity() { onWindowLayoutInfoChange() + enableEdgeToEdge() + val universe = VisibleUniverse(namer = Namer(resources), randomSeed = randomSeed()) if (TEST_UNIVERSE) { @@ -254,6 +285,15 @@ class MainActivity : ComponentActivity() { universe.initRandom() } + com.android.egg.ComponentActivationActivity.lockUnlockComponents(applicationContext) + + // for autopilot testing in the activity + // val autopilot = Autopilot(universe.ship, universe) + // universe.ship.autopilot = autopilot + // universe.add(autopilot) + // autopilot.enabled = true + // DYNAMIC_ZOOM = autopilot.enabled + setContent { Spaaaace(modifier = Modifier.fillMaxSize(), u = universe, foldState = foldState) DebugText(DEBUG_TEXT) @@ -437,8 +477,13 @@ fun Spaaaace( val distToNearestSurf = max(0f, (u.ship.pos - closest.pos).mag() - closest.radius * 1.2f) // val normalizedDist = clamp(distToNearestSurf, 50f, 50_000f) / 50_000f if (DYNAMIC_ZOOM) { - // cameraZoom = lerp(0.1f, 5f, smooth(1f-normalizedDist)) - cameraZoom = clamp(500f / distToNearestSurf, MIN_CAMERA_ZOOM, MAX_CAMERA_ZOOM) + cameraZoom = + expSmooth( + cameraZoom, + clamp(500f / distToNearestSurf, MIN_CAMERA_ZOOM, MAX_CAMERA_ZOOM), + dt = u.dt, + speed = 1.5f + ) } else if (!TOUCH_CAMERA_ZOOM) cameraZoom = DEFAULT_CAMERA_ZOOM if (!TOUCH_CAMERA_PAN) cameraOffset = (u.follow?.pos ?: Vec2.Zero) * -1f @@ -478,26 +523,26 @@ fun Spaaaace( "star: '${u.star.name}' designation=UDC-${u.randomSeed % 100_000} " + "class=${u.star.cls.name} r=${u.star.radius.toInt()} m=${u.star.mass}\n" + "planets: ${u.planets.size}\n" + - u.planets.joinToString("\n") { - val range = (u.ship.pos - it.pos).mag() - val vorbit = sqrt(GRAVITATION * it.mass / range) - val vescape = sqrt(2 * GRAVITATION * it.mass / it.radius) - " * ${it.name}:\n" + - if (it.explored) { - " TYPE: ${it.description.capitalize()}\n" + - " ATMO: ${it.atmosphere.capitalize()}\n" + - " FAUNA: ${it.fauna.capitalize()}\n" + - " FLORA: ${it.flora.capitalize()}\n" - } else { - " (Unexplored)\n" - } + - " orbit=${(it.pos - it.orbitCenter).mag().toInt()}" + - " radius=${it.radius.toInt()}" + - " mass=${"%g".format(it.mass)}" + - " vel=${(it.speed).toInt()}" + - " // range=${"%.0f".format(range)}" + - " vorbit=${vorbit.toInt()} vescape=${vescape.toInt()}" - }) + u.planets.joinToString("\n") { + val range = (u.ship.pos - it.pos).mag() + val vorbit = sqrt(GRAVITATION * it.mass / range) + val vescape = sqrt(2 * GRAVITATION * it.mass / it.radius) + " * ${it.name}:\n" + + if (it.explored) { + " TYPE: ${it.description.capitalize()}\n" + + " ATMO: ${it.atmosphere.capitalize()}\n" + + " FAUNA: ${it.fauna.capitalize()}\n" + + " FLORA: ${it.flora.capitalize()}\n" + } else { + " (Unexplored)\n" + } + + " orbit=${(it.pos - it.orbitCenter).mag().toInt()}" + + " radius=${it.radius.toInt()}" + + " mass=${"%g".format(it.mass)}" + + " vel=${(it.speed).toInt()}" + + " // range=${"%.0f".format(range)}" + + " vorbit=${vorbit.toInt()} vescape=${vescape.toInt()}" + }) zoom(cameraZoom) { // All coordinates are space coordinates now. diff --git a/packages/EasterEgg/src/com/android/egg/landroid/Maths.kt b/packages/EasterEgg/src/com/android/egg/landroid/Maths.kt index fdf29f7aa948..a1e82127578d 100644 --- a/packages/EasterEgg/src/com/android/egg/landroid/Maths.kt +++ b/packages/EasterEgg/src/com/android/egg/landroid/Maths.kt @@ -16,6 +16,7 @@ package com.android.egg.landroid +import kotlin.math.exp import kotlin.math.pow /** smoothstep. Ken Perlin's version */ @@ -32,3 +33,8 @@ fun invsmoothish(x: Float): Float { fun lexp(start: Float, end: Float, progress: Float): Float { return (progress - start) / (end - start) } + +/** Exponentially smooth current toward target by a factor of speed. */ +fun expSmooth(current: Float, target: Float, dt: Float = 1f / 60, speed: Float = 5f): Float { + return current + (target - current) * (1 - exp(-dt * speed)) +} diff --git a/packages/EasterEgg/src/com/android/egg/landroid/Namer.kt b/packages/EasterEgg/src/com/android/egg/landroid/Namer.kt index 67d536e0aea1..73318077f47a 100644 --- a/packages/EasterEgg/src/com/android/egg/landroid/Namer.kt +++ b/packages/EasterEgg/src/com/android/egg/landroid/Namer.kt @@ -17,9 +17,8 @@ package com.android.egg.landroid import android.content.res.Resources -import kotlin.random.Random - import com.android.egg.R +import kotlin.random.Random const val SUFFIX_PROB = 0.75f const val LETTER_PROB = 0.3f @@ -62,6 +61,11 @@ class Namer(resources: Resources) { 0.1f to "(^*!%@##!!" ) + private var activities = Bag(resources.getStringArray(R.array.activities)) + private var floraGenericPlurals = Bag(resources.getStringArray(R.array.flora_generic_plurals)) + private var faunaGenericPlurals = Bag(resources.getStringArray(R.array.fauna_generic_plurals)) + private var atmoGenericPlurals = Bag(resources.getStringArray(R.array.atmo_generic_plurals)) + fun describePlanet(rng: Random): String { return planetTable.roll(rng).pull(rng) + " " + planetTypes.pull(rng) } @@ -93,4 +97,30 @@ class Namer(resources: Resources) { fun describeAtmo(rng: Random): String { return atmoTable.roll(rng).pull(rng) } + + fun floraPlural(rng: Random): String { + return floraGenericPlurals.pull(rng) + } + fun faunaPlural(rng: Random): String { + return faunaGenericPlurals.pull(rng) + } + fun atmoPlural(rng: Random): String { + return atmoGenericPlurals.pull(rng) + } + + val TEMPLATE_REGEX = Regex("""\{(flora|fauna|planet|atmo)\}""") + fun describeActivity(rng: Random, target: Planet?): String { + return activities + .pull(rng) + .replace(TEMPLATE_REGEX) { + when (it.groupValues[1]) { + "flora" -> (target?.flora ?: "SOME") + " " + floraPlural(rng) + "fauna" -> (target?.fauna ?: "SOME") + " " + faunaPlural(rng) + "atmo" -> (target?.atmosphere ?: "SOME") + " " + atmoPlural(rng) + "planet" -> (target?.description ?: "SOME BODY") // once told me + else -> "unknown template tag: ${it.groupValues[0]}" + } + } + .toUpperCase() + } } diff --git a/packages/EasterEgg/src/com/android/egg/landroid/PathTools.kt b/packages/EasterEgg/src/com/android/egg/landroid/PathTools.kt index 851064063d19..cd87335ab07b 100644 --- a/packages/EasterEgg/src/com/android/egg/landroid/PathTools.kt +++ b/packages/EasterEgg/src/com/android/egg/landroid/PathTools.kt @@ -32,6 +32,13 @@ fun createPolygon(radius: Float, sides: Int): Path { } } +fun createPolygonPoints(radius: Float, sides: Int): List<Vec2> { + val angleStep = PI2f / sides + return (0 until sides).map { i -> + Vec2(radius * cos(angleStep * i), radius * sin(angleStep * i)) + } +} + fun createStar(radius1: Float, radius2: Float, points: Int): Path { return Path().apply { val angleStep = PI2f / points @@ -46,15 +53,16 @@ fun createStar(radius1: Float, radius2: Float, points: Int): Path { } fun Path.parseSvgPathData(d: String) { - Regex("([A-Z])([-.,0-9e ]+)").findAll(d.trim()).forEach { + Regex("([A-Za-z])\\s*([-.,0-9e ]+)").findAll(d.trim()).forEach { val cmd = it.groups[1]!!.value val args = it.groups[2]?.value?.split(Regex("\\s+"))?.map { v -> v.toFloat() } ?: emptyList() - Log.d("Landroid", "cmd = $cmd, args = " + args.joinToString(",")) + // Log.d("Landroid", "cmd = $cmd, args = " + args.joinToString(",")) when (cmd) { "M" -> moveTo(args[0], args[1]) "C" -> cubicTo(args[0], args[1], args[2], args[3], args[4], args[5]) "L" -> lineTo(args[0], args[1]) + "l" -> relativeLineTo(args[0], args[1]) "Z" -> close() else -> Log.v("Landroid", "unsupported SVG command: $cmd") } diff --git a/packages/EasterEgg/src/com/android/egg/landroid/Randomness.kt b/packages/EasterEgg/src/com/android/egg/landroid/Randomness.kt index ebbb2bd1270c..2903534b0cb3 100644 --- a/packages/EasterEgg/src/com/android/egg/landroid/Randomness.kt +++ b/packages/EasterEgg/src/com/android/egg/landroid/Randomness.kt @@ -61,6 +61,7 @@ fun Random.nextFloatInRange(from: Float, until: Float): Float = /** Return a random float in the range [start, end). */ fun Random.nextFloatInRange(fromUntil: ClosedFloatingPointRange<Float>): Float = nextFloatInRange(fromUntil.start, fromUntil.endInclusive) + /** Return a random float in the range [first, second). */ fun Random.nextFloatInRange(fromUntil: Pair<Float, Float>): Float = nextFloatInRange(fromUntil.first, fromUntil.second) diff --git a/packages/EasterEgg/src/com/android/egg/landroid/Universe.kt b/packages/EasterEgg/src/com/android/egg/landroid/Universe.kt index 11dce613b0fb..1e5456966c6e 100644 --- a/packages/EasterEgg/src/com/android/egg/landroid/Universe.kt +++ b/packages/EasterEgg/src/com/android/egg/landroid/Universe.kt @@ -155,10 +155,7 @@ open class Universe(val namer: Namer, randomSeed: Long) : Simulator(randomSeed) speed = speed, color = Colors.Eigengrau4 ) - android.util.Log.v( - "Landroid", - "created planet $p with period $period and vel $speed" - ) + android.util.Log.v("Landroid", "created planet $p with period $period and vel $speed") val num = it + 1 p.description = "TEST PLANET #$num" p.atmosphere = "radius=$radius" @@ -215,10 +212,7 @@ open class Universe(val namer: Namer, randomSeed: Long) : Simulator(randomSeed) speed = speed, color = Colors.Eigengrau4 ) - android.util.Log.v( - "Landroid", - "created planet $p with period $period and vel $speed" - ) + android.util.Log.v("Landroid", "created planet $p with period $period and vel $speed") p.description = namer.describePlanet(rng) p.atmosphere = namer.describeAtmo(rng) p.flora = namer.describeLife(rng) @@ -302,7 +296,7 @@ open class Universe(val namer: Namer, randomSeed: Long) : Simulator(randomSeed) // && // vDiff < 100f ) { - val landing = Landing(ship, planet, a) + val landing = Landing(ship, planet, a, namer.describeActivity(rng, planet)) ship.landing = landing ship.velocity = planet.velocity add(landing) @@ -370,12 +364,15 @@ open class Universe(val namer: Namer, randomSeed: Long) : Simulator(randomSeed) } } -class Landing(val ship: Spacecraft, val planet: Planet, val angle: Float) : Constraint { - private val landingVector = Vec2.makeWithAngleMag(angle, ship.radius + planet.radius) +class Landing(var ship: Spacecraft?, val planet: Planet, val angle: Float, val text: String = "") : + Constraint { override fun solve(sim: Simulator, dt: Float) { - val desiredPos = planet.pos + landingVector - ship.pos = (ship.pos * 0.5f) + (desiredPos * 0.5f) // @@@ FIXME - ship.angle = angle + ship?.let { ship -> + val landingVector = Vec2.makeWithAngleMag(angle, ship.radius + planet.radius) + val desiredPos = planet.pos + landingVector + ship.pos = (ship.pos * 0.5f) + (desiredPos * 0.5f) // @@@ FIXME + ship.angle = angle + } } } @@ -435,6 +432,7 @@ class Spacecraft : Body() { val track = Track() var landing: Landing? = null + var autopilot: Autopilot? = null init { mass = SPACECRAFT_MASS @@ -448,23 +446,19 @@ class Spacecraft : Body() { var deltaV = MAIN_ENGINE_ACCEL * dt if (SCALED_THRUST) deltaV *= thrustMag.coerceIn(0f, 1f) - if (landing == null) { - // we are free in space, so we attempt to pivot toward the desired direction - // NOTE: no longer required thanks to FlightStick - // angle = thrust.angle() - } else - landing?.let { landing -> - if (launchClock == 0f) launchClock = sim.now + 1f /* @@@ TODO extract */ - - if (sim.now > launchClock) { - // first-stage to orbit has 1000x power - // deltaV *= 1000f - sim.remove(landing) - this.landing = null - } else { - deltaV = 0f - } + // check if we are currently attached to a landing + landing?.let { landing -> + // launch clock is 1 second long + if (launchClock == 0f) launchClock = sim.now + 1f /* @@@ TODO extract */ + + if (sim.now > launchClock) { + // detach from landing site + landing.ship = null + this.landing = null + } else { + deltaV = 0f } + } // this is it. impart thrust to the ship. // note that we always thrust in the forward direction diff --git a/packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt b/packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt index 6baf36ee3c8a..974784d418ca 100644 --- a/packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt +++ b/packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt @@ -28,11 +28,10 @@ import androidx.compose.ui.graphics.drawscope.scale import androidx.compose.ui.graphics.drawscope.translate import androidx.compose.ui.util.lerp import androidx.core.math.MathUtils.clamp +import com.android.egg.flags.Flags.flagFlag import java.lang.Float.max import kotlin.math.sqrt -import com.android.egg.flags.Flags.flagFlag - const val DRAW_ORBITS = true const val DRAW_GRAVITATIONAL_FIELDS = true const val DRAW_STAR_GRAVITATIONAL_FIELDS = true @@ -71,16 +70,6 @@ fun ZoomedDrawScope.drawUniverse(universe: VisibleUniverse) { with(universe) { triggerDraw.value // Please recompose when this value changes. - // star.drawZoomed(ds, zoom) - // planets.forEach { p -> - // p.drawZoomed(ds, zoom) - // if (p == follow) { - // drawCircle(Color.Red, 20f / zoom, p.pos) - // } - // } - // - // ship.drawZoomed(ds, zoom) - constraints.forEach { when (it) { is Landing -> drawLanding(it) @@ -89,13 +78,14 @@ fun ZoomedDrawScope.drawUniverse(universe: VisibleUniverse) { } drawStar(star) entities.forEach { - if (it === ship || it === star) return@forEach // draw the ship last + if (it === star) return@forEach // don't draw the star as a planet when (it) { - is Spacecraft -> drawSpacecraft(it) is Spark -> drawSpark(it) is Planet -> drawPlanet(it) + else -> Unit // draw these at a different time, or not at all } } + ship.autopilot?.let { drawAutopilot(it) } drawSpacecraft(ship) } } @@ -111,15 +101,6 @@ fun ZoomedDrawScope.drawContainer(container: Container) { pathEffect = PathEffect.dashPathEffect(floatArrayOf(8f / zoom, 8f / zoom), 0f) ) ) - // val path = Path().apply { - // fillType = PathFillType.EvenOdd - // addOval(Rect(center = Vec2.Zero, radius = container.radius)) - // addOval(Rect(center = Vec2.Zero, radius = container.radius + 10_000)) - // } - // drawPath( - // path = path, - // - // ) } fun ZoomedDrawScope.drawGravitationalField(planet: Planet) { @@ -226,23 +207,47 @@ Z """ ) } -val thrustPath = createPolygon(-3f, 3).also { it.translate(Vec2(-4f, 0f)) } +val spaceshipLegs = + Path().apply { + parseSvgPathData( + """ +M-7 -6.5 +l-3.5 0 +l-1 -2 +l 0 4 +l 1 -2 +Z +M-7 6.5 +l-3.5 0 +l-1 -2 +l 0 4 +l 1 -2 +Z +""" + ) + } +val thrustPath = createPolygon(-3f, 3).also { it.translate(Vec2(-5f, 0f)) } fun ZoomedDrawScope.drawSpacecraft(ship: Spacecraft) { with(ship) { rotateRad(angle, pivot = pos) { translate(pos.x, pos.y) { - // drawPath( - // path = createStar(200f, 100f, 3), - // color = Color.White, - // style = Stroke(width = 2f / zoom) - // ) + // new in V: little landing legs + ship.landing?.let { + drawPath( + path = spaceshipLegs, + color = Color(0xFFCCCCCC), + style = Stroke(width = 2f / this@drawSpacecraft.zoom) + ) + } + // draw the ship drawPath(path = spaceshipPath, color = Colors.Eigengrau) // fauxpaque drawPath( path = spaceshipPath, color = if (transit) Color.Black else Color.White, style = Stroke(width = 2f / this@drawSpacecraft.zoom) ) + // draw thrust if (thrust != Vec2.Zero) { drawPath( path = thrustPath, @@ -254,27 +259,8 @@ fun ZoomedDrawScope.drawSpacecraft(ship: Spacecraft) { ) ) } - // drawRect( - // topLeft = Offset(-1f, -1f), - // size = Size(2f, 2f), - // color = Color.Cyan, - // style = Stroke(width = 2f / zoom) - // ) - // drawLine( - // start = Vec2.Zero, - // end = Vec2(20f, 0f), - // color = Color.Cyan, - // strokeWidth = 2f / zoom - // ) } } - // // DEBUG: draw velocity vector - // drawLine( - // start = pos, - // end = pos + velocity, - // color = Color.Red, - // strokeWidth = 3f / zoom - // ) drawTrack(track) } } @@ -287,14 +273,15 @@ fun ZoomedDrawScope.drawLanding(landing: Landing) { val height = 80f rotateRad(landing.angle, pivot = v) { translate(v.x, v.y) { - drawPath( + val flagPath = Path().apply { moveTo(0f, 0f) lineTo(height, 0f) lineTo(height * 0.875f, height * 0.25f) lineTo(height * 0.75f, 0f) close() - }, Color.Yellow, style = Stroke(width = strokeWidth)) + } + drawPath(flagPath, Colors.Flag, style = Stroke(width = strokeWidth)) } } } @@ -311,10 +298,7 @@ fun ZoomedDrawScope.drawSpark(spark: Spark) { Spark.Style.DOT -> drawCircle(color, size, pos) Spark.Style.DOT_ABSOLUTE -> drawCircle(color, size, pos / zoom) Spark.Style.RING -> drawCircle(color, size, pos, style = Stroke(width = 1f / zoom)) - // drawPoints(listOf(pos), PointMode.Points, color, strokeWidth = 2f/zoom) - // drawCircle(color, 2f/zoom, pos) } - // drawCircle(Color.Gray, center = pos, radius = 1.5f / zoom) } } @@ -324,19 +308,9 @@ fun ZoomedDrawScope.drawTrack(track: Track) { drawPoints( positions, pointMode = PointMode.Lines, - color = Color.Green, + color = Colors.Track, strokeWidth = 1f / zoom ) - // if (positions.size < 2) return - // drawPath(Path() - // .apply { - // val p = positions[positions.size - 1] - // moveTo(p.x, p.y) - // positions.reversed().subList(1, positions.size).forEach { p -> - // lineTo(p.x, p.y) - // } - // }, - // color = Color.Green, style = Stroke(1f/zoom)) } else { if (positions.size < 2) return var prev: Vec2 = positions[positions.size - 1] @@ -349,3 +323,43 @@ fun ZoomedDrawScope.drawTrack(track: Track) { } } } + +fun ZoomedDrawScope.drawAutopilot(autopilot: Autopilot) { + val color = Colors.Autopilot.copy(alpha = 0.5f) + + autopilot.target?.let { target -> + val zoom = zoom + rotateRad(autopilot.universe.now * PI2f / 10f, target.pos) { + translate(target.pos.x, target.pos.y) { + drawPath( + path = + createPolygon( + radius = target.radius + autopilot.brakingDistance, + sides = 15 // Autopilot introduced in Android 15 + ), + color = color, + style = Stroke(1f / zoom) + ) + drawCircle( + color, + radius = target.radius + autopilot.landingAltitude / 2, + center = Vec2.Zero, + alpha = 0.25f, + style = Stroke(autopilot.landingAltitude) + ) + } + } + drawLine( + color, + start = autopilot.ship.pos, + end = autopilot.leadingPos, + strokeWidth = 1f / zoom + ) + drawCircle( + color, + radius = 5f / zoom, + center = autopilot.leadingPos, + style = Stroke(1f / zoom) + ) + } +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Flows.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Flows.kt index 83cb549bb3a2..61b8b7f73754 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Flows.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Flows.kt @@ -20,6 +20,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle +import kotlinx.coroutines.Job import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine @@ -61,10 +62,8 @@ fun <T> Flow<T>.collectLatestWithLifecycle( lifecycleOwner: LifecycleOwner, minActiveState: Lifecycle.State = Lifecycle.State.STARTED, action: suspend (value: T) -> Unit, -) { - lifecycleOwner.lifecycleScope.launch { - lifecycleOwner.repeatOnLifecycle(minActiveState) { - collectLatest(action) - } +): Job = lifecycleOwner.lifecycleScope.launch { + lifecycleOwner.repeatOnLifecycle(minActiveState) { + collectLatest(action) } } diff --git a/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java b/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java index ea3dbd925792..0e71a1b127e7 100644 --- a/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java +++ b/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java @@ -38,8 +38,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * Progres bar preference with a usage summary and a total summary. - * This preference shows number in usage summary with enlarged font size. + * Progress bar preference with a usage summary and a total summary. + * + * <p>This preference shows number in usage summary with enlarged font size. */ public class UsageProgressBarPreference extends Preference { @@ -48,18 +49,18 @@ public class UsageProgressBarPreference extends Preference { private CharSequence mUsageSummary; private CharSequence mTotalSummary; private CharSequence mBottomSummary; + private CharSequence mBottomSummaryContentDescription; private ImageView mCustomImageView; private int mPercent = -1; /** * Perform inflation from XML and apply a class-specific base style. * - * @param context The {@link Context} this is associated with, through which it can - * access the current theme, resources, {@link SharedPreferences}, etc. - * @param attrs The attributes of the XML tag that is inflating the preference + * @param context The {@link Context} this is associated with, through which it can access the + * current theme, resources, {@link SharedPreferences}, etc. + * @param attrs The attributes of the XML tag that is inflating the preference * @param defStyle An attribute in the current theme that contains a reference to a style - * resource that supplies default values for the view. Can be 0 to not - * look for defaults. + * resource that supplies default values for the view. Can be 0 to not look for defaults. */ public UsageProgressBarPreference(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); @@ -69,9 +70,9 @@ public class UsageProgressBarPreference extends Preference { /** * Perform inflation from XML and apply a class-specific base style. * - * @param context The {@link Context} this is associated with, through which it can - * access the current theme, resources, {@link SharedPreferences}, etc. - * @param attrs The attributes of the XML tag that is inflating the preference + * @param context The {@link Context} this is associated with, through which it can access the + * current theme, resources, {@link SharedPreferences}, etc. + * @param attrs The attributes of the XML tag that is inflating the preference */ public UsageProgressBarPreference(Context context, AttributeSet attrs) { super(context, attrs); @@ -114,9 +115,17 @@ public class UsageProgressBarPreference extends Preference { notifyChanged(); } + /** Set content description for the bottom summary. */ + public void setBottomSummaryContentDescription(CharSequence contentDescription) { + if (!TextUtils.equals(mBottomSummaryContentDescription, contentDescription)) { + mBottomSummaryContentDescription = contentDescription; + notifyChanged(); + } + } + /** Set percentage of the progress bar. */ public void setPercent(long usage, long total) { - if (usage > total) { + if (usage > total) { return; } if (total == 0L) { @@ -146,14 +155,13 @@ public class UsageProgressBarPreference extends Preference { /** * Binds the created View to the data for this preference. * - * <p>This is a good place to grab references to custom Views in the layout and set - * properties on them. + * <p>This is a good place to grab references to custom Views in the layout and set properties + * on them. * * <p>Make sure to call through to the superclass's implementation. * * @param holder The ViewHolder that provides references to the views to fill in. These views - * will be recycled, so you should not hold a reference to them after this method - * returns. + * will be recycled, so you should not hold a reference to them after this method returns. */ @Override public void onBindViewHolder(PreferenceViewHolder holder) { @@ -177,6 +185,9 @@ public class UsageProgressBarPreference extends Preference { bottomSummary.setVisibility(View.VISIBLE); bottomSummary.setMovementMethod(LinkMovementMethod.getInstance()); bottomSummary.setText(mBottomSummary); + if (!TextUtils.isEmpty(mBottomSummaryContentDescription)) { + bottomSummary.setContentDescription(mBottomSummaryContentDescription); + } } final ProgressBar progressBar = (ProgressBar) holder.findViewById(android.R.id.progress); @@ -205,9 +216,12 @@ public class UsageProgressBarPreference extends Preference { final Matcher matcher = mNumberPattern.matcher(summary); if (matcher.find()) { - final SpannableString spannableSummary = new SpannableString(summary); - spannableSummary.setSpan(new AbsoluteSizeSpan(64, true /* dip */), matcher.start(), - matcher.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + final SpannableString spannableSummary = new SpannableString(summary); + spannableSummary.setSpan( + new AbsoluteSizeSpan(64, true /* dip */), + matcher.start(), + matcher.end(), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); return spannableSummary; } return summary; diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml index a72322350b4c..95586eaf9da5 100644 --- a/packages/SettingsLib/res/values-be/strings.xml +++ b/packages/SettingsLib/res/values-be/strings.xml @@ -84,7 +84,7 @@ <string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string> <string name="bluetooth_disconnected" msgid="7739366554710388701">"Адключана"</string> <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Адключэнне..."</string> - <string name="bluetooth_connecting" msgid="5871702668260192755">"Злучэнне..."</string> + <string name="bluetooth_connecting" msgid="5871702668260192755">"Падключэнне..."</string> <string name="bluetooth_connected" msgid="8065345572198502293">"Падключана прылада <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string> <string name="bluetooth_pairing" msgid="4269046942588193600">"Спалучэнне..."</string> <string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"Падключана прылада <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> (без званкоў)"</string> diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index 3c63119497df..0b96faa7f6b4 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -127,7 +127,7 @@ <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transferencia de archivos"</string> <string name="bluetooth_profile_hid" msgid="2969922922664315866">"Dispositivo de entrada"</string> <string name="bluetooth_profile_pan" msgid="1006235139308318188">"Acceso a Internet"</string> - <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"Acceso a contactos e historial de llamadas"</string> + <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"Permitir acceso a contactos e historial de llamadas"</string> <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"La información se usará para avisos de llamada y más"</string> <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Compartir conexión a Internet"</string> <string name="bluetooth_profile_map" msgid="8907204701162107271">"Mensajes de texto"</string> diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml index 647309bd8ec7..a0dc830dc58f 100644 --- a/packages/SettingsLib/res/values-fi/strings.xml +++ b/packages/SettingsLib/res/values-fi/strings.xml @@ -632,7 +632,7 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Profiilin tiedot"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Ennen kuin voit luoda rajoitetun profiilin, määritä näytön lukitus, joka suojelee sovelluksiasi ja henkilökohtaisia tietojasi."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Aseta lukitus"</string> - <string name="user_switch_to_user" msgid="6975428297154968543">"Vaihda tähän käyttäjään: <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="user_switch_to_user" msgid="6975428297154968543">"Vaihda käyttäjään: <xliff:g id="USER_NAME">%s</xliff:g>"</string> <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Luodaan uutta käyttäjää…"</string> <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Luodaan uutta vierasta…"</string> <string name="add_user_failed" msgid="4809887794313944872">"Uuden käyttäjän luominen epäonnistui"</string> diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml index bfec96c218b2..f80ec8d1cb00 100644 --- a/packages/SettingsLib/res/values-pa/strings.xml +++ b/packages/SettingsLib/res/values-pa/strings.xml @@ -422,7 +422,7 @@ <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ਐਪ ਵੱਲੋਂ ਵੈਧ ਚੈਨਲ ਤੋਂ ਬਿਨਾਂ ਸੂਚਨਾ ਪੋਸਟ ਕਰਨ \'ਤੇ ਸਕ੍ਰੀਨ \'ਤੇ ਚਿਤਾਵਨੀ ਦਿਖਾਉਂਦੀ ਹੈ"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"ਐਪਾਂ ਨੂੰ ਜ਼ਬਰਦਸਤੀ ਬਾਹਰੀ ਸਟੋਰੇਜ \'ਤੇ ਆਗਿਆ ਦਿਓ"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"ਮੈਨੀਫੈਸਟ ਮੁੱਲਾਂ ਦੀ ਪਰਵਾਹ ਕੀਤੇ ਬਿਨਾਂ, ਕਿਸੇ ਵੀ ਐਪ ਨੂੰ ਬਾਹਰੀ ਸਟੋਰੇਜ \'ਤੇ ਲਿਖਣ ਦੇ ਯੋਗ ਬਣਾਉਂਦੀ ਹੈ"</string> - <string name="force_resizable_activities" msgid="7143612144399959606">"ਵਿੰਡੋ ਮੁਤਾਬਕ ਸਰਗਰਮੀਆਂ ਦਾ ਆਕਾਰ ਬਦਲਣ ਦਿਓ"</string> + <string name="force_resizable_activities" msgid="7143612144399959606">"ਸਰਗਰਮੀਆਂ ਨੂੰ ਜ਼ਬਰਦਸਤੀ ਆਕਾਰ ਬਦਲਣਯੋਗ ਬਣਾਓ"</string> <string name="force_resizable_activities_summary" msgid="2490382056981583062">"ਮੈਨੀਫ਼ੈਸਟ ਮੁੱਲਾਂ ਦੀ ਪਰਵਾਹ ਕੀਤੇ ਬਿਨਾਂ, ਮਲਟੀ-ਵਿੰਡੋ ਲਈ ਸਾਰੀਆਂ ਸਰਗਰਮੀਆਂ ਨੂੰ ਆਕਾਰ ਬਦਲਣਯੋਗ ਬਣਾਓ।"</string> <string name="enable_freeform_support" msgid="7599125687603914253">"ਫ੍ਰੀਫਾਰਮ ਵਿੰਡੋਜ਼ ਨੂੰ ਚਾਲੂ ਕਰੋ"</string> <string name="enable_freeform_support_summary" msgid="1822862728719276331">"ਪ੍ਰਯੋਗਮਈ ਫ੍ਰੀਫਾਰਮ ਵਿੰਡੋਜ਼ ਲਈ ਸਮਰਥਨ ਨੂੰ ਚਾਲੂ ਕਰੋ।"</string> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index e76be70d5c44..8babb8be0a39 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -288,7 +288,7 @@ <string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"Zezwolić na zdjęcie blokady OEM?"</string> <string name="confirm_enable_oem_unlock_text" msgid="854131050791011970">"UWAGA: gdy to ustawienie jest włączone, na urządzeniu nie będą działać funkcje ochrony."</string> <string name="mock_location_app" msgid="6269380172542248304">"Aplikacja do pozorowania lokalizacji"</string> - <string name="mock_location_app_not_set" msgid="6972032787262831155">"Nie wybrano aplikacji do pozorowania lokalizacji"</string> + <string name="mock_location_app_not_set" msgid="6972032787262831155">"Nie wybrano aplikacji"</string> <string name="mock_location_app_set" msgid="4706722469342913843">"Aplikacja do pozorowania lokalizacji: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="debug_networking_category" msgid="6829757985772659599">"Sieci"</string> <string name="wifi_display_certification" msgid="1805579519992520381">"Certyfikacja wyświetlacza bezprzewodowego"</string> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index 1c76fdd9191a..4bddeb9a1cd0 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -94,7 +94,7 @@ <string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"Conectat (fără telefon), baterie <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> <string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"Conectat (fără conținut media), baterie <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"Conectat (fără telefon sau conținut media), baterie <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> - <string name="bluetooth_active_battery_level" msgid="2685517576209066008">"Activ. Nivelul bateriei <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> + <string name="bluetooth_active_battery_level" msgid="2685517576209066008">"Activ. Nivelul bateriei: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_battery_level_untethered" msgid="4961338936672922617">"Activ. Nivelul bateriei din stânga: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, dreapta: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_active_battery_level_untethered_left" msgid="2895644748625343977">"Activ. Nivelul bateriei din stânga: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_battery_level_untethered_right" msgid="7407517998880370179">"Activ. Nivelul bateriei din dreapta: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java index cdb87404b016..063807abeb0a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java @@ -17,6 +17,8 @@ package com.android.settingslib.media; import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_TRANSFER; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHearingAid; @@ -37,21 +39,14 @@ public class BluetoothMediaDevice extends MediaDevice { private static final String TAG = "BluetoothMediaDevice"; - private CachedBluetoothDevice mCachedDevice; + private final CachedBluetoothDevice mCachedDevice; private final AudioManager mAudioManager; BluetoothMediaDevice( - Context context, - CachedBluetoothDevice device, - MediaRoute2Info info) { - this(context, device, info, null); - } - - BluetoothMediaDevice( - Context context, - CachedBluetoothDevice device, - MediaRoute2Info info, - RouteListingPreference.Item item) { + @NonNull Context context, + @NonNull CachedBluetoothDevice device, + @Nullable MediaRoute2Info info, + @Nullable RouteListingPreference.Item item) { super(context, info, item); mCachedDevice = device; mAudioManager = context.getSystemService(AudioManager.class); diff --git a/packages/SettingsLib/src/com/android/settingslib/media/ComplexMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/ComplexMediaDevice.java index 338fb872650c..a87daf90a84f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/ComplexMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/ComplexMediaDevice.java @@ -16,6 +16,8 @@ package com.android.settingslib.media; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.graphics.drawable.Drawable; import android.media.MediaRoute2Info; @@ -32,9 +34,9 @@ public class ComplexMediaDevice extends MediaDevice { private final String mSummary = ""; ComplexMediaDevice( - Context context, - MediaRoute2Info info, - RouteListingPreference.Item item) { + @NonNull Context context, + @NonNull MediaRoute2Info info, + @Nullable RouteListingPreference.Item item) { super(context, info, item); } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java index 1347dd131f69..21873ef3aeab 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java @@ -26,6 +26,8 @@ import static android.media.MediaRoute2Info.TYPE_REMOTE_TABLET; import static android.media.MediaRoute2Info.TYPE_REMOTE_TABLET_DOCKED; import static android.media.MediaRoute2Info.TYPE_REMOTE_TV; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.graphics.drawable.Drawable; import android.media.MediaRoute2Info; @@ -43,17 +45,13 @@ public class InfoMediaDevice extends MediaDevice { private static final String TAG = "InfoMediaDevice"; InfoMediaDevice( - Context context, - MediaRoute2Info info, - RouteListingPreference.Item item) { + @NonNull Context context, + @NonNull MediaRoute2Info info, + @Nullable RouteListingPreference.Item item) { super(context, info, item); initDeviceRecord(); } - InfoMediaDevice(Context context, MediaRoute2Info info) { - this(context, info, null); - } - @Override public String getName() { return mRouteInfo.getName().toString(); diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java index cfa825bbb1c4..72a60fbc9fea 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java @@ -570,7 +570,7 @@ public class LocalMediaManager implements BluetoothCallback { final CachedBluetoothDevice cachedDevice = cachedDeviceManager.findDevice(device); if (isBondedMediaDevice(cachedDevice) && isMutingExpectedDevice(cachedDevice)) { - return new BluetoothMediaDevice(mContext, cachedDevice, null); + return new BluetoothMediaDevice(mContext, cachedDevice, null, /* item */ null); } } return null; @@ -617,7 +617,7 @@ public class LocalMediaManager implements BluetoothCallback { mDisconnectedMediaDevices.clear(); for (CachedBluetoothDevice cachedDevice : cachedBluetoothDeviceList) { final MediaDevice mediaDevice = - new BluetoothMediaDevice(mContext, cachedDevice, null); + new BluetoothMediaDevice(mContext, cachedDevice, null, /* item */ null); if (!mMediaDevices.contains(mediaDevice)) { cachedDevice.registerCallback(mDeviceAttributeChangeCallback); mDisconnectedMediaDevices.add(mediaDevice); diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java index 0c4cf769ca90..ce1f29766bed 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java @@ -49,6 +49,8 @@ import static android.media.RouteListingPreference.Item.SUBTEXT_UNAUTHORIZED; import static com.android.settingslib.media.LocalMediaManager.MediaDeviceState.STATE_SELECTED; import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_TRANSFER; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.drawable.Drawable; @@ -123,9 +125,9 @@ public abstract class MediaDevice implements Comparable<MediaDevice> { protected final RouteListingPreference.Item mItem; MediaDevice( - Context context, - MediaRoute2Info info, - RouteListingPreference.Item item) { + @NonNull Context context, + @Nullable MediaRoute2Info info, + @Nullable RouteListingPreference.Item item) { mContext = context; mRouteInfo = info; mItem = item; diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java index ba9180db0887..9eaf8d3838d8 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java @@ -29,6 +29,8 @@ import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET; import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_TRANSFER; import android.Manifest; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; @@ -40,7 +42,6 @@ import android.media.RouteListingPreference; import android.os.SystemProperties; import android.util.Log; -import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import com.android.settingslib.R; @@ -100,17 +101,6 @@ public class PhoneMediaDevice extends MediaDevice { R.string.media_transfer_external_device_name); break; case TYPE_HDMI_ARC: - if (isTv) { - String deviceName = getHdmiOutDeviceName(context); - if (deviceName != null) { - name = deviceName; - } else { - name = context.getString(R.string.tv_media_transfer_arc_fallback_title); - } - } else { - name = context.getString(R.string.media_transfer_external_device_name); - } - break; case TYPE_HDMI_EARC: if (isTv) { String deviceName = getHdmiOutDeviceName(context); @@ -130,14 +120,10 @@ public class PhoneMediaDevice extends MediaDevice { return name.toString(); } - PhoneMediaDevice(Context context, MediaRoute2Info info) { - this(context, info, null); - } - PhoneMediaDevice( - Context context, - MediaRoute2Info info, - RouteListingPreference.Item item) { + @NonNull Context context, + @NonNull MediaRoute2Info info, + @Nullable RouteListingPreference.Item item) { super(context, info, item); mDeviceIconUtil = new DeviceIconUtil(mContext); initDeviceRecord(); diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt index 8204569ce2f8..20b949f4a30f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt +++ b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt @@ -37,6 +37,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterIsInstance @@ -161,6 +162,7 @@ class AudioRepositoryImpl( }, volumeSettingChanges(audioStream), ) + .conflate() .map { getCurrentAudioStream(audioStream) } .onStart { emit(getCurrentAudioStream(audioStream)) } .flowOn(backgroundCoroutineContext) @@ -184,10 +186,11 @@ class AudioRepositoryImpl( } } - override suspend fun setVolume(audioStream: AudioStream, volume: Int) = + override suspend fun setVolume(audioStream: AudioStream, volume: Int) { withContext(backgroundCoroutineContext) { audioManager.setStreamVolume(audioStream.value, volume, 0) } + } override suspend fun setMuted(audioStream: AudioStream, isMuted: Boolean): Boolean { return withContext(backgroundCoroutineContext) { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java index 0665308fdbfb..6647a278a6bd 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java @@ -65,7 +65,7 @@ public class InfoMediaDeviceTest { MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; - mInfoMediaDevice = new InfoMediaDevice(mContext, mRouteInfo); + mInfoMediaDevice = new InfoMediaDevice(mContext, mRouteInfo, /* item */ null); } @Test diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java index ce07fe9fdf0a..c9b35a0ae833 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java @@ -559,7 +559,7 @@ public class InfoMediaManagerTest { routingSessionInfos.add(info); final MediaRoute2Info route2Info = mock(MediaRoute2Info.class); - final MediaDevice device = new InfoMediaDevice(mContext, route2Info); + final MediaDevice device = new InfoMediaDevice(mContext, route2Info, /* item */ null); final List<String> list = new ArrayList<>(); list.add(TEST_ID); @@ -580,7 +580,7 @@ public class InfoMediaManagerTest { routingSessionInfos.add(info); final MediaRoute2Info route2Info = mock(MediaRoute2Info.class); - final MediaDevice device = new InfoMediaDevice(mContext, route2Info); + final MediaDevice device = new InfoMediaDevice(mContext, route2Info, /* item */ null); final List<String> list = new ArrayList<>(); list.add("fake_id"); @@ -602,7 +602,7 @@ public class InfoMediaManagerTest { routingSessionInfos.add(info); final MediaRoute2Info route2Info = mock(MediaRoute2Info.class); - final MediaDevice device = new InfoMediaDevice(mContext, route2Info); + final MediaDevice device = new InfoMediaDevice(mContext, route2Info, /* item */ null); final List<String> list = new ArrayList<>(); list.add(TEST_ID); @@ -623,7 +623,7 @@ public class InfoMediaManagerTest { routingSessionInfos.add(info); final MediaRoute2Info route2Info = mock(MediaRoute2Info.class); - final MediaDevice device = new InfoMediaDevice(mContext, route2Info); + final MediaDevice device = new InfoMediaDevice(mContext, route2Info, /* item */ null); final List<String> list = new ArrayList<>(); list.add("fake_id"); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java index 12541bb51cc8..a30d6a787971 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java @@ -135,8 +135,8 @@ public class LocalMediaManagerTest { .when(mInfoMediaManager) .getRoutingSessionsForPackage(); - mInfoMediaDevice1 = spy(new InfoMediaDevice(mContext, mRouteInfo1)); - mInfoMediaDevice2 = new InfoMediaDevice(mContext, mRouteInfo2); + mInfoMediaDevice1 = spy(new InfoMediaDevice(mContext, mRouteInfo1, /* item */ null)); + mInfoMediaDevice2 = new InfoMediaDevice(mContext, mRouteInfo2, /* item */ null); mLocalMediaManager = new LocalMediaManager( mContext, mLocalBluetoothManager, mInfoMediaManager, TEST_PACKAGE_NAME); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java index 098ab162c225..3d16d6f1cd56 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java @@ -171,17 +171,17 @@ public class MediaDeviceTest { mBluetoothMediaDevice1 = new BluetoothMediaDevice( - mContext, mCachedDevice1, mBluetoothRouteInfo1); + mContext, mCachedDevice1, mBluetoothRouteInfo1, /* item */ null); mBluetoothMediaDevice2 = new BluetoothMediaDevice( - mContext, mCachedDevice2, mBluetoothRouteInfo2); + mContext, mCachedDevice2, mBluetoothRouteInfo2, /* item */ null); mBluetoothMediaDevice3 = new BluetoothMediaDevice( - mContext, mCachedDevice3, mBluetoothRouteInfo3); - mInfoMediaDevice1 = new InfoMediaDevice(mContext, mRouteInfo1); - mInfoMediaDevice2 = new InfoMediaDevice(mContext, mRouteInfo2); - mInfoMediaDevice3 = new InfoMediaDevice(mContext, mRouteInfo3); - mPhoneMediaDevice = new PhoneMediaDevice(mContext, mPhoneRouteInfo); + mContext, mCachedDevice3, mBluetoothRouteInfo3, /* item */ null); + mInfoMediaDevice1 = new InfoMediaDevice(mContext, mRouteInfo1, /* item */ null); + mInfoMediaDevice2 = new InfoMediaDevice(mContext, mRouteInfo2, /* item */ null); + mInfoMediaDevice3 = new InfoMediaDevice(mContext, mRouteInfo3, /* item */ null); + mPhoneMediaDevice = new PhoneMediaDevice(mContext, mPhoneRouteInfo, /* item */ null); } @Test @@ -316,7 +316,7 @@ public class MediaDeviceTest { when(phoneRouteInfo.getType()).thenReturn(TYPE_WIRED_HEADPHONES); final PhoneMediaDevice phoneMediaDevice = - new PhoneMediaDevice(mContext, phoneRouteInfo); + new PhoneMediaDevice(mContext, phoneRouteInfo, /* item */ null); mMediaDevices.add(mBluetoothMediaDevice1); mMediaDevices.add(phoneMediaDevice); @@ -332,7 +332,7 @@ public class MediaDeviceTest { when(phoneRouteInfo.getType()).thenReturn(TYPE_WIRED_HEADPHONES); final PhoneMediaDevice phoneMediaDevice = - new PhoneMediaDevice(mContext, phoneRouteInfo); + new PhoneMediaDevice(mContext, phoneRouteInfo, /* item */ null); mMediaDevices.add(mInfoMediaDevice1); mMediaDevices.add(phoneMediaDevice); @@ -483,7 +483,7 @@ public class MediaDeviceTest { public void getFeatures_noRouteInfo_returnEmptyList() { mBluetoothMediaDevice1 = new BluetoothMediaDevice( - mContext, mCachedDevice1, /* MediaRoute2Info */ null); + mContext, mCachedDevice1, /* MediaRoute2Info */ null, /* item */ null); assertThat(mBluetoothMediaDevice1.getFeatures().size()).isEqualTo(0); } diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java index 1706a6f6b1d4..4125a81f9bbc 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java @@ -101,7 +101,6 @@ public class GlobalSettings { Settings.Global.Wearable.AMBIENT_TILT_TO_WAKE, Settings.Global.Wearable.AMBIENT_TOUCH_TO_WAKE, Settings.Global.Wearable.GESTURE_TOUCH_AND_HOLD_WATCH_FACE_ENABLED, - Settings.Global.Wearable.BATTERY_SAVER_MODE, Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS, Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_SET_BY_USER, Settings.Global.Wearable.DYNAMIC_COLOR_THEME_ENABLED, diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java index 11fa8f43290d..5245456d98c2 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java @@ -79,6 +79,7 @@ public class SystemSettings { Settings.System.SIP_CALL_OPTIONS, Settings.System.SIP_RECEIVE_CALLS, Settings.System.POINTER_SPEED, + Settings.System.POINTER_FILL_STYLE, Settings.System.VIBRATE_ON, Settings.System.VIBRATE_WHEN_RINGING, Settings.System.RINGTONE, diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java index 011b42f451bc..2c3be4c10f5a 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java @@ -26,6 +26,8 @@ import static android.provider.settings.validators.SettingsValidators.NON_NEGATI import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.URI_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.VIBRATION_INTENSITY_VALIDATOR; +import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BEGIN; +import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_END; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; @@ -206,6 +208,9 @@ public class SystemSettingsValidators { VALIDATORS.put(System.SIP_ADDRESS_ONLY, BOOLEAN_VALIDATOR); VALIDATORS.put(System.SIP_ASK_ME_EACH_TIME, BOOLEAN_VALIDATOR); VALIDATORS.put(System.POINTER_SPEED, new InclusiveFloatRangeValidator(-7, 7)); + VALIDATORS.put(System.POINTER_FILL_STYLE, + new InclusiveIntegerRangeValidator(POINTER_ICON_VECTOR_STYLE_FILL_BEGIN, + POINTER_ICON_VECTOR_STYLE_FILL_END)); VALIDATORS.put(System.TOUCHPAD_POINTER_SPEED, new InclusiveIntegerRangeValidator(-7, 7)); VALIDATORS.put(System.TOUCHPAD_NATURAL_SCROLLING, BOOLEAN_VALIDATOR); VALIDATORS.put(System.TOUCHPAD_TAP_TO_CLICK, BOOLEAN_VALIDATOR); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 70ce202c289a..625b8e4e2911 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -2911,6 +2911,11 @@ class SettingsProtoDumpUtil { // Settings.System.NOTIFICATIONS_USE_RING_VOLUME intentionally excluded since it's deprecated. p.end(notificationToken); + final long pointerToken = p.start(SystemSettingsProto.POINTER); + dumpSetting(s, p, + Settings.System.POINTER_FILL_STYLE, + SystemSettingsProto.Pointer.POINTER_FILL_STYLE); + p.end(pointerToken); dumpSetting(s, p, Settings.System.POINTER_SPEED, SystemSettingsProto.POINTER_SPEED); diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 4ec170dda6f3..c6ae96ed193d 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -595,6 +595,7 @@ public class SettingsBackupTest { Settings.Global.Wearable.MOBILE_SIGNAL_DETECTOR, Settings.Global.Wearable.AMBIENT_LOW_BIT_ENABLED_DEV, Settings.Global.Wearable.AMBIENT_TILT_TO_BRIGHT, + Settings.Global.Wearable.BATTERY_SAVER_MODE, Settings.Global.Wearable.DECOMPOSABLE_WATCHFACE, Settings.Global.Wearable.AMBIENT_FORCE_WHEN_DOCKED, Settings.Global.Wearable.AMBIENT_LOW_BIT_ENABLED, diff --git a/packages/SoundPicker/res/values-vi/strings.xml b/packages/SoundPicker/res/values-vi/strings.xml index bed0e9687271..b6f8793cf5d0 100644 --- a/packages/SoundPicker/res/values-vi/strings.xml +++ b/packages/SoundPicker/res/values-vi/strings.xml @@ -20,7 +20,7 @@ <string name="notification_sound_default" msgid="8133121186242636840">"Âm thanh thông báo mặc định"</string> <string name="alarm_sound_default" msgid="4787646764557462649">"Âm thanh chuông báo mặc định"</string> <string name="add_ringtone_text" msgid="6642389991738337529">"Thêm nhạc chuông"</string> - <string name="add_alarm_text" msgid="3545497316166999225">"Thêm báo thức"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Thêm chuông báo"</string> <string name="add_notification_text" msgid="4431129543300614788">"Thêm thông báo"</string> <string name="delete_ringtone_text" msgid="201443984070732499">"Xóa"</string> <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Không thể thêm nhạc chuông tùy chỉnh"</string> diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 07a00fb7e8e3..c2c334bf896a 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -483,6 +483,7 @@ android_library { "androidx.compose.material_material-icons-extended", "androidx.activity_activity-compose", "androidx.compose.animation_animation-graphics", + "androidx.lifecycle_lifecycle-viewmodel-compose", "device_policy_aconfig_flags_lib", ], libs: [ @@ -644,6 +645,7 @@ android_library { "androidx.compose.material_material-icons-extended", "androidx.activity_activity-compose", "androidx.compose.animation_animation-graphics", + "androidx.lifecycle_lifecycle-viewmodel-compose", "TraceurCommon", ], } diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 9c58371a387d..a9c4399d81ab 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -475,6 +475,15 @@ android:exported="false" android:noHistory="true" /> + <activity android:name=".touchpad.tutorial.ui.view.TouchpadTutorialActivity" + android:exported="true" + android:theme="@style/Theme.AppCompat.NoActionBar"> + <intent-filter> + <action android:name="com.android.systemui.action.TOUCHPAD_TUTORIAL"/> + <category android:name="android.intent.category.DEFAULT"/> + </intent-filter> + </activity> + <service android:name=".screenshot.appclips.AppClipsScreenshotHelperService" android:exported="false" android:singleUser="true" diff --git a/packages/SystemUI/aconfig/communal.aconfig b/packages/SystemUI/aconfig/communal.aconfig index 2e9af7e3a763..afcd8a9624c8 100644 --- a/packages/SystemUI/aconfig/communal.aconfig +++ b/packages/SystemUI/aconfig/communal.aconfig @@ -7,3 +7,13 @@ flag { description: "Enables the communal hub experience" bug: "304584416" } + +flag { + name: "enable_widget_picker_size_filter" + namespace: "communal" + description: "Enables passing a size filter to the widget picker" + bug: "345482907" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index f84f6274b1e6..4311e7968e91 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -1064,3 +1064,23 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "dozeui_scheduling_alarms_background_execution" + namespace: "systemui" + description: "Decide whether to execute binder calls to schedule alarms in background thread" + bug: "330492575" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "notification_pulsing_fix" + namespace: "systemui" + description: "Allow showing new pulsing notifications when the device is already pulsing." + bug: "335560575" + metadata { + purpose: PURPOSE_BUGFIX + } +} 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 c32938497147..a1f8f1b32f77 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 @@ -1,6 +1,6 @@ package com.android.systemui.communal.ui.compose -import androidx.compose.animation.core.LinearEasing +import androidx.compose.animation.core.CubicBezierEasing import androidx.compose.animation.core.RepeatMode import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.infiniteRepeatable @@ -20,20 +20,18 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect 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 import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.composed import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.BlendMode import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color -import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.CommunalSwipeDetector @@ -217,6 +215,7 @@ private fun SceneScope.CommunalScene( CommunalBackgroundType.DEFAULT -> DefaultBackground(colors = colors) CommunalBackgroundType.STATIC_GRADIENT -> StaticLinearGradient() CommunalBackgroundType.ANIMATED -> AnimatedLinearGradient() + CommunalBackgroundType.NONE -> BackgroundTopScrim() } } with(content) { Content(modifier = modifier) } @@ -252,7 +251,8 @@ private fun BoxScope.AnimatedLinearGradient() { val colors = LocalAndroidColorScheme.current Box( Modifier.matchParentSize() - .animatedGradientBackground(colors = listOf(colors.primary, colors.primaryContainer)) + .background(colors.primary) + .animatedRadialGradientBackground(colors.primary, colors.primaryContainer) ) BackgroundTopScrim() } @@ -265,29 +265,76 @@ private fun BoxScope.BackgroundTopScrim() { Box(Modifier.matchParentSize().alpha(0.34f).background(scrimOnTopColor)) } -/** Modifier which sets the background of a composable to an animated gradient */ +/** The duration to use for the gradient background animation. */ +private const val ANIMATION_DURATION_MS = 10_000 + +/** The offset to use in order to place the center of each gradient offscreen. */ +private val ANIMATION_OFFSCREEN_OFFSET = 128.dp + +/** Modifier which creates two radial gradients that animate up and down. */ @Composable -private fun Modifier.animatedGradientBackground(colors: List<Color>): Modifier = composed { - var size by remember { mutableStateOf(IntSize.Zero) } - val transition = rememberInfiniteTransition(label = "scrim background") - val startOffsetX by - transition.animateFloat( - initialValue = -size.width.toFloat(), - targetValue = size.width.toFloat(), +fun Modifier.animatedRadialGradientBackground(toColor: Color, fromColor: Color): Modifier { + val density = LocalDensity.current + val infiniteTransition = rememberInfiniteTransition(label = "radial gradient transition") + val centerFraction by + infiniteTransition.animateFloat( + initialValue = 0f, + targetValue = 1f, animationSpec = infiniteRepeatable( - animation = tween(durationMillis = 5_000, easing = LinearEasing), - repeatMode = RepeatMode.Reverse, + animation = + tween( + durationMillis = ANIMATION_DURATION_MS, + easing = CubicBezierEasing(0.33f, 0f, 0.67f, 1f), + ), + repeatMode = RepeatMode.Reverse ), - label = "scrim start offset" + label = "radial gradient center fraction" ) - background( + + // Offset to place the center of the gradients offscreen. This is applied to both the + // x and y coordinates. + val offsetPx = remember(density) { with(density) { ANIMATION_OFFSCREEN_OFFSET.toPx() } } + + return drawBehind { + val gradientRadius = (size.width / 2) + offsetPx + val totalHeight = size.height + 2 * offsetPx + + val leftCenter = + Offset( + x = -offsetPx, + y = totalHeight * centerFraction - offsetPx, + ) + val rightCenter = + Offset( + x = offsetPx + size.width, + y = totalHeight * (1f - centerFraction) - offsetPx, + ) + + // Right gradient + drawCircle( brush = - Brush.linearGradient( - colors = colors, - start = Offset(startOffsetX, 0f), - end = Offset(startOffsetX + size.width.toFloat(), size.height.toFloat()), - ) + Brush.radialGradient( + colors = listOf(fromColor, toColor), + center = rightCenter, + radius = gradientRadius + ), + center = rightCenter, + radius = gradientRadius, + blendMode = BlendMode.SrcAtop, ) - .onGloballyPositioned { size = it.size } + + // Left gradient + drawCircle( + brush = + Brush.radialGradient( + colors = listOf(fromColor, toColor), + center = leftCenter, + radius = gradientRadius + ), + center = leftCenter, + radius = gradientRadius, + blendMode = BlendMode.SrcAtop, + ) + } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QSMediaMeasurePolicy.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QSMediaMeasurePolicy.kt new file mode 100644 index 000000000000..8fe870393dd1 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QSMediaMeasurePolicy.kt @@ -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 com.android.systemui.qs.ui.composable + +import androidx.compose.ui.layout.Measurable +import androidx.compose.ui.layout.MeasurePolicy +import androidx.compose.ui.layout.MeasureResult +import androidx.compose.ui.layout.MeasureScope +import androidx.compose.ui.layout.layoutId +import androidx.compose.ui.unit.Constraints +import androidx.compose.ui.unit.Density +import androidx.compose.ui.util.fastFirst +import kotlin.math.max + +/* + This layout puts QS taking all horizontal space and media taking the right half of the space. + However, QS (in QSPanel) puts an empty view taking half the horizontal space so that it can be + covered by media. +*/ +class QSMediaMeasurePolicy( + val qsHeight: () -> Int, + val mediaVerticalOffset: Density.() -> Int = { 0 }, +) : MeasurePolicy { + override fun MeasureScope.measure( + measurables: List<Measurable>, + constraints: Constraints + ): MeasureResult { + val qsMeasurable = measurables.fastFirst { it.layoutId == LayoutId.QS } + val mediaMeasurable = measurables.fastFirst { it.layoutId == LayoutId.Media } + + val qsPlaceable = qsMeasurable.measure(constraints) + val mediaPlaceable = + mediaMeasurable.measure(constraints.copy(maxWidth = constraints.maxWidth / 2)) + + val width = qsPlaceable.width + val height = max(qsHeight(), mediaPlaceable.height) + return layout(width, height) { + qsPlaceable.placeRelative(0, 0) + mediaPlaceable.placeRelative(width / 2, mediaVerticalOffset()) + } + } + + enum class LayoutId { + QS, + Media, + } +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt index 8195df3b01e8..8058dcde8cf8 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt @@ -29,6 +29,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.drawWithContent import androidx.compose.ui.layout.layout import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.ElementKey @@ -62,11 +63,21 @@ object QuickSettings { object SharedValues { val TilesSquishiness = ValueKey("QuickSettingsTileSquishiness") + object SquishinessValues { val Default = 1f val LockscreenSceneStarting = 0f val GoneSceneStarting = 0.3f } + + val MediaLandscapeTopOffset = ValueKey("MediaLandscapeTopOffset") + + object MediaOffset { + val InQQS = 0.dp + // Brightness + padding + val InQS = 92.dp + val Default = 0.dp + } } } @@ -77,8 +88,8 @@ private fun SceneScope.stateForQuickSettingsContent( return when (val transitionState = layoutState.transitionState) { is TransitionState.Idle -> { when (transitionState.currentScene) { - Scenes.Shade -> QSSceneAdapter.State.QQS.takeUnless { isSplitShade } - ?: QSSceneAdapter.State.QS + Scenes.Shade -> + QSSceneAdapter.State.QQS.takeUnless { isSplitShade } ?: QSSceneAdapter.State.QS Scenes.QuickSettings -> QSSceneAdapter.State.QS else -> QSSceneAdapter.State.CLOSED } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt index 0ee485c496be..1b49b6702275 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt @@ -46,6 +46,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect @@ -56,6 +57,8 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.CompositingStrategy import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.layout.Layout +import androidx.compose.ui.layout.layoutId import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.res.colorResource @@ -63,6 +66,7 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.TransitionState +import com.android.compose.animation.scene.animateSceneDpAsState import com.android.compose.animation.scene.animateSceneFloatAsState import com.android.compose.modifiers.thenIf import com.android.compose.windowsizeclass.LocalWindowSizeClass @@ -79,6 +83,8 @@ import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.media.dagger.MediaModule import com.android.systemui.notifications.ui.composable.HeadsUpNotificationSpace import com.android.systemui.qs.footer.ui.compose.FooterActionsWithAnimatedVisibility +import com.android.systemui.qs.ui.composable.QuickSettings.SharedValues.MediaLandscapeTopOffset +import com.android.systemui.qs.ui.composable.QuickSettings.SharedValues.MediaOffset.InQS import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel import com.android.systemui.res.R import com.android.systemui.scene.session.ui.composable.SaveableSession @@ -258,6 +264,14 @@ private fun SceneScope.QuickSettingsScene( } } + // ############# Media ############### + val isMediaVisible by viewModel.isMediaVisible.collectAsStateWithLifecycle() + val mediaInRow = + isMediaVisible && + LocalWindowSizeClass.current.heightSizeClass == WindowHeightSizeClass.Compact + val mediaOffset by + animateSceneDpAsState(value = InQS, key = MediaLandscapeTopOffset, canOverflow = false) + // This is the background for the whole scene, as the elements don't necessarily provide // a background that extends to the edges. Spacer( @@ -337,21 +351,37 @@ private fun SceneScope.QuickSettingsScene( } Spacer(modifier = Modifier.height(16.dp)) // This view has its own horizontal padding - QuickSettings( - viewModel.qsSceneAdapter, - { viewModel.qsSceneAdapter.qsHeight }, - isSplitShade = false, - modifier = Modifier - ) + val content: @Composable () -> Unit = { + QuickSettings( + viewModel.qsSceneAdapter, + { viewModel.qsSceneAdapter.qsHeight }, + isSplitShade = false, + modifier = Modifier.layoutId(QSMediaMeasurePolicy.LayoutId.QS) + ) - val isMediaVisible by viewModel.isMediaVisible.collectAsStateWithLifecycle() - - MediaCarousel( - isVisible = isMediaVisible, - mediaHost = mediaHost, - modifier = Modifier.fillMaxWidth(), - carouselController = mediaCarouselController, - ) + MediaCarousel( + isVisible = isMediaVisible, + mediaHost = mediaHost, + modifier = + Modifier.fillMaxWidth() + .layoutId(QSMediaMeasurePolicy.LayoutId.Media), + carouselController = mediaCarouselController, + ) + } + val landscapeQsMediaMeasurePolicy = remember { + QSMediaMeasurePolicy( + { viewModel.qsSceneAdapter.qsHeight }, + { mediaOffset.roundToPx() }, + ) + } + if (mediaInRow) { + Layout( + content = content, + measurePolicy = landscapeQsMediaMeasurePolicy, + ) + } else { + content() + } } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt index efda4cd3638e..4e334c274657 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt @@ -28,11 +28,14 @@ import androidx.compose.ui.unit.IntOffset import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult +import com.android.compose.animation.scene.animateSceneDpAsState import com.android.compose.animation.scene.animateSceneFloatAsState import com.android.internal.policy.SystemBarUtils import com.android.systemui.dagger.SysUISingleton import com.android.systemui.notifications.ui.composable.HeadsUpNotificationSpace import com.android.systemui.qs.ui.composable.QuickSettings +import com.android.systemui.qs.ui.composable.QuickSettings.SharedValues.MediaLandscapeTopOffset +import com.android.systemui.qs.ui.composable.QuickSettings.SharedValues.MediaOffset.Default import com.android.systemui.res.R import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.ui.viewmodel.GoneSceneViewModel @@ -67,6 +70,7 @@ constructor( value = QuickSettings.SharedValues.SquishinessValues.GoneSceneStarting, key = QuickSettings.SharedValues.TilesSquishiness, ) + animateSceneDpAsState(value = Default, key = MediaLandscapeTopOffset, canOverflow = false) Spacer(modifier.fillMaxSize()) HeadsUpNotificationStack( stackScrollView = notificationStackScrolLView.get(), 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 33a630c8086a..d51cdd3036f4 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 @@ -25,18 +25,15 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.clipScrollableContainer import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.displayCutoutPadding import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding @@ -55,6 +52,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.CompositingStrategy import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.Layout +import androidx.compose.ui.layout.layoutId import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.res.colorResource @@ -66,6 +64,7 @@ import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.TransitionState import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult +import com.android.compose.animation.scene.animateSceneDpAsState import com.android.compose.animation.scene.animateSceneFloatAsState import com.android.compose.modifiers.padding import com.android.compose.modifiers.thenIf @@ -85,7 +84,10 @@ import com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL import com.android.systemui.notifications.ui.composable.NotificationScrollingStack import com.android.systemui.qs.footer.ui.compose.FooterActionsWithAnimatedVisibility import com.android.systemui.qs.ui.composable.BrightnessMirror +import com.android.systemui.qs.ui.composable.QSMediaMeasurePolicy import com.android.systemui.qs.ui.composable.QuickSettings +import com.android.systemui.qs.ui.composable.QuickSettings.SharedValues.MediaLandscapeTopOffset +import com.android.systemui.qs.ui.composable.QuickSettings.SharedValues.MediaOffset.InQQS import com.android.systemui.res.R import com.android.systemui.scene.session.ui.composable.SaveableSession import com.android.systemui.scene.shared.model.Scenes @@ -242,6 +244,8 @@ private fun SceneScope.SingleShade( val mediaInRow = isMediaVisible && LocalWindowSizeClass.current.heightSizeClass == WindowHeightSizeClass.Compact + val mediaOffset by + animateSceneDpAsState(value = InQQS, key = MediaLandscapeTopOffset, canOverflow = false) Box( modifier = @@ -282,10 +286,10 @@ private fun SceneScope.SingleShade( statusBarIconController = statusBarIconController, ) - val content: @Composable (Modifier) -> Unit = { modifier -> + val content: @Composable () -> Unit = { Box( Modifier.element(QuickSettings.Elements.QuickQuickSettings) - .then(modifier) + .layoutId(QSMediaMeasurePolicy.LayoutId.QS) ) { QuickSettings( viewModel.qsSceneAdapter, @@ -298,23 +302,26 @@ private fun SceneScope.SingleShade( MediaCarousel( isVisible = isMediaVisible, mediaHost = mediaHost, - modifier = Modifier.fillMaxWidth().then(modifier), + modifier = + Modifier.fillMaxWidth() + .layoutId(QSMediaMeasurePolicy.LayoutId.Media), carouselController = mediaCarouselController, ) } - - if (!mediaInRow) { - content(Modifier) + val landscapeQsMediaMeasurePolicy = remember { + QSMediaMeasurePolicy( + { viewModel.qsSceneAdapter.qqsHeight }, + { mediaOffset.roundToPx() }, + ) + } + if (mediaInRow) { + Layout( + content = content, + measurePolicy = landscapeQsMediaMeasurePolicy, + ) } else { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = spacedBy(16.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - content(Modifier.weight(1f)) - } + content() } - Spacer(modifier = Modifier.height(16.dp)) } }, { diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt index 48a348b9d1c5..c2dd80375d5a 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt @@ -109,8 +109,7 @@ internal fun CoroutineScope.animateToScene( layoutState.transitions.interruptionHandler.onInterruption( transitionState, target, - ) - ?: DefaultInterruptionHandler.onInterruption(transitionState, target) + ) ?: DefaultInterruptionHandler.onInterruption(transitionState, target) val animateFrom = interruptionResult.animateFrom if ( @@ -159,6 +158,7 @@ private fun CoroutineScope.animate( val transition = if (reversed) { OneOffTransition( + key = transitionKey, fromScene = targetScene, toScene = fromScene, currentScene = targetScene, @@ -167,6 +167,7 @@ private fun CoroutineScope.animate( ) } else { OneOffTransition( + key = transitionKey, fromScene = fromScene, toScene = targetScene, currentScene = targetScene, @@ -178,7 +179,7 @@ private fun CoroutineScope.animate( // Change the current layout state to start this new transition. This will compute the // TransformationSpec associated to this transition, which we need to initialize the Animatable // that will actually animate it. - layoutState.startTransition(transition, transitionKey, chain) + layoutState.startTransition(transition, chain) // The transition now contains the transformation spec that we should use to instantiate the // Animatable. @@ -207,6 +208,7 @@ private fun CoroutineScope.animate( } private class OneOffTransition( + override val key: TransitionKey?, fromScene: SceneKey, toScene: SceneKey, override val currentScene: SceneKey, 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 e9633c2f6603..60d78feec8c2 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 @@ -257,7 +257,7 @@ private class DragControllerImpl( fun updateTransition(newTransition: SwipeTransition, force: Boolean = false) { if (isDrivingTransition || force) { - layoutState.startTransition(newTransition, newTransition.key) + layoutState.startTransition(newTransition) } swipeTransition = newTransition @@ -555,7 +555,7 @@ private class SwipeTransition( val layoutImpl: SceneTransitionLayoutImpl, val layoutState: BaseSceneTransitionLayoutState, val coroutineScope: CoroutineScope, - val key: TransitionKey?, + override val key: TransitionKey?, val _fromScene: Scene, val _toScene: Scene, val userActionDistanceScope: UserActionDistanceScope, 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 11d384196b5d..980982a30926 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 @@ -66,6 +66,9 @@ internal class Element(val key: ElementKey) { */ var lastTransition: TransitionState.Transition? = null + /** Whether this element was ever drawn in a scene. */ + var wasDrawnInAnyScene = false + override fun toString(): String { return "Element(key=$key)" } @@ -277,7 +280,7 @@ internal class ElementNode( constraints: Constraints, ): MeasureResult { val transitions = currentTransitions - val transition = elementTransition(element, transitions) + val transition = elementTransition(layoutImpl, element, transitions) // If this element is not supposed to be laid out now, either because it is not part of any // ongoing transition or the other scene of its transition is overscrolling, then lay out @@ -299,20 +302,110 @@ internal class ElementNode( val placeable = measure(layoutImpl, scene, element, transition, sceneState, measurable, constraints) sceneState.lastSize = placeable.size() - return layout(placeable.width, placeable.height) { - place( - layoutImpl, - scene, - element, - transition, - sceneState, - placeable, - ) + return layout(placeable.width, placeable.height) { place(transition, placeable) } + } + + @OptIn(ExperimentalComposeUiApi::class) + private fun Placeable.PlacementScope.place( + transition: TransitionState.Transition?, + placeable: Placeable, + ) { + with(layoutImpl.lookaheadScope) { + // Update the offset (relative to the SceneTransitionLayout) this element has in this + // scene when idle. + val coords = + coordinates ?: error("Element ${element.key} does not have any coordinates") + val targetOffsetInScene = lookaheadScopeCoordinates.localLookaheadPositionOf(coords) + + // No need to place the element in this scene if we don't want to draw it anyways. + if (!shouldPlaceElement(layoutImpl, scene.key, element, transition)) { + sceneState.lastOffset = Offset.Unspecified + sceneState.lastScale = Scale.Unspecified + sceneState.lastAlpha = Element.AlphaUnspecified + return + } + + val currentOffset = lookaheadScopeCoordinates.localPositionOf(coords, Offset.Zero) + val targetOffset = + computeValue( + layoutImpl, + scene, + element, + transition, + sceneValue = { it.targetOffset }, + transformation = { it.offset }, + idleValue = targetOffsetInScene, + currentValue = { currentOffset }, + isSpecified = { it != Offset.Unspecified }, + ::lerp, + ) + + val interruptedOffset = + computeInterruptedValue( + layoutImpl, + transition, + value = targetOffset, + unspecifiedValue = Offset.Unspecified, + zeroValue = Offset.Zero, + getValueBeforeInterruption = { sceneState.offsetBeforeInterruption }, + setValueBeforeInterruption = { sceneState.offsetBeforeInterruption = it }, + getInterruptionDelta = { sceneState.offsetInterruptionDelta }, + setInterruptionDelta = { delta -> + setPlacementInterruptionDelta( + element = element, + sceneState = sceneState, + transition = transition, + delta = delta, + setter = { sceneState, delta -> + sceneState.offsetInterruptionDelta = delta + }, + ) + }, + diff = { a, b -> a - b }, + add = { a, b, bProgress -> a + b * bProgress }, + ) + + sceneState.lastOffset = interruptedOffset + + val offset = (interruptedOffset - currentOffset).round() + if ( + isElementOpaque(scene, element, transition) && + interruptedAlpha(layoutImpl, element, transition, sceneState, alpha = 1f) == 1f + ) { + sceneState.lastAlpha = 1f + + // TODO(b/291071158): Call placeWithLayer() if offset != IntOffset.Zero and size is + // not animated once b/305195729 is fixed. Test that drawing is not invalidated in + // that case. + placeable.place(offset) + } else { + placeable.placeWithLayer(offset) { + // This layer might still run on its own (outside of the placement phase) even + // if this element is not placed or composed anymore, so we need to double check + // again here before calling [elementAlpha] (which will update + // [SceneState.lastAlpha]). We also need to recompute the current transition to + // make sure that we are using the current transition and not a reference to an + // old one. See b/343138966 for details. + if (_element == null) { + return@placeWithLayer + } + + val transition = elementTransition(layoutImpl, element, currentTransitions) + if (!shouldPlaceElement(layoutImpl, scene.key, element, transition)) { + return@placeWithLayer + } + + alpha = elementAlpha(layoutImpl, scene, element, transition, sceneState) + compositingStrategy = CompositingStrategy.ModulateAlpha + } + } } } override fun ContentDrawScope.draw() { - val transition = elementTransition(element, currentTransitions) + element.wasDrawnInAnyScene = true + + val transition = elementTransition(layoutImpl, element, currentTransitions) val drawScale = getDrawScale(layoutImpl, scene, element, transition, sceneState) if (drawScale == Scale.Default) { drawContent() @@ -353,6 +446,7 @@ internal class ElementNode( * its scenes contains the element. */ private fun elementTransition( + layoutImpl: SceneTransitionLayoutImpl, element: Element, transitions: List<TransitionState.Transition>, ): TransitionState.Transition? { @@ -366,7 +460,7 @@ private fun elementTransition( if (transition != previousTransition && transition != null && previousTransition != null) { // The previous transition was interrupted by another transition. - prepareInterruption(element, transition, previousTransition) + prepareInterruption(layoutImpl, element, transition, previousTransition) } else if (transition == null && previousTransition != null) { // The transition was just finished. element.sceneStates.values.forEach { @@ -379,18 +473,43 @@ private fun elementTransition( } private fun prepareInterruption( + layoutImpl: SceneTransitionLayoutImpl, element: Element, transition: TransitionState.Transition, previousTransition: TransitionState.Transition, ) { val sceneStates = element.sceneStates - sceneStates[previousTransition.fromScene]?.selfUpdateValuesBeforeInterruption() - sceneStates[previousTransition.toScene]?.selfUpdateValuesBeforeInterruption() - sceneStates[transition.fromScene]?.selfUpdateValuesBeforeInterruption() - sceneStates[transition.toScene]?.selfUpdateValuesBeforeInterruption() + fun updatedSceneState(key: SceneKey): Element.SceneState? { + return sceneStates[key]?.also { it.selfUpdateValuesBeforeInterruption() } + } + + val previousFromState = updatedSceneState(previousTransition.fromScene) + val previousToState = updatedSceneState(previousTransition.toScene) + val fromState = updatedSceneState(transition.fromScene) + val toState = updatedSceneState(transition.toScene) reconcileStates(element, previousTransition) reconcileStates(element, transition) + + // Remove the interruption values to all scenes but the scene(s) where the element will be + // placed, to make sure that interruption deltas are computed only right after this interruption + // is prepared. + fun maybeCleanPlacementValuesBeforeInterruption(sceneState: Element.SceneState) { + if (!shouldPlaceElement(layoutImpl, sceneState.scene, element, transition)) { + sceneState.offsetBeforeInterruption = Offset.Unspecified + sceneState.alphaBeforeInterruption = Element.AlphaUnspecified + sceneState.scaleBeforeInterruption = Scale.Unspecified + + sceneState.offsetInterruptionDelta = Offset.Zero + sceneState.alphaInterruptionDelta = 0f + sceneState.scaleInterruptionDelta = Scale.Zero + } + } + + previousFromState?.let { maybeCleanPlacementValuesBeforeInterruption(it) } + previousToState?.let { maybeCleanPlacementValuesBeforeInterruption(it) } + fromState?.let { maybeCleanPlacementValuesBeforeInterruption(it) } + toState?.let { maybeCleanPlacementValuesBeforeInterruption(it) } } /** @@ -497,9 +616,38 @@ private inline fun <T> computeInterruptedValue( } } +/** + * Set the interruption delta of a *placement/drawing*-related value (offset, alpha, scale). This + * ensures that the delta is also set on the other scene in the transition for shared elements, so + * that there is no jump cut if the scene where the element is placed has changed. + */ +private inline fun <T> setPlacementInterruptionDelta( + element: Element, + sceneState: Element.SceneState, + transition: TransitionState.Transition?, + delta: T, + setter: (Element.SceneState, T) -> Unit, +) { + // Set the interruption delta on the current scene. + setter(sceneState, delta) + + if (transition == null) { + return + } + + // If the element is shared, also set the delta on the other scene so that it is used by that + // scene if we start overscrolling it and change the scene where the element is placed. + val otherScene = + if (sceneState.scene == transition.fromScene) transition.toScene else transition.fromScene + val otherSceneState = element.sceneStates[otherScene] ?: return + if (isSharedElementEnabled(element.key, transition)) { + setter(otherSceneState, delta) + } +} + private fun shouldPlaceElement( layoutImpl: SceneTransitionLayoutImpl, - scene: Scene, + scene: SceneKey, element: Element, transition: TransitionState.Transition?, ): Boolean { @@ -510,16 +658,13 @@ private fun shouldPlaceElement( // Don't place the element in this scene if this scene is not part of the current element // transition. - if (scene.key != transition.fromScene && scene.key != transition.toScene) { + if (scene != transition.fromScene && scene != transition.toScene) { return false } - // Place the element if it is not shared or if the current scene is the one that is currently - // overscrolling with [OverscrollSpec]. + // Place the element if it is not shared. if ( - transition.fromScene !in element.sceneStates || - transition.toScene !in element.sceneStates || - transition.currentOverscrollSpec?.scene == scene.key + transition.fromScene !in element.sceneStates || transition.toScene !in element.sceneStates ) { return true } @@ -529,20 +674,26 @@ private fun shouldPlaceElement( return true } - return shouldDrawOrComposeSharedElement( + return shouldPlaceOrComposeSharedElement( layoutImpl, - scene.key, + scene, element.key, transition, ) } -internal fun shouldDrawOrComposeSharedElement( +internal fun shouldPlaceOrComposeSharedElement( layoutImpl: SceneTransitionLayoutImpl, scene: SceneKey, element: ElementKey, transition: TransitionState.Transition, ): Boolean { + // If we are overscrolling, only place/compose the element in the overscrolling scene. + val overscrollScene = transition.currentOverscrollSpec?.scene + if (overscrollScene != null) { + return scene == overscrollScene + } + val scenePicker = element.scenePicker val fromScene = transition.fromScene val toScene = transition.toScene @@ -555,7 +706,7 @@ internal fun shouldDrawOrComposeSharedElement( toSceneZIndex = layoutImpl.scenes.getValue(toScene).zIndex, ) ?: return false - return pickedScene == scene || transition.currentOverscrollSpec?.scene == scene + return pickedScene == scene } private fun isSharedElementEnabled( @@ -649,13 +800,20 @@ private fun elementAlpha( ) .fastCoerceIn(0f, 1f) - val interruptedAlpha = interruptedAlpha(layoutImpl, transition, sceneState, alpha) + // If the element is fading during this transition and that it is drawn for the first time, make + // sure that it doesn't instantly appear on screen. + if (!element.wasDrawnInAnyScene && alpha > 0f) { + element.sceneStates.forEach { it.value.alphaBeforeInterruption = 0f } + } + + val interruptedAlpha = interruptedAlpha(layoutImpl, element, transition, sceneState, alpha) sceneState.lastAlpha = interruptedAlpha return interruptedAlpha } private fun interruptedAlpha( layoutImpl: SceneTransitionLayoutImpl, + element: Element, transition: TransitionState.Transition?, sceneState: Element.SceneState, alpha: Float, @@ -669,7 +827,15 @@ private fun interruptedAlpha( getValueBeforeInterruption = { sceneState.alphaBeforeInterruption }, setValueBeforeInterruption = { sceneState.alphaBeforeInterruption = it }, getInterruptionDelta = { sceneState.alphaInterruptionDelta }, - setInterruptionDelta = { sceneState.alphaInterruptionDelta = it }, + setInterruptionDelta = { delta -> + setPlacementInterruptionDelta( + element = element, + sceneState = sceneState, + transition = transition, + delta = delta, + setter = { sceneState, delta -> sceneState.alphaInterruptionDelta = delta }, + ) + }, diff = { a, b -> a - b }, add = { a, b, bProgress -> a + b * bProgress }, ) @@ -776,7 +942,15 @@ private fun ContentDrawScope.getDrawScale( getValueBeforeInterruption = { sceneState.scaleBeforeInterruption }, setValueBeforeInterruption = { sceneState.scaleBeforeInterruption = it }, getInterruptionDelta = { sceneState.scaleInterruptionDelta }, - setInterruptionDelta = { sceneState.scaleInterruptionDelta = it }, + setInterruptionDelta = { delta -> + setPlacementInterruptionDelta( + element = element, + sceneState = sceneState, + transition = transition, + delta = delta, + setter = { sceneState, delta -> sceneState.scaleInterruptionDelta = delta }, + ) + }, diff = { a, b -> Scale( scaleX = a.scaleX - b.scaleX, @@ -807,84 +981,6 @@ private fun ContentDrawScope.getDrawScale( return interruptedScale } -@OptIn(ExperimentalComposeUiApi::class) -private fun Placeable.PlacementScope.place( - layoutImpl: SceneTransitionLayoutImpl, - scene: Scene, - element: Element, - transition: TransitionState.Transition?, - sceneState: Element.SceneState, - placeable: Placeable, -) { - with(layoutImpl.lookaheadScope) { - // Update the offset (relative to the SceneTransitionLayout) this element has in this scene - // when idle. - val coords = coordinates ?: error("Element ${element.key} does not have any coordinates") - val targetOffsetInScene = lookaheadScopeCoordinates.localLookaheadPositionOf(coords) - - // No need to place the element in this scene if we don't want to draw it anyways. - if (!shouldPlaceElement(layoutImpl, scene, element, transition)) { - sceneState.lastOffset = Offset.Unspecified - sceneState.lastScale = Scale.Unspecified - sceneState.lastAlpha = Element.AlphaUnspecified - - sceneState.clearValuesBeforeInterruption() - sceneState.clearInterruptionDeltas() - return - } - - val currentOffset = lookaheadScopeCoordinates.localPositionOf(coords, Offset.Zero) - val targetOffset = - computeValue( - layoutImpl, - scene, - element, - transition, - sceneValue = { it.targetOffset }, - transformation = { it.offset }, - idleValue = targetOffsetInScene, - currentValue = { currentOffset }, - isSpecified = { it != Offset.Unspecified }, - ::lerp, - ) - - val interruptedOffset = - computeInterruptedValue( - layoutImpl, - transition, - value = targetOffset, - unspecifiedValue = Offset.Unspecified, - zeroValue = Offset.Zero, - getValueBeforeInterruption = { sceneState.offsetBeforeInterruption }, - setValueBeforeInterruption = { sceneState.offsetBeforeInterruption = it }, - getInterruptionDelta = { sceneState.offsetInterruptionDelta }, - setInterruptionDelta = { sceneState.offsetInterruptionDelta = it }, - diff = { a, b -> a - b }, - add = { a, b, bProgress -> a + b * bProgress }, - ) - - sceneState.lastOffset = interruptedOffset - - val offset = (interruptedOffset - currentOffset).round() - if ( - isElementOpaque(scene, element, transition) && - interruptedAlpha(layoutImpl, transition, sceneState, alpha = 1f) == 1f - ) { - sceneState.lastAlpha = 1f - - // TODO(b/291071158): Call placeWithLayer() if offset != IntOffset.Zero and size is not - // animated once b/305195729 is fixed. Test that drawing is not invalidated in that - // case. - placeable.place(offset) - } else { - placeable.placeWithLayer(offset) { - alpha = elementAlpha(layoutImpl, scene, element, transition, sceneState) - compositingStrategy = CompositingStrategy.ModulateAlpha - } - } - } -} - /** * Return the value that should be used depending on the current layout state and transition. * 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 be005eac1b75..32eadde7bf30 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 @@ -187,7 +187,7 @@ private fun shouldComposeMovableElement( } ?: return false // Always compose movable elements in the scene picked by their scene picker. - return shouldDrawOrComposeSharedElement( + return shouldPlaceOrComposeSharedElement( layoutImpl, scene, element, 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 2946b04af51a..b9251307f1d2 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 @@ -56,7 +56,7 @@ fun SceneTransitionLayout( modifier: Modifier = Modifier, swipeSourceDetector: SwipeSourceDetector = DefaultEdgeDetector, swipeDetector: SwipeDetector = DefaultSwipeDetector, - @FloatRange(from = 0.0, to = 0.5) transitionInterceptionThreshold: Float = 0f, + @FloatRange(from = 0.0, to = 0.5) transitionInterceptionThreshold: Float = 0.05f, scenes: SceneTransitionLayoutScope.() -> Unit, ) { SceneTransitionLayoutForTesting( 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 44affd968513..6a178c8b0c25 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 @@ -226,6 +226,12 @@ sealed interface TransitionState { val toScene: SceneKey, ) : TransitionState { /** + * The key of this transition. This should usually be null, but it can be specified to use a + * specific set of transformations associated to this transition. + */ + open val key: TransitionKey? = null + + /** * The progress of the transition. This is usually in the `[0; 1]` range, but it can also be * less than `0` or greater than `1` when using transitions with a spring AnimationSpec or * when flinging quickly during a swipe gesture. @@ -455,11 +461,7 @@ internal abstract class BaseSceneTransitionLayoutState( * * Important: you *must* call [finishTransition] once the transition is finished. */ - internal fun startTransition( - transition: TransitionState.Transition, - transitionKey: TransitionKey? = null, - chain: Boolean = true, - ) { + internal fun startTransition(transition: TransitionState.Transition, chain: Boolean = true) { checkThread() // Compute the [TransformationSpec] when the transition starts. @@ -469,7 +471,9 @@ internal abstract class BaseSceneTransitionLayoutState( // Update the transition specs. transition.transformationSpec = - transitions.transitionSpec(fromScene, toScene, key = transitionKey).transformationSpec() + transitions + .transitionSpec(fromScene, toScene, key = transition.key) + .transformationSpec() if (orientation != null) { transition.updateOverscrollSpecs( fromSpec = transitions.overscrollSpec(fromScene, orientation), @@ -568,9 +572,10 @@ internal abstract class BaseSceneTransitionLayoutState( originalTransition = transitionState, fromScene = targetCurrentScene, toScene = matchingLink.targetTo, + key = matchingLink.targetTransitionKey, ) - stateLink.target.startTransition(linkedTransition, matchingLink.targetTransitionKey) + stateLink.target.startTransition(linkedTransition) activeTransitionLinks[stateLink] = linkedTransition } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt index 79f126d24561..ed9888560f05 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt @@ -17,6 +17,7 @@ package com.android.compose.animation.scene.transition.link import com.android.compose.animation.scene.SceneKey +import com.android.compose.animation.scene.TransitionKey import com.android.compose.animation.scene.TransitionState import kotlinx.coroutines.Job @@ -25,6 +26,7 @@ internal class LinkedTransition( private val originalTransition: TransitionState.Transition, fromScene: SceneKey, toScene: SceneKey, + override val key: TransitionKey? = null, ) : TransitionState.Transition(fromScene, toScene) { override val currentScene: SceneKey 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 beb74bc9bb36..41cacb4c71fc 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 @@ -32,6 +32,7 @@ import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.size 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 @@ -46,9 +47,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.layout.approachLayout import androidx.compose.ui.platform.LocalViewConfiguration +import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertIsNotDisplayed import androidx.compose.ui.test.assertPositionInRootIsEqualTo import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo +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 @@ -635,10 +638,7 @@ class ElementTest { // Change the current transition. rule.runOnUiThread { - state.startTransition( - transition(from = SceneA, to = SceneB, progress = { 0.5f }), - transitionKey = null, - ) + state.startTransition(transition(from = SceneA, to = SceneB, progress = { 0.5f })) } // The size of Foo should still be 20dp given that the new state was not composed yet. @@ -1167,7 +1167,7 @@ class ElementTest { val offsetInAToB = lerp(offsetInA, offsetInB, aToBProgress) val sizeInAToB = lerp(sizeInA, sizeInB, aToBProgress) val valueInAToB = lerp(valueInA, valueInB, aToBProgress) - rule.runOnUiThread { state.startTransition(aToB, transitionKey = null) } + rule.runOnUiThread { state.startTransition(aToB) } rule .onNode(isElement(TestElements.Foo, SceneB)) .assertSizeIsEqualTo(sizeInAToB) @@ -1187,7 +1187,7 @@ class ElementTest { progress = { bToCProgress }, interruptionProgress = { interruptionProgress }, ) - rule.runOnUiThread { state.startTransition(bToC, transitionKey = null) } + rule.runOnUiThread { state.startTransition(bToC) } // The interruption deltas, which will be multiplied by the interruption progress then added // to the current transition offset and size. @@ -1329,9 +1329,9 @@ class ElementTest { interruptionProgress = { bToCInterruptionProgress }, onFinish = neverFinish(), ) - rule.runOnUiThread { state.startTransition(aToB, transitionKey = null) } + rule.runOnUiThread { state.startTransition(aToB) } rule.waitForIdle() - rule.runOnUiThread { state.startTransition(bToC, transitionKey = null) } + rule.runOnUiThread { state.startTransition(bToC) } // Foo is placed in both B and C given that the shared transition is disabled. In B, its // offset is impacted by the interruption but in C it is not. @@ -1367,7 +1367,7 @@ class ElementTest { progress = { 0.7f }, interruptionProgress = { 1f }, ) - rule.runOnUiThread { state.startTransition(bToA, transitionKey = null) } + rule.runOnUiThread { state.startTransition(bToA) } // Foo should have the position it had in B right before the interruption. rule @@ -1391,8 +1391,7 @@ class ElementTest { to = SceneB, progress = { -1f }, orientation = Orientation.Horizontal - ), - transitionKey = null, + ) ) } } @@ -1418,4 +1417,306 @@ class ElementTest { assertThat(bState.targetSize).isNotEqualTo(Element.SizeUnspecified) assertThat(bState.targetOffset).isNotEqualTo(Offset.Unspecified) } + + @Test + fun lastAlphaIsNotSetByOutdatedLayer() = runTest { + val state = + rule.runOnUiThread { + MutableSceneTransitionLayoutStateImpl( + SceneA, + transitions { from(SceneA, to = SceneB) { fade(TestElements.Foo) } } + ) + } + + lateinit var layoutImpl: SceneTransitionLayoutImpl + rule.setContent { + SceneTransitionLayoutForTesting(state, onLayoutImpl = { layoutImpl = it }) { + scene(SceneA) {} + scene(SceneB) { Box(Modifier.element(TestElements.Foo)) } + scene(SceneC) { Box(Modifier.element(TestElements.Foo)) } + } + } + + // Start A => B at 0.5f. + var aToBProgress by mutableStateOf(0.5f) + rule.runOnUiThread { + state.startTransition( + transition( + from = SceneA, + to = SceneB, + progress = { aToBProgress }, + onFinish = neverFinish(), + ) + ) + } + rule.waitForIdle() + + val foo = checkNotNull(layoutImpl.elements[TestElements.Foo]) + assertThat(foo.sceneStates[SceneA]).isNull() + + val fooInB = foo.sceneStates[SceneB] + assertThat(fooInB).isNotNull() + assertThat(fooInB!!.lastAlpha).isEqualTo(0.5f) + + // Move the progress of A => B to 0.7f. + aToBProgress = 0.7f + rule.waitForIdle() + assertThat(fooInB.lastAlpha).isEqualTo(0.7f) + + // Start B => C at 0.3f. + rule.runOnUiThread { + state.startTransition(transition(from = SceneB, to = SceneC, progress = { 0.3f })) + } + rule.waitForIdle() + val fooInC = foo.sceneStates[SceneC] + assertThat(fooInC).isNotNull() + assertThat(fooInC!!.lastAlpha).isEqualTo(1f) + assertThat(fooInB.lastAlpha).isEqualTo(Element.AlphaUnspecified) + + // Move the progress of A => B to 0.9f. This shouldn't change anything given that B => C is + // now the transition applied to Foo. + aToBProgress = 0.9f + rule.waitForIdle() + assertThat(fooInC.lastAlpha).isEqualTo(1f) + assertThat(fooInB.lastAlpha).isEqualTo(Element.AlphaUnspecified) + } + + @Test + fun fadingElementsDontAppearInstantly() { + val state = + rule.runOnUiThread { + MutableSceneTransitionLayoutStateImpl( + SceneA, + transitions { from(SceneA, to = SceneB) { fade(TestElements.Foo) } } + ) + } + + lateinit var layoutImpl: SceneTransitionLayoutImpl + rule.setContent { + SceneTransitionLayoutForTesting(state, onLayoutImpl = { layoutImpl = it }) { + scene(SceneA) {} + scene(SceneB) { Box(Modifier.element(TestElements.Foo)) } + } + } + + // Start A => B at 60%. + var interruptionProgress by mutableStateOf(1f) + rule.runOnUiThread { + state.startTransition( + transition( + from = SceneA, + to = SceneB, + progress = { 0.6f }, + interruptionProgress = { interruptionProgress }, + ) + ) + } + rule.waitForIdle() + + // Alpha of Foo should be 0f at interruption progress 100%. + val fooInB = layoutImpl.elements.getValue(TestElements.Foo).sceneStates.getValue(SceneB) + assertThat(fooInB.lastAlpha).isEqualTo(0f) + + // Alpha of Foo should be 0.6f at interruption progress 0%. + interruptionProgress = 0f + rule.waitForIdle() + assertThat(fooInB.lastAlpha).isEqualTo(0.6f) + + // Alpha of Foo should be 0.3f at interruption progress 50%. + interruptionProgress = 0.5f + rule.waitForIdle() + assertThat(fooInB.lastAlpha).isEqualTo(0.3f) + } + + @Test + fun sharedElementIsOnlyPlacedInOverscrollingScene() { + val state = + rule.runOnUiThread { + MutableSceneTransitionLayoutStateImpl( + SceneA, + transitions { + overscroll(SceneA, Orientation.Horizontal) + overscroll(SceneB, Orientation.Horizontal) + } + ) + } + + @Composable + fun SceneScope.Foo() { + Box(Modifier.element(TestElements.Foo).size(10.dp)) + } + + rule.setContent { + 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) + rule.runOnUiThread { + 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 { + overscroll(SceneA, Orientation.Horizontal) + overscroll(SceneB, Orientation.Horizontal) + } + ) + } + + val fooInA = "fooInA" + val fooInB = "fooInB" + + @Composable + fun SceneScope.MovableFoo(text: String, modifier: Modifier = Modifier) { + MovableElement(TestElements.Foo, modifier) { content { Text(text) } } + } + + rule.setContent { + 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) + rule.runOnUiThread { + 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() = runTest { + val state = + rule.runOnUiThread { + MutableSceneTransitionLayoutStateImpl( + SceneA, + transitions { + overscroll(SceneB, Orientation.Vertical) { + translate(TestElements.Foo, y = 15.dp) + } + } + ) + } + + @Composable + fun SceneScope.SceneWithFoo(offset: DpOffset, modifier: Modifier = Modifier) { + Box(modifier.fillMaxSize()) { + Box(Modifier.offset(offset.x, offset.y).element(TestElements.Foo).size(100.dp)) + } + } + + rule.setContent { + 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%. + rule.runOnUiThread { + state.startTransition( + transition( + from = SceneA, + to = SceneB, + progress = { 0.75f }, + onFinish = neverFinish(), + ) + ) + } + + // 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) + rule.runOnUiThread { + state.startTransition( + transition( + from = SceneB, + to = SceneC, + progress = { progress }, + interruptionProgress = { interruptionProgress }, + orientation = Orientation.Vertical, + onFinish = neverFinish(), + ) + ) + } + + // 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) + } } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt index 85d4165b4bf6..09d1a827d0c7 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt @@ -40,7 +40,7 @@ class InterruptionHandlerTest { val state = MutableSceneTransitionLayoutState( SceneA, - transitions { /* default interruption handler */}, + transitions { /* default interruption handler */ }, ) state.setTargetScene(SceneB, coroutineScope = this) @@ -160,7 +160,7 @@ class InterruptionHandlerTest { progressVelocity = { progressVelocity }, onFinish = { launch {} }, ) - state.startTransition(aToB, transitionKey = null) + state.startTransition(aToB) // Animate back to A. The previous transition is reversed, i.e. it has the same (from, to) // pair, and its velocity is used when animating the progress back to 0. @@ -186,7 +186,7 @@ class InterruptionHandlerTest { progressVelocity = { progressVelocity }, onFinish = { launch {} }, ) - state.startTransition(aToB, transitionKey = null) + state.startTransition(aToB) // Animate to B. The previous transition is reversed, i.e. it has the same (from, to) pair, // and its velocity is used when animating the progress to 1. diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ObservableTransitionStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ObservableTransitionStateTest.kt index 2a75e13066df..55431354b693 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ObservableTransitionStateTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ObservableTransitionStateTest.kt @@ -135,7 +135,7 @@ class ObservableTransitionStateTest { var transitionCurrentScene by mutableStateOf(SceneA) val transition = transition(from = SceneA, to = SceneB, current = { transitionCurrentScene }) - state.startTransition(transition, transitionKey = null) + state.startTransition(transition) assertThat(currentScene.value).isEqualTo(SceneA) // Change the transition current scene. 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 d2c8bd6928ee..de6f1cc518f4 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 @@ -57,7 +57,7 @@ class SceneTransitionLayoutStateTest { @Test fun isTransitioningTo_transition() { val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty) - state.startTransition(transition(from = SceneA, to = SceneB), transitionKey = null) + state.startTransition(transition(from = SceneA, to = SceneB)) assertThat(state.isTransitioning()).isTrue() assertThat(state.isTransitioning(from = SceneA)).isTrue() @@ -175,7 +175,7 @@ class SceneTransitionLayoutStateTest { val childTransition = transition(SceneA, SceneB) - childState.startTransition(childTransition, null) + childState.startTransition(childTransition) assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue() assertThat(parentState.isTransitioning(SceneC, SceneD)).isTrue() @@ -211,7 +211,7 @@ class SceneTransitionLayoutStateTest { val childTransition = transition(SceneA, SceneB) - childState.startTransition(childTransition, null) + childState.startTransition(childTransition) assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue() assertThat(parentState.isTransitioning(SceneC, SceneD)).isTrue() assertThat(parentParentState.isTransitioning(SceneB, SceneC)).isTrue() @@ -229,7 +229,7 @@ class SceneTransitionLayoutStateTest { var progress = 0f val childTransition = transition(SceneA, SceneB, progress = { progress }) - childState.startTransition(childTransition, null) + childState.startTransition(childTransition) assertThat(parentState.currentTransition?.progress).isEqualTo(0f) progress = .5f @@ -242,7 +242,7 @@ class SceneTransitionLayoutStateTest { val childTransition = transition(SceneB, SceneA) - childState.startTransition(childTransition, null) + childState.startTransition(childTransition) assertThat(childState.isTransitioning(SceneB, SceneA)).isTrue() assertThat(parentState.transitionState).isEqualTo(TransitionState.Idle(SceneC)) @@ -256,7 +256,7 @@ class SceneTransitionLayoutStateTest { val (parentState, childState) = setupLinkedStates() val childTransition = transition(SceneA, SceneB) - childState.startTransition(childTransition, null) + childState.startTransition(childTransition) childState.finishTransition(childTransition, SceneA) assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneA)) @@ -268,7 +268,7 @@ class SceneTransitionLayoutStateTest { val (parentState, childState) = setupLinkedStates() val childTransition = transition(SceneA, SceneB) - childState.startTransition(childTransition, null) + childState.startTransition(childTransition) childState.finishTransition(childTransition, SceneD) assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneD)) @@ -283,16 +283,16 @@ class SceneTransitionLayoutStateTest { transition( SceneA, SceneB, - onFinish = { launch { /* Do nothing. */} }, + onFinish = { launch { /* Do nothing. */ } }, ) val parentTransition = transition( SceneC, SceneA, - onFinish = { launch { /* Do nothing. */} }, + onFinish = { launch { /* Do nothing. */ } }, ) - childState.startTransition(childTransition, null) - parentState.startTransition(parentTransition, null) + childState.startTransition(childTransition) + parentState.startTransition(parentTransition) childState.finishTransition(childTransition, SceneB) assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneB)) @@ -341,10 +341,7 @@ class SceneTransitionLayoutStateTest { @Test fun snapToIdleIfClose_snapToStart() = runMonotonicClockTest { val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty) - state.startTransition( - transition(from = SceneA, to = SceneB, progress = { 0.2f }), - transitionKey = null - ) + state.startTransition(transition(from = SceneA, to = SceneB, progress = { 0.2f })) assertThat(state.isTransitioning()).isTrue() // Ignore the request if the progress is not close to 0 or 1, using the threshold. @@ -360,10 +357,7 @@ class SceneTransitionLayoutStateTest { @Test fun snapToIdleIfClose_snapToEnd() = runMonotonicClockTest { val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty) - state.startTransition( - transition(from = SceneA, to = SceneB, progress = { 0.8f }), - transitionKey = null - ) + state.startTransition(transition(from = SceneA, to = SceneB, progress = { 0.8f })) assertThat(state.isTransitioning()).isTrue() // Ignore the request if the progress is not close to 0 or 1, using the threshold. @@ -385,13 +379,13 @@ class SceneTransitionLayoutStateTest { from = SceneA, to = SceneB, progress = { 0.5f }, - onFinish = { launch { /* do nothing */} }, + onFinish = { launch { /* do nothing */ } }, ) - state.startTransition(aToB, transitionKey = null) + state.startTransition(aToB) assertThat(state.currentTransitions).containsExactly(aToB).inOrder() val bToC = transition(from = SceneB, to = SceneC, progress = { 0.8f }) - state.startTransition(bToC, transitionKey = null) + state.startTransition(bToC) assertThat(state.currentTransitions).containsExactly(aToB, bToC).inOrder() // Ignore the request if the progress is not close to 0 or 1, using the threshold. @@ -409,7 +403,7 @@ class SceneTransitionLayoutStateTest { val (parentState, childState) = setupLinkedStates(SceneC, SceneA, null, null, null, SceneD) val childTransition = transition(SceneA, SceneB) - childState.startTransition(childTransition, null) + childState.startTransition(childTransition) assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue() assertThat(parentState.isTransitioning(SceneC, SceneD)).isTrue() @@ -425,7 +419,7 @@ class SceneTransitionLayoutStateTest { val childTransition = transition(SceneA, SceneB) - childState.startTransition(childTransition, null) + childState.startTransition(childTransition) assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue() assertThat(parentState.isTransitioning(SceneC, SceneD)).isTrue() @@ -440,7 +434,7 @@ class SceneTransitionLayoutStateTest { setupLinkedStates(SceneC, SceneA, SceneB, null, SceneC, SceneD) val childTransition = transition(SceneA, SceneB) - childState.startTransition(childTransition, null) + childState.startTransition(childTransition) assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue() assertThat(parentState.isTransitioning(SceneC, SceneD)).isFalse() } @@ -460,8 +454,7 @@ class SceneTransitionLayoutStateTest { to = SceneB, progress = progress, orientation = Orientation.Vertical, - ), - transitionKey = null + ) ) assertThat(state.isTransitioning()).isTrue() return state @@ -583,19 +576,19 @@ class SceneTransitionLayoutStateTest { assertThat(state.currentTransitions).isEmpty() // A => B. - state.startTransition(aToB, transitionKey = null) + state.startTransition(aToB) assertThat(finishingTransitions).isEmpty() assertThat(state.finishedTransitions).isEmpty() assertThat(state.currentTransitions).containsExactly(aToB).inOrder() // B => C. This should automatically call finish() on aToB. - state.startTransition(bToC, transitionKey = null) + state.startTransition(bToC) assertThat(finishingTransitions).containsExactly(aToB) assertThat(state.finishedTransitions).isEmpty() assertThat(state.currentTransitions).containsExactly(aToB, bToC).inOrder() // C => A. This should automatically call finish() on bToC. - state.startTransition(cToA, transitionKey = null) + state.startTransition(cToA) assertThat(finishingTransitions).containsExactly(aToB, bToC) assertThat(state.finishedTransitions).isEmpty() assertThat(state.currentTransitions).containsExactly(aToB, bToC, cToA).inOrder() @@ -617,8 +610,8 @@ class SceneTransitionLayoutStateTest { val state = MutableSceneTransitionLayoutStateImpl(SceneA, EmptyTestTransitions) fun startTransition() { - val transition = transition(SceneA, SceneB, onFinish = { launch { /* do nothing */} }) - state.startTransition(transition, transitionKey = null) + val transition = transition(SceneA, SceneB, onFinish = { launch { /* do nothing */ } }) + state.startTransition(transition) } var hasLoggedWtf = false diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt index e6fa69d87b34..322b0355c2bd 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt @@ -30,7 +30,7 @@ fun transition( current: () -> SceneKey = { from }, progress: () -> Float = { 0f }, progressVelocity: () -> Float = { 0f }, - interruptionProgress: () -> Float = { 100f }, + interruptionProgress: () -> Float = { 0f }, isInitiatedByUserInput: Boolean = false, isUserInputOngoing: Boolean = false, isUpOrLeft: Boolean = false, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.java index 27bffd0818e7..04b930ed73b0 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.java @@ -18,9 +18,13 @@ package com.android.systemui.ambient.touch; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.DreamManager; import android.view.GestureDetector; import android.view.MotionEvent; @@ -36,6 +40,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; @@ -52,63 +57,104 @@ public class ShadeTouchHandlerTest extends SysuiTestCase { ShadeViewController mShadeViewController; @Mock + DreamManager mDreamManager; + + @Mock TouchHandler.TouchSession mTouchSession; ShadeTouchHandler mTouchHandler; + @Captor + ArgumentCaptor<GestureDetector.OnGestureListener> mGestureListenerCaptor; + @Captor + ArgumentCaptor<InputChannelCompat.InputEventListener> mInputListenerCaptor; + private static final int TOUCH_HEIGHT = 20; @Before public void setup() { MockitoAnnotations.initMocks(this); + mTouchHandler = new ShadeTouchHandler(Optional.of(mCentralSurfaces), mShadeViewController, - TOUCH_HEIGHT); + mDreamManager, TOUCH_HEIGHT); } - /** - * Verify that touches aren't handled when the bouncer is showing. - */ + // Verifies that a swipe down in the gesture region is captured by the shade touch handler. @Test - public void testInactiveOnBouncer() { - when(mCentralSurfaces.isBouncerShowing()).thenReturn(true); - mTouchHandler.onSessionStart(mTouchSession); - verify(mTouchSession).pop(); + public void testSwipeDown_captured() { + final boolean captured = swipe(Direction.DOWN); + + assertThat(captured).isTrue(); } - /** - * Make sure {@link ShadeTouchHandler} - */ + // Verifies that a swipe in the upward direction is not catpured. @Test - public void testTouchPilferingOnScroll() { - final MotionEvent motionEvent1 = Mockito.mock(MotionEvent.class); - final MotionEvent motionEvent2 = Mockito.mock(MotionEvent.class); + public void testSwipeUp_notCaptured() { + final boolean captured = swipe(Direction.UP); - final ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerArgumentCaptor = - ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class); + // Motion events not captured as the swipe is going in the wrong direction. + assertThat(captured).isFalse(); + } - mTouchHandler.onSessionStart(mTouchSession); - verify(mTouchSession).registerGestureListener(gestureListenerArgumentCaptor.capture()); + // Verifies that a swipe down forwards captured touches to central surfaces for handling. + @Test + public void testSwipeDown_sentToCentralSurfaces() { + swipe(Direction.DOWN); - assertThat(gestureListenerArgumentCaptor.getValue() - .onScroll(motionEvent1, motionEvent2, 1, 1)) - .isTrue(); + // Both motion events are sent for the shade window to process. + verify(mCentralSurfaces, times(2)).handleExternalShadeWindowTouch(any()); } - /** - * Ensure touches are propagated to the {@link ShadeViewController}. - */ + // Verifies that a swipe down forwards captured touches to central surfaces for handling. @Test - public void testEventPropagation() { - final MotionEvent motionEvent = Mockito.mock(MotionEvent.class); + public void testSwipeDown_dreaming_sentToShadeView() { + when(mDreamManager.isDreaming()).thenReturn(true); + + swipe(Direction.DOWN); + + // Both motion events are sent for the shade window to process. + verify(mShadeViewController, times(2)).handleExternalTouch(any()); + } - final ArgumentCaptor<InputChannelCompat.InputEventListener> - inputEventListenerArgumentCaptor = - ArgumentCaptor.forClass(InputChannelCompat.InputEventListener.class); + // Verifies that a swipe down is not forwarded to the shade window. + @Test + public void testSwipeUp_touchesNotSent() { + swipe(Direction.UP); + + // Motion events are not sent for the shade window to process as the swipe is going in the + // wrong direction. + verify(mCentralSurfaces, never()).handleExternalShadeWindowTouch(any()); + } + /** + * Simulates a swipe in the given direction and returns true if the touch was intercepted by the + * touch handler's gesture listener. + * <p> + * Swipe down starts from a Y coordinate of 0 and goes downward. Swipe up starts from the edge + * of the gesture region, {@link #TOUCH_HEIGHT}, and goes upward to 0. + */ + private boolean swipe(Direction direction) { + Mockito.clearInvocations(mTouchSession); mTouchHandler.onSessionStart(mTouchSession); - verify(mTouchSession).registerInputListener(inputEventListenerArgumentCaptor.capture()); - inputEventListenerArgumentCaptor.getValue().onInputEvent(motionEvent); - verify(mShadeViewController).handleExternalTouch(motionEvent); + + verify(mTouchSession).registerGestureListener(mGestureListenerCaptor.capture()); + verify(mTouchSession).registerInputListener(mInputListenerCaptor.capture()); + + final float startY = direction == Direction.UP ? TOUCH_HEIGHT : 0; + final float endY = direction == Direction.UP ? 0 : TOUCH_HEIGHT; + + // Send touches to the input and gesture listener. + final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, startY, 0); + final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, endY, 0); + mInputListenerCaptor.getValue().onInputEvent(event1); + mInputListenerCaptor.getValue().onInputEvent(event2); + final boolean captured = mGestureListenerCaptor.getValue().onScroll(event1, event2, 0, + startY - endY); + + return captured; } + private enum Direction { + DOWN, UP, + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt index ffa63d83a97f..e42a67b7c5b0 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt @@ -295,7 +295,7 @@ class CommunalInteractorTest : SysuiTestCase() { val targets = listOf(target1, target2, target3) smartspaceRepository.setCommunalSmartspaceTargets(targets) - val smartspaceContent by collectLastValue(underTest.ongoingContent) + val smartspaceContent by collectLastValue(underTest.getOngoingContent(true)) assertThat(smartspaceContent?.size).isEqualTo(1) assertThat(smartspaceContent?.get(0)?.key) .isEqualTo(CommunalContentModel.KEY.smartspace("target3")) @@ -393,7 +393,7 @@ class CommunalInteractorTest : SysuiTestCase() { smartspaceRepository.setCommunalSmartspaceTargets(targets) - val smartspaceContent by collectLastValue(underTest.ongoingContent) + val smartspaceContent by collectLastValue(underTest.getOngoingContent(true)) assertThat(smartspaceContent?.size).isEqualTo(totalTargets) for (index in 0 until totalTargets) { assertThat(smartspaceContent?.get(index)?.size).isEqualTo(expectedSizes[index]) @@ -409,7 +409,7 @@ class CommunalInteractorTest : SysuiTestCase() { // Media is playing. mediaRepository.mediaActive() - val umoContent by collectLastValue(underTest.ongoingContent) + val umoContent by collectLastValue(underTest.getOngoingContent(true)) assertThat(umoContent?.size).isEqualTo(1) assertThat(umoContent?.get(0)).isInstanceOf(CommunalContentModel.Umo::class.java) @@ -417,6 +417,20 @@ class CommunalInteractorTest : SysuiTestCase() { } @Test + fun umo_mediaPlaying_doNotShowUmo() = + testScope.run { + // Tutorial completed. + tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) + + // Media is playing. + mediaRepository.mediaActive() + + val umoContent by collectLastValue(underTest.getOngoingContent(false)) + + assertThat(umoContent?.size).isEqualTo(0) + } + + @Test fun ongoing_shouldOrderAndSizeByTimestamp() = testScope.runTest { // Keyguard showing, and tutorial completed. @@ -439,7 +453,7 @@ class CommunalInteractorTest : SysuiTestCase() { val timer3 = smartspaceTimer("timer3", timestamp = 4L) smartspaceRepository.setCommunalSmartspaceTargets(listOf(timer1, timer2, timer3)) - val ongoingContent by collectLastValue(underTest.ongoingContent) + val ongoingContent by collectLastValue(underTest.getOngoingContent(true)) assertThat(ongoingContent?.size).isEqualTo(4) assertThat(ongoingContent?.get(0)?.key) .isEqualTo(CommunalContentModel.KEY.smartspace("timer3")) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt index 9dcea82e782b..e7a7b152d936 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt @@ -46,6 +46,7 @@ import com.android.systemui.communal.ui.viewmodel.CommunalViewModel import com.android.systemui.communal.ui.viewmodel.CommunalViewModel.Companion.POPUP_AUTO_HIDE_TIMEOUT_MS import com.android.systemui.communal.ui.viewmodel.PopupType import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.coroutines.collectValues import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED import com.android.systemui.flags.andSceneContainer import com.android.systemui.flags.fakeFeatureFlagsClassic @@ -61,6 +62,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.log.logcatLogBuffer import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager @@ -142,11 +144,13 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { selectedUserIndex = 0, ) whenever(providerInfo.profile).thenReturn(UserHandle(MAIN_USER_INFO.id)) + whenever(mediaHost.visible).thenReturn(true) kosmos.powerInteractor.setAwakeForTest() underTest = CommunalViewModel( + kosmos.testDispatcher, testScope, context.resources, kosmos.keyguardTransitionInteractor, @@ -235,6 +239,45 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { } @Test + fun communalContent_mediaHostVisible_umoIncluded() = + testScope.runTest { + // Media playing. + mediaRepository.mediaActive() + + val communalContent by collectLastValue(underTest.communalContent) + assertThat(communalContent?.size).isEqualTo(2) + assertThat(communalContent?.get(0)).isInstanceOf(CommunalContentModel.Umo::class.java) + } + + @Test + fun communalContent_mediaHostVisible_umoExcluded() = + testScope.runTest { + whenever(mediaHost.visible).thenReturn(false) + mediaHost.updateViewVisibility() + // Media playing. + mediaRepository.mediaActive() + + val communalContent by collectLastValue(underTest.communalContent) + assertThat(communalContent?.size).isEqualTo(1) + assertThat(communalContent?.get(0)) + .isInstanceOf(CommunalContentModel.CtaTileInViewMode::class.java) + } + + @Test + fun communalContent_mediaHostVisible_umoToggle() = + testScope.runTest { + mediaHost.updateViewVisibility() + mediaRepository.mediaActive() + + val communalContent by collectValues(underTest.communalContent) + + whenever(mediaHost.visible).thenReturn(false) + mediaHost.updateViewVisibility() + + assertThat(communalContent.size).isEqualTo(1) + } + + @Test fun isEmptyState_isTrue_noWidgetButActiveLiveContent() = testScope.runTest { tutorialRepository.setTutorialSettingState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt index 4849e66d37d5..c51413a2cc78 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt @@ -26,7 +26,6 @@ import com.android.systemui.haptics.vibratorHelper import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.kosmos.testScope -import com.android.systemui.qs.qsTileFactory import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.TestScope @@ -42,7 +41,6 @@ class QSLongPressEffectTest : SysuiTestCase() { private val kosmos = testKosmos() private val vibratorHelper = kosmos.vibratorHelper - private val qsTile = kosmos.qsTileFactory.createTile("Test Tile") private val effectDuration = 400 private val lowTickDuration = 12 @@ -63,7 +61,6 @@ class QSLongPressEffectTest : SysuiTestCase() { vibratorHelper, kosmos.keyguardInteractor, ) - longPressEffect.qsTile = qsTile } @Test @@ -94,10 +91,8 @@ class QSLongPressEffectTest : SysuiTestCase() { // GIVEN an action down event occurs longPressEffect.handleActionDown() - // THEN the effect moves to the TIMEOUT_WAIT state and starts the wait - val action by collectLastValue(longPressEffect.actionType) + // THEN the effect moves to the TIMEOUT_WAIT state assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.TIMEOUT_WAIT) - assertThat(action).isEqualTo(QSLongPressEffect.ActionType.WAIT_TAP_TIMEOUT) } @Test @@ -112,6 +107,20 @@ class QSLongPressEffectTest : SysuiTestCase() { } @Test + fun onActionUp_whileWaiting_performsClick() = + testWhileInState(QSLongPressEffect.State.TIMEOUT_WAIT) { + // GIVEN an action is being collected + val action by collectLastValue(longPressEffect.actionType) + + // GIVEN an action up occurs + longPressEffect.handleActionUp() + + // THEN the action to invoke is the click action and the effect does not start + assertThat(action).isEqualTo(QSLongPressEffect.ActionType.CLICK) + assertEffectDidNotStart() + } + + @Test fun onWaitComplete_whileWaiting_beginsEffect() = testWhileInState(QSLongPressEffect.State.TIMEOUT_WAIT) { // GIVEN the pressed timeout is complete @@ -212,10 +221,8 @@ class QSLongPressEffectTest : SysuiTestCase() { // GIVEN that the animator was cancelled longPressEffect.handleAnimationCancel() - // THEN the state goes to the timeout wait and the wait is posted - val action by collectLastValue(longPressEffect.actionType) + // THEN the state goes to the timeout wait assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.TIMEOUT_WAIT) - assertThat(action).isEqualTo(QSLongPressEffect.ActionType.WAIT_TAP_TIMEOUT) } @Test @@ -231,29 +238,6 @@ class QSLongPressEffectTest : SysuiTestCase() { assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.IDLE) } - @Test - fun onTileClick_whileWaiting_withQSTile_clicks() = - testWhileInState(QSLongPressEffect.State.TIMEOUT_WAIT) { - // GIVEN that a click was detected - val couldClick = longPressEffect.onTileClick() - - // THEN the click is successful - assertThat(couldClick).isTrue() - } - - @Test - fun onTileClick_whileWaiting_withoutQSTile_cannotClick() = - testWhileInState(QSLongPressEffect.State.TIMEOUT_WAIT) { - // GIVEN that no QSTile has been set - longPressEffect.qsTile = null - - // GIVEN that a click was detected - val couldClick = longPressEffect.onTileClick() - - // THEN the click is not successful - assertThat(couldClick).isFalse() - } - private fun testWithScope(initialize: Boolean = true, test: suspend TestScope.() -> Unit) = with(kosmos) { testScope.runTest { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelTest.kt index bf3231e6e59d..79671b885c56 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelTest.kt @@ -53,7 +53,7 @@ class DozingToGoneTransitionViewModelTest : SysuiTestCase() { @Test fun lockscreenAlpha() = testScope.runTest { - val viewState = ViewStateAccessor() + val viewState = ViewStateAccessor(alpha = { 0.6f }) val alpha by collectValues(underTest.lockscreenAlpha(viewState)) keyguardTransitionRepository.sendTransitionSteps( @@ -62,9 +62,11 @@ class DozingToGoneTransitionViewModelTest : SysuiTestCase() { testScope ) - // Remain at zero throughout - assertThat(alpha[0]).isEqualTo(0f) + assertThat(alpha[0]).isEqualTo(0.6f) + // Fades out just prior to halfway assertThat(alpha[1]).isEqualTo(0f) + // Must finish at 0 + assertThat(alpha[2]).isEqualTo(0f) } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeSceneViewModelTest.kt index 9d8ec951dfe7..6b1794e28237 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeSceneViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeSceneViewModelTest.kt @@ -30,7 +30,9 @@ import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.kosmos.testScope +import com.android.systemui.scene.domain.interactor.homeSceneFamilyResolver import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.ui.viewmodel.notificationsShadeSceneViewModel import com.android.systemui.testKosmos @@ -62,7 +64,9 @@ class NotificationsShadeSceneViewModelTest : SysuiTestCase() { val destinationScenes by collectLastValue(underTest.destinationScenes) lockDevice() - assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(Scenes.Lockscreen) + assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(SceneFamilies.Home) + assertThat(kosmos.homeSceneFamilyResolver.resolvedScene.value) + .isEqualTo(Scenes.Lockscreen) } @Test @@ -72,7 +76,8 @@ class NotificationsShadeSceneViewModelTest : SysuiTestCase() { lockDevice() unlockDevice() - assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(Scenes.Gone) + assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(SceneFamilies.Home) + assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Gone) } @Test @@ -85,7 +90,9 @@ class NotificationsShadeSceneViewModelTest : SysuiTestCase() { ) sceneInteractor.changeScene(Scenes.Lockscreen, "reason") - assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(Scenes.Lockscreen) + assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(SceneFamilies.Home) + assertThat(kosmos.homeSceneFamilyResolver.resolvedScene.value) + .isEqualTo(Scenes.Lockscreen) } @Test @@ -96,10 +103,12 @@ class NotificationsShadeSceneViewModelTest : SysuiTestCase() { kosmos.fakeAuthenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.None ) + sceneInteractor // force the lazy; this will kick off StateFlows runCurrent() sceneInteractor.changeScene(Scenes.Gone, "reason") - assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(Scenes.Gone) + assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(SceneFamilies.Home) + assertThat(kosmos.homeSceneFamilyResolver.resolvedScene.value).isEqualTo(Scenes.Gone) } private fun TestScope.lockDevice() { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt index 7388d51a7cf0..b35b7bca4809 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt @@ -164,25 +164,16 @@ class QSSceneAdapterImplTest : SysuiTestCase() { with(qsImpl!!) { verify(this).setQsVisible(false) - verify(this, never()) + verify(this) .setQsExpansion( - /* expansion= */ anyFloat(), - /* panelExpansionFraction= */ anyFloat(), - /* proposedTranslation= */ anyFloat(), - /* squishinessFraction= */ anyFloat(), + /* expansion= */ 0f, + /* panelExpansionFraction= */ 1f, + /* proposedTranslation= */ 0f, + /* squishinessFraction= */ 1f, ) verify(this).setListening(false) verify(this).setExpanded(false) } - - underTest.applyLatestExpansionAndSquishiness() - verify(qsImpl!!) - .setQsExpansion( - /* expansion= */ 0f, - /* panelExpansionFraction= */ 1f, - /* proposedTranslation= */ 0f, - /* squishinessFraction= */ 1f, - ) } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt index 0b55befce932..7ee20e587059 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt @@ -28,7 +28,6 @@ import com.android.systemui.authentication.data.repository.fakeAuthenticationRep import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository -import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.flags.Flags import com.android.systemui.flags.fakeFeatureFlagsClassic @@ -36,16 +35,17 @@ import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintA import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.kosmos.testScope import com.android.systemui.media.controls.data.repository.mediaFilterRepository -import com.android.systemui.media.controls.domain.pipeline.MediaDataManager import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor import com.android.systemui.media.controls.shared.model.MediaData import com.android.systemui.qs.FooterActionsController import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter import com.android.systemui.res.R +import com.android.systemui.scene.domain.interactor.homeSceneFamilyResolver import com.android.systemui.scene.domain.interactor.sceneBackInteractor import com.android.systemui.scene.domain.interactor.sceneContainerStartable import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.settings.brightness.ui.viewmodel.brightnessMirrorViewModel import com.android.systemui.shade.ui.viewmodel.shadeHeaderViewModel @@ -55,7 +55,6 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test @@ -82,11 +81,8 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { private val sceneBackInteractor = kosmos.sceneBackInteractor private val sceneContainerStartable = kosmos.sceneContainerStartable - private val mediaDataManager = mock<MediaDataManager>() - private lateinit var underTest: QuickSettingsSceneViewModel - @OptIn(ExperimentalCoroutinesApi::class) @Before fun setUp() { kosmos.fakeFeatureFlagsClassic.set(Flags.NEW_NETWORK_SLICE_UI, false) @@ -95,7 +91,6 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { underTest = QuickSettingsSceneViewModel( applicationScope = testScope.backgroundScope, - deviceEntryInteractor = kosmos.deviceEntryInteractor, brightnessMirrorViewModel = kosmos.brightnessMirrorViewModel, shadeHeaderViewModel = kosmos.shadeHeaderViewModel, qsSceneAdapter = qsFlexiglassAdapter, @@ -112,6 +107,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { testScope.runTest { overrideResource(R.bool.config_use_split_notification_shade, false) val destinations by collectLastValue(underTest.destinationScenes) + val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene) qsFlexiglassAdapter.setCustomizing(false) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.Pin @@ -128,9 +124,10 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { Swipe( fromSource = Edge.Bottom, direction = SwipeDirection.Up, - ) to UserActionResult(Scenes.Gone) + ) to UserActionResult(SceneFamilies.Home) ) ) + assertThat(homeScene).isEqualTo(Scenes.Gone) } @Test @@ -142,6 +139,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { val currentScene by collectLastValue(sceneInteractor.currentScene) val backScene by collectLastValue(sceneBackInteractor.backScene) + val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene) sceneInteractor.changeScene(Scenes.Lockscreen, "reason") sceneInteractor.changeScene(Scenes.QuickSettings, "reason") assertThat(currentScene).isEqualTo(Scenes.QuickSettings) @@ -155,9 +153,10 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { Swipe( fromSource = Edge.Bottom, direction = SwipeDirection.Up, - ) to UserActionResult(Scenes.Lockscreen) + ) to UserActionResult(SceneFamilies.Home) ) ) + assertThat(homeScene).isEqualTo(Scenes.Lockscreen) } @Test @@ -165,6 +164,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { testScope.runTest { overrideResource(R.bool.config_use_split_notification_shade, false) val destinations by collectLastValue(underTest.destinationScenes) + val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene) qsFlexiglassAdapter.setCustomizing(false) kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( @@ -179,9 +179,10 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { Swipe( fromSource = Edge.Bottom, direction = SwipeDirection.Up, - ) to UserActionResult(Scenes.Lockscreen) + ) to UserActionResult(SceneFamilies.Home) ) ) + assertThat(homeScene).isEqualTo(Scenes.Lockscreen) } @Test @@ -199,6 +200,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { testScope.runTest { overrideResource(R.bool.config_use_split_notification_shade, true) val destinations by collectLastValue(underTest.destinationScenes) + val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene) qsFlexiglassAdapter.setCustomizing(false) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.Pin @@ -215,9 +217,10 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { Swipe( fromSource = Edge.Bottom, direction = SwipeDirection.Up, - ) to UserActionResult(Scenes.Gone), + ) to UserActionResult(SceneFamilies.Home) ) ) + assertThat(homeScene).isEqualTo(Scenes.Gone) } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModelTest.kt index 034c2e9b6789..f28ddebb6e9d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModelTest.kt @@ -30,7 +30,9 @@ import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.kosmos.testScope +import com.android.systemui.scene.domain.interactor.homeSceneFamilyResolver import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.ui.viewmodel.quickSettingsShadeSceneViewModel import com.android.systemui.testKosmos @@ -60,38 +62,45 @@ class QuickSettingsShadeSceneViewModelTest : SysuiTestCase() { fun upTransitionSceneKey_deviceLocked_lockscreen() = testScope.runTest { val destinationScenes by collectLastValue(underTest.destinationScenes) + val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene) lockDevice() - assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(Scenes.Lockscreen) + assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(SceneFamilies.Home) + assertThat(homeScene).isEqualTo(Scenes.Lockscreen) } @Test fun upTransitionSceneKey_deviceUnlocked_gone() = testScope.runTest { val destinationScenes by collectLastValue(underTest.destinationScenes) + val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene) lockDevice() unlockDevice() - assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(Scenes.Gone) + assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(SceneFamilies.Home) + assertThat(homeScene).isEqualTo(Scenes.Gone) } @Test fun upTransitionSceneKey_authMethodSwipe_lockscreenNotDismissed_goesToLockscreen() = testScope.runTest { val destinationScenes by collectLastValue(underTest.destinationScenes) + val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene) kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.None ) sceneInteractor.changeScene(Scenes.Lockscreen, "reason") - assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(Scenes.Lockscreen) + assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(SceneFamilies.Home) + assertThat(homeScene).isEqualTo(Scenes.Lockscreen) } @Test fun upTransitionSceneKey_authMethodSwipe_lockscreenDismissed_goesToGone() = testScope.runTest { val destinationScenes by collectLastValue(underTest.destinationScenes) + val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene) kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.None @@ -99,7 +108,8 @@ class QuickSettingsShadeSceneViewModelTest : SysuiTestCase() { runCurrent() sceneInteractor.changeScene(Scenes.Gone, "reason") - assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(Scenes.Gone) + assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(SceneFamilies.Home) + assertThat(homeScene).isEqualTo(Scenes.Gone) } private fun TestScope.lockDevice() { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt index 9e7e766cb820..f8a62cb65309 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt @@ -51,7 +51,6 @@ import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel import com.android.systemui.kosmos.testScope -import com.android.systemui.media.controls.domain.pipeline.MediaDataManager import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest @@ -59,8 +58,10 @@ import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.qs.footerActionsController import com.android.systemui.qs.footerActionsViewModelFactory import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter +import com.android.systemui.scene.domain.interactor.homeSceneFamilyResolver import com.android.systemui.scene.domain.interactor.sceneContainerStartable import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.fakeSceneDataSource import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel @@ -91,7 +92,6 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @@ -169,8 +169,6 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { private val qsFlexiglassAdapter = FakeQSSceneAdapter(inflateDelegate = { mock() }) - @Mock private lateinit var mediaDataManager: MediaDataManager - private lateinit var emergencyAffordanceManager: EmergencyAffordanceManager private lateinit var telecomManager: TelecomManager private val fakeSceneDataSource = kosmos.fakeSceneDataSource @@ -205,7 +203,6 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { shadeSceneViewModel = ShadeSceneViewModel( applicationScope = testScope.backgroundScope, - deviceEntryInteractor = deviceEntryInteractor, shadeHeaderViewModel = kosmos.shadeHeaderViewModel, qsSceneAdapter = qsFlexiglassAdapter, notifications = kosmos.notificationsPlaceholderViewModel, @@ -280,6 +277,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { fun swipeUpOnShadeScene_withAuthMethodSwipe_lockscreenNotDismissed_goesToLockscreen() = testScope.runTest { val destinationScenes by collectLastValue(shadeSceneViewModel.destinationScenes) + val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene) setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = true) assertCurrentScene(Scenes.Lockscreen) @@ -288,9 +286,10 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { assertCurrentScene(Scenes.Shade) val upDestinationSceneKey = destinationScenes?.get(Swipe.Up)?.toScene - assertThat(upDestinationSceneKey).isEqualTo(Scenes.Lockscreen) + assertThat(upDestinationSceneKey).isEqualTo(SceneFamilies.Home) + assertThat(homeScene).isEqualTo(Scenes.Lockscreen) emulateUserDrivenTransition( - to = upDestinationSceneKey, + to = homeScene, ) } @@ -299,6 +298,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { testScope.runTest { val destinationScenes by collectLastValue(shadeSceneViewModel.destinationScenes) val canSwipeToEnter by collectLastValue(deviceEntryInteractor.canSwipeToEnter) + val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene) setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = true) @@ -314,9 +314,10 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { assertCurrentScene(Scenes.Shade) val upDestinationSceneKey = destinationScenes?.get(Swipe.Up)?.toScene - assertThat(upDestinationSceneKey).isEqualTo(Scenes.Gone) + assertThat(upDestinationSceneKey).isEqualTo(SceneFamilies.Home) + assertThat(homeScene).isEqualTo(Scenes.Gone) emulateUserDrivenTransition( - to = upDestinationSceneKey, + to = homeScene, ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt index 229a711d637d..881ce413a022 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt @@ -31,6 +31,7 @@ import com.android.systemui.scene.data.repository.sceneContainerRepository import com.android.systemui.scene.sceneContainerConfig import com.android.systemui.scene.sceneKeys import com.android.systemui.scene.shared.model.SceneContainerConfig +import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.fakeSceneDataSource import com.android.systemui.testKosmos @@ -38,6 +39,7 @@ import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.toList import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test @@ -151,6 +153,18 @@ class SceneInteractorTest : SysuiTestCase() { } @Test + fun changeScene_toHomeSceneFamily() = + testScope.runTest { + underTest = kosmos.sceneInteractor + val currentScene by collectLastValue(underTest.currentScene) + + underTest.changeScene(SceneFamilies.Home, "reason") + runCurrent() + + assertThat(currentScene).isEqualTo(kosmos.homeSceneFamilyResolver.resolvedScene.value) + } + + @Test fun snapToScene_toUnknownScene_doesNothing() = testScope.runTest { val sceneKeys = @@ -216,6 +230,18 @@ class SceneInteractorTest : SysuiTestCase() { } @Test + fun snapToScene_toHomeSceneFamily() = + testScope.runTest { + underTest = kosmos.sceneInteractor + val currentScene by collectLastValue(underTest.currentScene) + + underTest.snapToScene(SceneFamilies.Home, "reason") + runCurrent() + + assertThat(currentScene).isEqualTo(kosmos.homeSceneFamilyResolver.resolvedScene.value) + } + + @Test fun sceneChanged_inDataSource() = testScope.runTest { underTest = kosmos.sceneInteractor @@ -428,4 +454,20 @@ class SceneInteractorTest : SysuiTestCase() { assertThat(isVisible).isFalse() } + + @Test + fun resolveSceneFamily_home() = + testScope.runTest { + underTest = kosmos.sceneInteractor + assertThat(underTest.resolveSceneFamily(SceneFamilies.Home)) + .isEqualTo(kosmos.homeSceneFamilyResolver.resolvedScene) + } + + @Test + fun resolveSceneFamily_nonFamily() = + testScope.runTest { + underTest = kosmos.sceneInteractor + val resolved = underTest.resolveSceneFamily(Scenes.Gone).toList() + assertThat(resolved).containsExactly(Scenes.Gone).inOrder() + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImplTest.kt index 468c39daa282..3a5ff009c4fd 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImplTest.kt @@ -29,6 +29,7 @@ import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.kosmos.testScope +import com.android.systemui.scene.domain.interactor.homeSceneFamilyResolver import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shared.recents.utilities.Utilities @@ -36,6 +37,7 @@ import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest @@ -77,6 +79,8 @@ class ShadeBackActionInteractorImplTest : SysuiTestCase() { @Test fun animateCollapseQs_fullyCollapse_entered() = testScope.runTest { + // Ensure that HomeSceneFamilyResolver is running + kosmos.homeSceneFamilyResolver.resolvedScene.launchIn(backgroundScope) val actual by collectLastValue(sceneInteractor.currentScene) enterDevice() setScene(Scenes.QuickSettings) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt index 482dc5d992f0..f88d10242e04 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt @@ -27,7 +27,6 @@ import com.android.systemui.authentication.shared.model.AuthenticationMethodMode import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository -import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus @@ -40,7 +39,9 @@ import com.android.systemui.qs.footerActionsController import com.android.systemui.qs.footerActionsViewModelFactory import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter import com.android.systemui.res.R +import com.android.systemui.scene.domain.interactor.homeSceneFamilyResolver import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade import com.android.systemui.settings.brightness.ui.viewmodel.brightnessMirrorViewModel @@ -75,7 +76,6 @@ class ShadeSceneViewModelTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope private val sceneInteractor by lazy { kosmos.sceneInteractor } - private val deviceEntryInteractor by lazy { kosmos.deviceEntryInteractor } private val shadeRepository by lazy { kosmos.shadeRepository } private val qsSceneAdapter = FakeQSSceneAdapter({ mock() }) @@ -91,7 +91,6 @@ class ShadeSceneViewModelTest : SysuiTestCase() { underTest = ShadeSceneViewModel( applicationScope = testScope.backgroundScope, - deviceEntryInteractor = deviceEntryInteractor, shadeHeaderViewModel = kosmos.shadeHeaderViewModel, qsSceneAdapter = qsSceneAdapter, notifications = kosmos.notificationsPlaceholderViewModel, @@ -109,18 +108,21 @@ class ShadeSceneViewModelTest : SysuiTestCase() { fun upTransitionSceneKey_deviceLocked_lockScreen() = testScope.runTest { val destinationScenes by collectLastValue(underTest.destinationScenes) + val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.Pin ) assertThat(destinationScenes?.get(Swipe(SwipeDirection.Up))?.toScene) - .isEqualTo(Scenes.Lockscreen) + .isEqualTo(SceneFamilies.Home) + assertThat(homeScene).isEqualTo(Scenes.Lockscreen) } @Test fun upTransitionSceneKey_deviceUnlocked_gone() = testScope.runTest { val destinationScenes by collectLastValue(underTest.destinationScenes) + val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.Pin ) @@ -129,13 +131,15 @@ class ShadeSceneViewModelTest : SysuiTestCase() { ) assertThat(destinationScenes?.get(Swipe(SwipeDirection.Up))?.toScene) - .isEqualTo(Scenes.Gone) + .isEqualTo(SceneFamilies.Home) + assertThat(homeScene).isEqualTo(Scenes.Gone) } @Test fun upTransitionSceneKey_authMethodSwipe_lockscreenNotDismissed_goesToLockscreen() = testScope.runTest { val destinationScenes by collectLastValue(underTest.destinationScenes) + val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene) kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.None @@ -143,13 +147,15 @@ class ShadeSceneViewModelTest : SysuiTestCase() { sceneInteractor.changeScene(Scenes.Lockscreen, "reason") assertThat(destinationScenes?.get(Swipe(SwipeDirection.Up))?.toScene) - .isEqualTo(Scenes.Lockscreen) + .isEqualTo(SceneFamilies.Home) + assertThat(homeScene).isEqualTo(Scenes.Lockscreen) } @Test fun upTransitionSceneKey_authMethodSwipe_lockscreenDismissed_goesToGone() = testScope.runTest { val destinationScenes by collectLastValue(underTest.destinationScenes) + val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene) kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.None @@ -158,7 +164,8 @@ class ShadeSceneViewModelTest : SysuiTestCase() { sceneInteractor.changeScene(Scenes.Gone, "reason") assertThat(destinationScenes?.get(Swipe(SwipeDirection.Up))?.toScene) - .isEqualTo(Scenes.Gone) + .isEqualTo(SceneFamilies.Home) + assertThat(homeScene).isEqualTo(Scenes.Gone) } @Test diff --git a/packages/SystemUI/res/drawable/audio_bars_playing.xml b/packages/SystemUI/res/drawable/audio_bars_playing.xml new file mode 100644 index 000000000000..6a6706a73f64 --- /dev/null +++ b/packages/SystemUI/res/drawable/audio_bars_playing.xml @@ -0,0 +1,457 @@ +<!-- + ~ 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. + --> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt"> + <target android:name="_R_G_L_4_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="283" + android:propertyName="pathData" + android:startOffset="0" + android:valueFrom="M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " + android:valueTo="M-37.16 -13.39 C-33.94,-13.39 -31.32,-10.83 -31.2,-7.64 C-31.2,-7.57 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,6.79 -31.2,6.86 C-31.31,10.05 -33.94,12.61 -37.16,12.61 C-40.39,12.61 -43.01,10.05 -43.12,6.85 C-43.12,6.79 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-7.58 -43.12,-7.66 C-42.99,-10.84 -40.37,-13.39 -37.16,-13.39c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="433" + android:propertyName="pathData" + android:startOffset="283" + android:valueFrom="M-37.16 -13.39 C-33.94,-13.39 -31.32,-10.83 -31.2,-7.64 C-31.2,-7.57 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,6.79 -31.2,6.86 C-31.31,10.05 -33.94,12.61 -37.16,12.61 C-40.39,12.61 -43.01,10.05 -43.12,6.85 C-43.12,6.79 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-7.58 -43.12,-7.66 C-42.99,-10.84 -40.37,-13.39 -37.16,-13.39c " + android:valueTo="M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="417" + android:propertyName="pathData" + android:startOffset="717" + android:valueFrom="M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " + android:valueTo="M-37.16 -13.39 C-33.94,-13.39 -31.32,-10.83 -31.2,-7.64 C-31.2,-7.57 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,6.79 -31.2,6.86 C-31.31,10.05 -33.94,12.61 -37.16,12.61 C-40.39,12.61 -43.01,10.05 -43.12,6.85 C-43.12,6.79 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-7.58 -43.12,-7.66 C-42.99,-10.84 -40.37,-13.39 -37.16,-13.39c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="467" + android:propertyName="pathData" + android:startOffset="1133" + android:valueFrom="M-37.16 -13.39 C-33.94,-13.39 -31.32,-10.83 -31.2,-7.64 C-31.2,-7.57 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,6.79 -31.2,6.86 C-31.31,10.05 -33.94,12.61 -37.16,12.61 C-40.39,12.61 -43.01,10.05 -43.12,6.85 C-43.12,6.79 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-7.58 -43.12,-7.66 C-42.99,-10.84 -40.37,-13.39 -37.16,-13.39c " + android:valueTo="M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="433" + android:propertyName="pathData" + android:startOffset="1600" + android:valueFrom="M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " + android:valueTo="M-37.16 -13.39 C-33.94,-13.39 -31.32,-10.83 -31.2,-7.64 C-31.2,-7.57 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,6.79 -31.2,6.86 C-31.31,10.05 -33.94,12.61 -37.16,12.61 C-40.39,12.61 -43.01,10.05 -43.12,6.85 C-43.12,6.79 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-7.58 -43.12,-7.66 C-42.99,-10.84 -40.37,-13.39 -37.16,-13.39c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="517" + android:propertyName="pathData" + android:startOffset="2033" + android:valueFrom="M-37.16 -13.39 C-33.94,-13.39 -31.32,-10.83 -31.2,-7.64 C-31.2,-7.57 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,6.79 -31.2,6.86 C-31.31,10.05 -33.94,12.61 -37.16,12.61 C-40.39,12.61 -43.01,10.05 -43.12,6.85 C-43.12,6.79 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-7.58 -43.12,-7.66 C-42.99,-10.84 -40.37,-13.39 -37.16,-13.39c " + android:valueTo="M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_3_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="367" + android:propertyName="pathData" + android:startOffset="0" + android:valueFrom="M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " + android:valueTo="M-37.16 -18.51 C-33.94,-18.51 -31.32,-15.96 -31.2,-12.77 C-31.2,-12.7 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,13.16 -31.2,13.23 C-31.31,16.43 -33.94,18.99 -37.16,18.99 C-40.39,18.99 -43.01,16.43 -43.12,13.23 C-43.12,13.16 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-12.71 -43.12,-12.78 C-42.99,-15.97 -40.37,-18.51 -37.16,-18.51c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="433" + android:propertyName="pathData" + android:startOffset="367" + android:valueFrom="M-37.16 -18.51 C-33.94,-18.51 -31.32,-15.96 -31.2,-12.77 C-31.2,-12.7 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,13.16 -31.2,13.23 C-31.31,16.43 -33.94,18.99 -37.16,18.99 C-40.39,18.99 -43.01,16.43 -43.12,13.23 C-43.12,13.16 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-12.71 -43.12,-12.78 C-42.99,-15.97 -40.37,-18.51 -37.16,-18.51c " + android:valueTo="M-37.16 -9.14 C-33.94,-9.14 -31.32,-6.58 -31.2,-3.39 C-31.2,-3.32 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,3.79 -31.2,3.86 C-31.31,7.05 -33.94,9.61 -37.16,9.61 C-40.39,9.61 -43.01,7.05 -43.12,3.85 C-43.12,3.79 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-3.33 -43.12,-3.41 C-42.99,-6.59 -40.37,-9.14 -37.16,-9.14c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="417" + android:propertyName="pathData" + android:startOffset="800" + android:valueFrom="M-37.16 -9.14 C-33.94,-9.14 -31.32,-6.58 -31.2,-3.39 C-31.2,-3.32 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,3.79 -31.2,3.86 C-31.31,7.05 -33.94,9.61 -37.16,9.61 C-40.39,9.61 -43.01,7.05 -43.12,3.85 C-43.12,3.79 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-3.33 -43.12,-3.41 C-42.99,-6.59 -40.37,-9.14 -37.16,-9.14c " + android:valueTo="M-37.16 -18.51 C-33.94,-18.51 -31.32,-15.96 -31.2,-12.77 C-31.2,-12.7 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,13.16 -31.2,13.23 C-31.31,16.43 -33.94,18.99 -37.16,18.99 C-40.39,18.99 -43.01,16.43 -43.12,13.23 C-43.12,13.16 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-12.71 -43.12,-12.78 C-42.99,-15.97 -40.37,-18.51 -37.16,-18.51c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="467" + android:propertyName="pathData" + android:startOffset="1217" + android:valueFrom="M-37.16 -18.51 C-33.94,-18.51 -31.32,-15.96 -31.2,-12.77 C-31.2,-12.7 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,13.16 -31.2,13.23 C-31.31,16.43 -33.94,18.99 -37.16,18.99 C-40.39,18.99 -43.01,16.43 -43.12,13.23 C-43.12,13.16 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-12.71 -43.12,-12.78 C-42.99,-15.97 -40.37,-18.51 -37.16,-18.51c " + android:valueTo="M-37.16 -9.14 C-33.94,-9.14 -31.32,-6.58 -31.2,-3.39 C-31.2,-3.32 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,3.79 -31.2,3.86 C-31.31,7.05 -33.94,9.61 -37.16,9.61 C-40.39,9.61 -43.01,7.05 -43.12,3.85 C-43.12,3.79 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-3.33 -43.12,-3.41 C-42.99,-6.59 -40.37,-9.14 -37.16,-9.14c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="450" + android:propertyName="pathData" + android:startOffset="1683" + android:valueFrom="M-37.16 -9.14 C-33.94,-9.14 -31.32,-6.58 -31.2,-3.39 C-31.2,-3.32 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,3.79 -31.2,3.86 C-31.31,7.05 -33.94,9.61 -37.16,9.61 C-40.39,9.61 -43.01,7.05 -43.12,3.85 C-43.12,3.79 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-3.33 -43.12,-3.41 C-42.99,-6.59 -40.37,-9.14 -37.16,-9.14c " + android:valueTo="M-37.16 -18.51 C-33.94,-18.51 -31.32,-15.96 -31.2,-12.77 C-31.2,-12.7 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,13.16 -31.2,13.23 C-31.31,16.43 -33.94,18.99 -37.16,18.99 C-40.39,18.99 -43.01,16.43 -43.12,13.23 C-43.12,13.16 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-12.71 -43.12,-12.78 C-42.99,-15.97 -40.37,-18.51 -37.16,-18.51c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="417" + android:propertyName="pathData" + android:startOffset="2133" + android:valueFrom="M-37.16 -18.51 C-33.94,-18.51 -31.32,-15.96 -31.2,-12.77 C-31.2,-12.7 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,13.16 -31.2,13.23 C-31.31,16.43 -33.94,18.99 -37.16,18.99 C-40.39,18.99 -43.01,16.43 -43.12,13.23 C-43.12,13.16 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-12.71 -43.12,-12.78 C-42.99,-15.97 -40.37,-18.51 -37.16,-18.51c " + android:valueTo="M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_2_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="433" + android:propertyName="pathData" + android:startOffset="0" + android:valueFrom="M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " + android:valueTo="M-37.16 -25.01 C-33.94,-25.01 -31.32,-22.46 -31.2,-19.27 C-31.2,-19.2 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,19.54 -31.2,19.6 C-31.31,22.8 -33.94,25.36 -37.16,25.36 C-40.39,25.36 -43.01,22.8 -43.12,19.6 C-43.12,19.54 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-19.21 -43.12,-19.28 C-42.99,-22.47 -40.37,-25.01 -37.16,-25.01c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="450" + android:propertyName="pathData" + android:startOffset="433" + android:valueFrom="M-37.16 -25.01 C-33.94,-25.01 -31.32,-22.46 -31.2,-19.27 C-31.2,-19.2 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,19.54 -31.2,19.6 C-31.31,22.8 -33.94,25.36 -37.16,25.36 C-40.39,25.36 -43.01,22.8 -43.12,19.6 C-43.12,19.54 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-19.21 -43.12,-19.28 C-42.99,-22.47 -40.37,-25.01 -37.16,-25.01c " + android:valueTo="M-37.16 -15.76 C-33.94,-15.76 -31.32,-13.21 -31.2,-10.02 C-31.2,-9.95 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,10.54 -31.2,10.61 C-31.31,13.8 -33.94,16.36 -37.16,16.36 C-40.39,16.36 -43.01,13.8 -43.12,10.6 C-43.12,10.54 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-9.96 -43.12,-10.03 C-42.99,-13.22 -40.37,-15.76 -37.16,-15.76c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.833,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="417" + android:propertyName="pathData" + android:startOffset="883" + android:valueFrom="M-37.16 -15.76 C-33.94,-15.76 -31.32,-13.21 -31.2,-10.02 C-31.2,-9.95 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,10.54 -31.2,10.61 C-31.31,13.8 -33.94,16.36 -37.16,16.36 C-40.39,16.36 -43.01,13.8 -43.12,10.6 C-43.12,10.54 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-9.96 -43.12,-10.03 C-42.99,-13.22 -40.37,-15.76 -37.16,-15.76c " + android:valueTo="M-37.16 -25.01 C-33.94,-25.01 -31.32,-22.46 -31.2,-19.27 C-31.2,-19.2 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,19.54 -31.2,19.6 C-31.31,22.8 -33.94,25.36 -37.16,25.36 C-40.39,25.36 -43.01,22.8 -43.12,19.6 C-43.12,19.54 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-19.21 -43.12,-19.28 C-42.99,-22.47 -40.37,-25.01 -37.16,-25.01c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="467" + android:propertyName="pathData" + android:startOffset="1300" + android:valueFrom="M-37.16 -25.01 C-33.94,-25.01 -31.32,-22.46 -31.2,-19.27 C-31.2,-19.2 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,19.54 -31.2,19.6 C-31.31,22.8 -33.94,25.36 -37.16,25.36 C-40.39,25.36 -43.01,22.8 -43.12,19.6 C-43.12,19.54 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-19.21 -43.12,-19.28 C-42.99,-22.47 -40.37,-25.01 -37.16,-25.01c " + android:valueTo="M-37.16 -15.76 C-33.94,-15.76 -31.32,-13.21 -31.2,-10.02 C-31.2,-9.95 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,10.54 -31.2,10.61 C-31.31,13.8 -33.94,16.36 -37.16,16.36 C-40.39,16.36 -43.01,13.8 -43.12,10.6 C-43.12,10.54 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-9.96 -43.12,-10.03 C-42.99,-13.22 -40.37,-15.76 -37.16,-15.76c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.833,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="433" + android:propertyName="pathData" + android:startOffset="1767" + android:valueFrom="M-37.16 -15.76 C-33.94,-15.76 -31.32,-13.21 -31.2,-10.02 C-31.2,-9.95 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,10.54 -31.2,10.61 C-31.31,13.8 -33.94,16.36 -37.16,16.36 C-40.39,16.36 -43.01,13.8 -43.12,10.6 C-43.12,10.54 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-9.96 -43.12,-10.03 C-42.99,-13.22 -40.37,-15.76 -37.16,-15.76c " + android:valueTo="M-37.16 -25.01 C-33.94,-25.01 -31.32,-22.46 -31.2,-19.27 C-31.2,-19.2 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,19.54 -31.2,19.6 C-31.31,22.8 -33.94,25.36 -37.16,25.36 C-40.39,25.36 -43.01,22.8 -43.12,19.6 C-43.12,19.54 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-19.21 -43.12,-19.28 C-42.99,-22.47 -40.37,-25.01 -37.16,-25.01c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="350" + android:propertyName="pathData" + android:startOffset="2200" + android:valueFrom="M-37.16 -25.01 C-33.94,-25.01 -31.32,-22.46 -31.2,-19.27 C-31.2,-19.2 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,19.54 -31.2,19.6 C-31.31,22.8 -33.94,25.36 -37.16,25.36 C-40.39,25.36 -43.01,22.8 -43.12,19.6 C-43.12,19.54 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-19.21 -43.12,-19.28 C-42.99,-22.47 -40.37,-25.01 -37.16,-25.01c " + android:valueTo="M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="500" + android:propertyName="pathData" + android:startOffset="0" + android:valueFrom="M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " + android:valueTo="M-37.16 -38.14 C-33.94,-38.14 -31.32,-35.58 -31.2,-32.39 C-31.2,-32.32 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,32.04 -31.2,32.1 C-31.31,35.3 -33.94,37.86 -37.16,37.86 C-40.39,37.86 -43.01,35.3 -43.12,32.1 C-43.12,32.04 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-32.33 -43.12,-32.41 C-42.99,-35.59 -40.37,-38.14 -37.16,-38.14c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="467" + android:propertyName="pathData" + android:startOffset="500" + android:valueFrom="M-37.16 -38.14 C-33.94,-38.14 -31.32,-35.58 -31.2,-32.39 C-31.2,-32.32 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,32.04 -31.2,32.1 C-31.31,35.3 -33.94,37.86 -37.16,37.86 C-40.39,37.86 -43.01,35.3 -43.12,32.1 C-43.12,32.04 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-32.33 -43.12,-32.41 C-42.99,-35.59 -40.37,-38.14 -37.16,-38.14c " + android:valueTo="M-37.16 -19.01 C-33.94,-19.01 -31.32,-16.46 -31.2,-13.27 C-31.2,-13.2 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,13.66 -31.2,13.73 C-31.31,16.93 -33.94,19.49 -37.16,19.49 C-40.39,19.49 -43.01,16.93 -43.12,13.73 C-43.12,13.66 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-13.21 -43.12,-13.28 C-42.99,-16.47 -40.37,-19.01 -37.16,-19.01c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.833,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="383" + android:propertyName="pathData" + android:startOffset="967" + android:valueFrom="M-37.16 -19.01 C-33.94,-19.01 -31.32,-16.46 -31.2,-13.27 C-31.2,-13.2 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,13.66 -31.2,13.73 C-31.31,16.93 -33.94,19.49 -37.16,19.49 C-40.39,19.49 -43.01,16.93 -43.12,13.73 C-43.12,13.66 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-13.21 -43.12,-13.28 C-42.99,-16.47 -40.37,-19.01 -37.16,-19.01c " + android:valueTo="M-37.16 -38.14 C-33.94,-38.14 -31.32,-35.58 -31.2,-32.39 C-31.2,-32.32 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,32.04 -31.2,32.1 C-31.31,35.3 -33.94,37.86 -37.16,37.86 C-40.39,37.86 -43.01,35.3 -43.12,32.1 C-43.12,32.04 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-32.33 -43.12,-32.41 C-42.99,-35.59 -40.37,-38.14 -37.16,-38.14c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="467" + android:propertyName="pathData" + android:startOffset="1350" + android:valueFrom="M-37.16 -38.14 C-33.94,-38.14 -31.32,-35.58 -31.2,-32.39 C-31.2,-32.32 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,32.04 -31.2,32.1 C-31.31,35.3 -33.94,37.86 -37.16,37.86 C-40.39,37.86 -43.01,35.3 -43.12,32.1 C-43.12,32.04 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-32.33 -43.12,-32.41 C-42.99,-35.59 -40.37,-38.14 -37.16,-38.14c " + android:valueTo="M-37.16 -19.01 C-33.94,-19.01 -31.32,-16.46 -31.2,-13.27 C-31.2,-13.2 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,13.66 -31.2,13.73 C-31.31,16.93 -33.94,19.49 -37.16,19.49 C-40.39,19.49 -43.01,16.93 -43.12,13.73 C-43.12,13.66 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-13.21 -43.12,-13.28 C-42.99,-16.47 -40.37,-19.01 -37.16,-19.01c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.833,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="433" + android:propertyName="pathData" + android:startOffset="1817" + android:valueFrom="M-37.16 -19.01 C-33.94,-19.01 -31.32,-16.46 -31.2,-13.27 C-31.2,-13.2 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,13.66 -31.2,13.73 C-31.31,16.93 -33.94,19.49 -37.16,19.49 C-40.39,19.49 -43.01,16.93 -43.12,13.73 C-43.12,13.66 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-13.21 -43.12,-13.28 C-42.99,-16.47 -40.37,-19.01 -37.16,-19.01c " + android:valueTo="M-37.16 -38.14 C-33.94,-38.14 -31.32,-35.58 -31.2,-32.39 C-31.2,-32.32 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,32.04 -31.2,32.1 C-31.31,35.3 -33.94,37.86 -37.16,37.86 C-40.39,37.86 -43.01,35.3 -43.12,32.1 C-43.12,32.04 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-32.33 -43.12,-32.41 C-42.99,-35.59 -40.37,-38.14 -37.16,-38.14c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="300" + android:propertyName="pathData" + android:startOffset="2250" + android:valueFrom="M-37.16 -38.14 C-33.94,-38.14 -31.32,-35.58 -31.2,-32.39 C-31.2,-32.32 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,32.04 -31.2,32.1 C-31.31,35.3 -33.94,37.86 -37.16,37.86 C-40.39,37.86 -43.01,35.3 -43.12,32.1 C-43.12,32.04 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-32.33 -43.12,-32.41 C-42.99,-35.59 -40.37,-38.14 -37.16,-38.14c " + android:valueTo="M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="533" + android:propertyName="pathData" + android:startOffset="0" + android:valueFrom="M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " + android:valueTo="M-37.16 -22.64 C-33.94,-22.64 -31.32,-20.08 -31.2,-16.89 C-31.2,-16.82 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,17.41 -31.2,17.48 C-31.31,20.68 -33.94,23.24 -37.16,23.24 C-40.39,23.24 -43.01,20.68 -43.12,17.48 C-43.12,17.41 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-16.83 -43.12,-16.91 C-42.99,-20.09 -40.37,-22.64 -37.16,-22.64c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="433" + android:propertyName="pathData" + android:startOffset="533" + android:valueFrom="M-37.16 -22.64 C-33.94,-22.64 -31.32,-20.08 -31.2,-16.89 C-31.2,-16.82 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,17.41 -31.2,17.48 C-31.31,20.68 -33.94,23.24 -37.16,23.24 C-40.39,23.24 -43.01,20.68 -43.12,17.48 C-43.12,17.41 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-16.83 -43.12,-16.91 C-42.99,-20.09 -40.37,-22.64 -37.16,-22.64c " + android:valueTo="M-37.18 -14.01 C-33.96,-14.01 -31.33,-11.46 -31.22,-8.27 C-31.22,-8.2 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,8.54 -31.2,8.61 C-31.31,11.8 -33.94,14.36 -37.16,14.36 C-40.39,14.36 -43.01,11.8 -43.12,8.6 C-43.12,8.54 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.14,-8.21 -43.13,-8.28 C-43.01,-11.47 -40.39,-14.01 -37.18,-14.01c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.833,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="417" + android:propertyName="pathData" + android:startOffset="967" + android:valueFrom="M-37.18 -14.01 C-33.96,-14.01 -31.33,-11.46 -31.22,-8.27 C-31.22,-8.2 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,8.54 -31.2,8.61 C-31.31,11.8 -33.94,14.36 -37.16,14.36 C-40.39,14.36 -43.01,11.8 -43.12,8.6 C-43.12,8.54 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.14,-8.21 -43.13,-8.28 C-43.01,-11.47 -40.39,-14.01 -37.18,-14.01c " + android:valueTo="M-37.16 -22.64 C-33.94,-22.64 -31.32,-20.08 -31.2,-16.89 C-31.2,-16.82 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,17.41 -31.2,17.48 C-31.31,20.68 -33.94,23.24 -37.16,23.24 C-40.39,23.24 -43.01,20.68 -43.12,17.48 C-43.12,17.41 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-16.83 -43.12,-16.91 C-42.99,-20.09 -40.37,-22.64 -37.16,-22.64c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="483" + android:propertyName="pathData" + android:startOffset="1383" + android:valueFrom="M-37.16 -22.64 C-33.94,-22.64 -31.32,-20.08 -31.2,-16.89 C-31.2,-16.82 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,17.41 -31.2,17.48 C-31.31,20.68 -33.94,23.24 -37.16,23.24 C-40.39,23.24 -43.01,20.68 -43.12,17.48 C-43.12,17.41 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-16.83 -43.12,-16.91 C-42.99,-20.09 -40.37,-22.64 -37.16,-22.64c " + android:valueTo="M-37.18 -14.01 C-33.96,-14.01 -31.33,-11.46 -31.22,-8.27 C-31.22,-8.2 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,8.54 -31.2,8.61 C-31.31,11.8 -33.94,14.36 -37.16,14.36 C-40.39,14.36 -43.01,11.8 -43.12,8.6 C-43.12,8.54 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.14,-8.21 -43.13,-8.28 C-43.01,-11.47 -40.39,-14.01 -37.18,-14.01c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.833,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="417" + android:propertyName="pathData" + android:startOffset="1867" + android:valueFrom="M-37.18 -14.01 C-33.96,-14.01 -31.33,-11.46 -31.22,-8.27 C-31.22,-8.2 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,8.54 -31.2,8.61 C-31.31,11.8 -33.94,14.36 -37.16,14.36 C-40.39,14.36 -43.01,11.8 -43.12,8.6 C-43.12,8.54 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.14,-8.21 -43.13,-8.28 C-43.01,-11.47 -40.39,-14.01 -37.18,-14.01c " + android:valueTo="M-37.16 -22.64 C-33.94,-22.64 -31.32,-20.08 -31.2,-16.89 C-31.2,-16.82 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,17.41 -31.2,17.48 C-31.31,20.68 -33.94,23.24 -37.16,23.24 C-40.39,23.24 -43.01,20.68 -43.12,17.48 C-43.12,17.41 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-16.83 -43.12,-16.91 C-42.99,-20.09 -40.37,-22.64 -37.16,-22.64c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="267" + android:propertyName="pathData" + android:startOffset="2283" + android:valueFrom="M-37.16 -22.64 C-33.94,-22.64 -31.32,-20.08 -31.2,-16.89 C-31.2,-16.82 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,17.41 -31.2,17.48 C-31.31,20.68 -33.94,23.24 -37.16,23.24 C-40.39,23.24 -43.01,20.68 -43.12,17.48 C-43.12,17.41 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-16.83 -43.12,-16.91 C-42.99,-20.09 -40.37,-22.64 -37.16,-22.64c " + android:valueTo="M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="time_group"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="2567" + android:propertyName="translateX" + android:startOffset="0" + android:valueFrom="0" + android:valueTo="1" + android:valueType="floatType" /> + </set> + </aapt:attr> + </target> + <aapt:attr name="android:drawable"> + <vector + android:width="168dp" + android:height="168dp" + android:viewportHeight="168" + android:viewportWidth="168"> + <group android:name="_R_G"> + <group + android:name="_R_G_L_4_G" + android:translateX="84.411" + android:translateY="83.911"> + <path + android:name="_R_G_L_4_G_D_0_P_0" + android:fillAlpha="1" + android:fillColor="#ffffff" + android:fillType="nonZero" + android:pathData=" M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " /> + </group> + <group + android:name="_R_G_L_3_G" + android:translateX="121.161" + android:translateY="83.911"> + <path + android:name="_R_G_L_3_G_D_0_P_0" + android:fillAlpha="1" + android:fillColor="#ffffff" + android:fillType="nonZero" + android:pathData=" M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " /> + </group> + <group + android:name="_R_G_L_2_G" + android:translateX="102.911" + android:translateY="83.911"> + <path + android:name="_R_G_L_2_G_D_0_P_0" + android:fillAlpha="1" + android:fillColor="#ffffff" + android:fillType="nonZero" + android:pathData=" M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " /> + </group> + <group + android:name="_R_G_L_1_G" + android:translateX="139.661" + android:translateY="83.911"> + <path + android:name="_R_G_L_1_G_D_0_P_0" + android:fillAlpha="1" + android:fillColor="#ffffff" + android:fillType="nonZero" + android:pathData=" M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " /> + </group> + <group + android:name="_R_G_L_0_G" + android:translateX="157.911" + android:translateY="83.911"> + <path + android:name="_R_G_L_0_G_D_0_P_0" + android:fillAlpha="1" + android:fillColor="#ffffff" + android:fillType="nonZero" + android:pathData=" M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " /> + </group> + </group> + <group android:name="time_group" /> + </vector> + </aapt:attr> +</animated-vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/auth_container_view.xml b/packages/SystemUI/res/layout/auth_container_view.xml index 2a1ce1fc5ec6..cc5a27d60ec1 100644 --- a/packages/SystemUI/res/layout/auth_container_view.xml +++ b/packages/SystemUI/res/layout/auth_container_view.xml @@ -28,9 +28,9 @@ <View android:id="@+id/panel" + style="@style/AuthNonCredentialPanelStyle" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?androidprv:attr/materialColorSurfaceContainer" android:elevation="@dimen/biometric_dialog_elevation"/> <ScrollView diff --git a/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml b/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml index 9f4ad0ec8677..ce205ca56549 100644 --- a/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml +++ b/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml @@ -29,10 +29,11 @@ android:layout_gravity="center_vertical" android:layout_marginStart="24dp" android:layout_marginBottom="8dp" - android:ellipsize="end" - android:maxLines="2" android:visibility="invisible" + app:layout_constrainedWidth="true" app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="@id/button_center_guideline" + app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" /> <!-- Cancel Button, replaces negative button when biometric is accepted --> @@ -46,7 +47,10 @@ android:layout_marginBottom="8dp" android:text="@string/cancel" android:visibility="invisible" + app:layout_constrainedWidth="true" app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="@id/button_center_guideline" + app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" /> <!-- "Use Credential" Button, replaces if device credential is allowed --> @@ -59,7 +63,10 @@ android:layout_marginStart="24dp" android:layout_marginBottom="8dp" android:visibility="invisible" + app:layout_constrainedWidth="true" app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="@id/button_center_guideline" + app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" /> <!-- Positive Button --> @@ -71,12 +78,13 @@ android:layout_gravity="center_vertical" android:layout_marginEnd="24dp" android:layout_marginBottom="8dp" - android:ellipsize="end" - android:maxLines="2" android:text="@string/biometric_dialog_confirm" android:visibility="invisible" + app:layout_constrainedWidth="true" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" /> + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="1.0" + app:layout_constraintStart_toStartOf="@id/button_center_guideline" /> <!-- Try Again Button --> <Button @@ -87,11 +95,19 @@ android:layout_gravity="center_vertical" android:layout_marginEnd="24dp" android:layout_marginBottom="8dp" - android:ellipsize="end" - android:maxLines="2" android:text="@string/biometric_dialog_try_again" android:visibility="invisible" + app:layout_constrainedWidth="true" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" /> + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="1.0" + app:layout_constraintStart_toStartOf="@id/button_center_guideline" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/button_center_guideline" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_constraintGuide_percent="0.5" /> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml index 8d50bfa00fd5..4670f34f11a7 100644 --- a/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml +++ b/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml @@ -27,7 +27,6 @@ app:layout_constraintTop_toTopOf="@id/topBarrier" app:layout_constraintWidth_max="@dimen/biometric_prompt_panel_max_width" /> - <include android:id="@+id/button_bar" layout="@layout/biometric_prompt_button_bar" @@ -148,9 +147,10 @@ <TextView android:id="@+id/indicator" style="@style/TextAppearance.AuthCredential.Indicator" - android:layout_width="wrap_content" + android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="24dp" + android:layout_marginHorizontal="24dp" android:accessibilityLiveRegion="assertive" android:fadingEdge="horizontal" android:gravity="center_horizontal" diff --git a/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml index 01b9f7e2e38a..c599f9e05b38 100644 --- a/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml +++ b/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml @@ -179,11 +179,13 @@ android:layout_height="match_parent"> android:fadingEdge="horizontal" android:gravity="center_horizontal" android:scrollHorizontally="true" + android:maxLines="2" app:layout_constraintBottom_toTopOf="@+id/button_bar" app:layout_constraintEnd_toEndOf="@+id/biometric_icon" app:layout_constraintStart_toStartOf="@+id/biometric_icon" app:layout_constraintTop_toBottomOf="@+id/biometric_icon" - app:layout_constraintVertical_bias="0.0" /> + app:layout_constraintVertical_bias="0.0" + app:layout_constraintWidth_max="@dimen/biometric_dialog_indicator_max_width" /> <include android:id="@+id/button_bar" diff --git a/packages/SystemUI/res/layout/screenshot_shelf.xml b/packages/SystemUI/res/layout/screenshot_shelf.xml index f3f472bf4d24..84ab0f1b6ee5 100644 --- a/packages/SystemUI/res/layout/screenshot_shelf.xml +++ b/packages/SystemUI/res/layout/screenshot_shelf.xml @@ -18,6 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" + android:theme="@style/FloatingOverlay" android:layout_width="match_parent" android:layout_height="match_parent" android:clipChildren="false" diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml index 39a1f1f9b85d..ad5621679681 100644 --- a/packages/SystemUI/res/layout/volume_dialog.xml +++ b/packages/SystemUI/res/layout/volume_dialog.xml @@ -13,9 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. --> -<FrameLayout - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:sysui="http://schemas.android.com/apk/res-auto" +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:id="@+id/volume_dialog_container" android:layout_width="wrap_content" @@ -96,16 +94,18 @@ android:paddingLeft="@dimen/volume_dialog_ringer_rows_padding" android:paddingBottom="@dimen/volume_dialog_ringer_rows_padding" android:paddingRight="@dimen/volume_dialog_ringer_rows_padding"> + <com.android.keyguard.AlphaOptimizedImageButton android:id="@+id/settings" - android:src="@drawable/horizontal_ellipsis" android:layout_width="@dimen/volume_dialog_tap_target_size" android:layout_height="@dimen/volume_dialog_tap_target_size" android:layout_gravity="center" - android:contentDescription="@string/accessibility_volume_settings" android:background="@drawable/ripple_drawable_20dp" - android:tint="?androidprv:attr/colorAccent" - android:soundEffectsEnabled="false" /> + android:contentDescription="@string/accessibility_volume_settings" + android:scaleType="centerInside" + android:soundEffectsEnabled="false" + android:src="@drawable/horizontal_ellipsis" + android:tint="?androidprv:attr/colorAccent" /> </FrameLayout> </LinearLayout> diff --git a/packages/SystemUI/res/raw/widget.rec b/packages/SystemUI/res/raw/widget.rec Binary files differdeleted file mode 100644 index a38b23b0078f..000000000000 --- a/packages/SystemUI/res/raw/widget.rec +++ /dev/null diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index a737ec75f92f..c25d8cb4e3f8 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Watter deel van jou toestelervaring is geraak?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Kies soort kwessie"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skermopname"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Werkverrigting"</item> - <item msgid="1627504621139124393">"Gebruikerkoppelvlak"</item> - <item msgid="8309220355268900335">"Battery"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Eenhandmodus"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Gehoortoestelle"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Gehoortoestelle"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Bind nuwe toestel saam"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik om nuwe toestel saam te bind"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Knoppie <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Back"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Oppyl"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Afpyl"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Linkspyl"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Regspyl"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Middel"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Spasie"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"gevou"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"oopgevou"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> batterykrag oor"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Koppel jou stilus aan ’n laaier"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Stilus se battery is amper pap"</string> <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Onlangs gebruik deur <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Word gebruik deur <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Onlangs gebruik deur <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Stelsel"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Verrigting van veelvuldige take"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Invoer"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Appkortpaaie"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Toeganklikheid"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Kortpadsleutels"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Soekkortpaaie"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Vou ikoon in"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Vou ikoon uit"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Sleutelbordlig"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Vlak %1$d van %2$d"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 0d15f6d442cd..ed6a3e16355e 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"የትኛው የመሣሪያዎ ተሞክሮ ክፍል ተጎድቷል?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"የችግሩን አይነት ይምረጡ"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"የማያ መቅረጫ"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"አፈጻጸም"</item> - <item msgid="1627504621139124393">"የተጠቃሚ በይነገፅ"</item> - <item msgid="8309220355268900335">"ባትሪ"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"የአንድ እጅ ሁነታ"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"የመስሚያ መሣሪያዎች"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"የመስማት ችሎታ መሣሪያ"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"አዲስ መሣሪያ ያጣምሩ"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"አዲስ መሣሪያ ለማጣመር ጠቅ ያድርጉ"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"ቅድመ-ቅምጥን ማዘመን አልተቻለም"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"ቅድመ-ቅምጥ"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"የቀጥታ ስርጭት መግለጫ ጽሁፍ"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"የመሣሪያ ማይክሮፎን እገዳ ይነሳ?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"የመሣሪያ ካሜራ እገዳ ይነሳ?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"የመሣሪያ ካሜራ እና ማይክሮፎን እገዳ ይነሳ?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"አዝራር <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"መነሻ"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"ተመለስ"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"የላይ ቀስት"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"የታች ቀስት"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"የግራ ቀስት"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"የቀኝ ቀስት"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"መሃል"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"ክፍተት"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"አስገባ"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"የታጠፈ"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"የተዘረጋ"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ባትሪ ይቀራል"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ብሮስፌዎን ከኃይል መሙያ ጋር ያገናኙ"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"የብሮስፌ ባትሪ ዝቅተኛ ነው"</string> <string name="video_camera" msgid="7654002575156149298">"የቪድዮ ካሜራ"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"በቅርብ ጊዜ በ<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) ጥቅም ላይ ውሏል"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"በ<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ጥቅም ላይ እየዋለ ነው"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"በቅርብ ጊዜ በ<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ጥቅም ላይ ውሏል"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"ሥርዓት"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ብዙ ተግባራትን በተመሳሳይ ጊዜ ማከናወን"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ግብዓት"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"የመተግበሪያ አቋራጮች"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ተደራሽነት"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"የቁልፍ ሰሌዳ አቋራጮች"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"የፍለጋ አቋራጮች"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"መሰብሰቢያ አዶ"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"መዘርጊያ አዶ"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"የቁልፍ ሰሌዳ የጀርባ ብርሃን"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"ደረጃ %1$d ከ %2$d"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 7c998d32dd86..1502765e8fbf 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -361,13 +361,15 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ما هو الجانب الذي تأثّر في تجربة استخدام الجهاز؟"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"اختيار نوع المشكلة"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"تسجيل الشاشة"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"الأداء"</item> - <item msgid="1627504621139124393">"واجهة المستخدم"</item> - <item msgid="8309220355268900335">"البطارية"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"الأداء"</string> + <string name="user_interface" msgid="3712869377953950887">"واجهة المستخدم"</string> + <string name="thermal" msgid="6758074791325414831">"الأداء الحراري"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"وضع \"التصفح بيد واحدة\""</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"سماعات الأذن الطبية"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"سماعات الأذن الطبية"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"إقران جهاز جديد"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"انقر لإقران جهاز جديد"</string> @@ -615,7 +617,7 @@ <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. انقر للتجاهل. قد يتم تجاهل خدمات \"سهولة الاستخدام\"."</string> <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. انقر للتعيين على الاهتزاز."</string> <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. انقر لكتم الصوت."</string> - <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"التحكُّم في مستوى الضجيج"</string> + <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"التحكُّم في مستوى الضوضاء"</string> <string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"الصوت المكاني"</string> <string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"غير مفعّل"</string> <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"تفعيل"</string> @@ -727,11 +729,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"الزر <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Back"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"سهم متّجه للأعلى"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"سهم متّجه للأسفل"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"سهم متّجه لليسار"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"سهم متّجه لليمين"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"وسط"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"مسافة"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1272,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"مطوي"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"غير مطوي"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"النسبة المئوية المتبقية من شحن البطارية: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"مستوى شحن بطارية قلم الشاشة: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"عليك توصيل قلم الشاشة بشاحن."</string> <string name="stylus_battery_low" msgid="7134370101603167096">"بطارية قلم الشاشة منخفضة"</string> <string name="video_camera" msgid="7654002575156149298">"كاميرا فيديو"</string> @@ -1318,23 +1315,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"تم الاستخدام مؤخرًا في <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"قيد الاستخدام في <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"تم الاستخدام مؤخرًا في <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"النظام"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"تعدُّد المهام"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"الإدخال"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"اختصارات التطبيقات"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"تسهيل الاستخدام"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"اختصارات لوحة المفاتيح"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"اختصارات طلبات البحث"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"رمز التصغير"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"رمز التوسيع"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"الإضاءة الخلفية للوحة المفاتيح"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"مستوى الإضاءة: %1$d من %2$d"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index a6ec1a0730db..00d673ea7231 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -361,13 +361,15 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"আপোনাৰ ডিভাইচৰ অভিজ্ঞতাৰ কোনটো অংশ প্ৰভাৱিত হৈছিল?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"সমস্যাৰ প্ৰকাৰ বাছনি কৰক"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"স্ক্ৰীন ৰেকৰ্ড"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"কাৰ্যদক্ষতা"</item> - <item msgid="1627504621139124393">"ব্যৱহাৰকাৰীৰ ইণ্টাৰফে’চ"</item> - <item msgid="8309220355268900335">"বেটাৰী"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"পাৰদৰ্শিতা"</string> + <string name="user_interface" msgid="3712869377953950887">"ব্যৱহাৰকাৰীৰ ইণ্টাৰফে’চ"</string> + <string name="thermal" msgid="6758074791325414831">"থাৰ্মেল"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"এখন হাতেৰে ব্যৱহাৰ কৰা ম’ড"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"শুনাৰ ডিভাইচ"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"শুনাৰ ডিভাইচ"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"নতুন ডিভাইচ পেয়াৰ কৰক"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"নতুন ডিভাইচ পেয়াৰ কৰিবলৈ ক্লিক কৰক"</string> @@ -727,11 +729,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> বুটাম"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"হ\'ম"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"উভতি যাওক"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"ওপৰলৈ নিৰ্দেশ কৰা কাঁড় চিহ্ন"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"তললৈ নিৰ্দেশ কৰা কাঁড় চিহ্ন"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"বাওঁফাললৈ নিৰ্দেশ কৰা কাঁড় চিহ্ন"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"সোঁফাললৈ নিৰ্দেশ কৰা কাঁড় চিহ্ন"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"স্ক্ৰীনৰ মাজত"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"স্পেচ"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"এণ্টাৰ"</string> @@ -1275,7 +1272,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ফ’ল্ড কৰা"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"আনফ’ল্ড কৰা"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> বেটাৰী বাকী আছে"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"ষ্টাইলাছৰ বেটাৰী <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"আপোনাৰ ষ্টাইলাছ এটা চাৰ্জাৰৰ সৈতে সংযোগ কৰক"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"ষ্টাইলাছৰ বেটাৰী কম আছে"</string> <string name="video_camera" msgid="7654002575156149298">"ভিডিঅ’ কেমেৰা"</string> @@ -1318,23 +1315,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"শেহতীয়াকৈ <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)এ ব্যৱহাৰ কৰিছে"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)এ ব্যৱহাৰ কৰি আছে"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"শেহতীয়াকৈ <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)এ ব্যৱহাৰ কৰিছে"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"ছিষ্টেম"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"মাল্টিটাস্কিং"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ইনপুট"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"এপ্ শ্বৰ্টকাটসমূহ"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"সাধ্য সুবিধা"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"কীব’ৰ্ডৰ শ্বৰ্টকাট"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"সন্ধানৰ শ্বৰ্টকাট"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"সংকোচন কৰাৰ চিহ্ন"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"বিস্তাৰ কৰাৰ চিহ্ন"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"কীব’ৰ্ডৰ বেকলাইট"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dৰ %1$d স্তৰ"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index da20087008d1..b3c0058d8368 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cihaz istifadəsinə necə təsir etdi?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Problem növü seçin"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekran qeydəalma"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Performans"</item> - <item msgid="1627504621139124393">"İstifadəçi interfeysi"</item> - <item msgid="8309220355268900335">"Batareya"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Birəlli rejim"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Eşitmə cihazları"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Eşitmə cihazları"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Yeni cihaz birləşdirin"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Yeni cihaz birləşdirmək üçün klikləyin"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Hazır ayar güncəllənmədi"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Hazır Ayar"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Avtomatik subtitrlər"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Cihaz mikrofonu blokdan çıxarılsın?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Cihaz kamerası blokdan çıxarılsın?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Cihaz kamerası və mikrofonu blokdan çıxarılsın?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Düymə <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Əsas səhifə"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Geri"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Yuxarı ox"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Aşağı ox"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Sol ox"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Sağ ox"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Mərkəz"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Boşluq"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Daxil olun"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"qatlanmış"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"açıq"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> enerji qalıb"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Qələmi adapterə qoşun"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Qələm enerjisi azdır"</string> <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Bu yaxınlarda <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) istifadə edib"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) istifadə edir"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Bu yaxınlarda <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) istifadə edib"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Sistem"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Çoxsaylı tapşırıq icrası"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Daxiletmə"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Tətbiq qısayolları"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Xüsusi imkanlar"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Klaviatura qısayolları"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Axtarış qısayolları"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"İkonanı yığcamlaşdırın"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"İkonanı genişləndirin"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatura işığı"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Səviyyə %1$d/%2$d"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index fafe7185b001..22afb40404dd 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -361,13 +361,15 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Na koji deo doživljaja na uređaju je ovo uticalo?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Izaberite tip problema"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Snimanje ekrana"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Učinak"</item> - <item msgid="1627504621139124393">"Korisnički interfejs"</item> - <item msgid="8309220355268900335">"Baterija"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"Performanse"</string> + <string name="user_interface" msgid="3712869377953950887">"Korisnički interfejs"</string> + <string name="thermal" msgid="6758074791325414831">"Termalna kamera"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Režim jednom rukom"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušni aparati"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušni aparati"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Upari novi uređaj"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite da biste uparili nov uređaj"</string> @@ -727,11 +729,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Dugme <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Taster Početna"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Taster Nazad"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Strelica nagore"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Strelica nadole"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Strelica nalevo"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Strelica nadesno"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Taster sa centralnom strelicom"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Razmak"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1272,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zatvoreno"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"otvoreno"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Preostalo je još<xliff:g id="PERCENTAGE">%s</xliff:g> baterije"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Baterija pisaljke je na <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Povežite pisaljku sa punjačem"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Nizak nivo baterije pisaljke"</string> <string name="video_camera" msgid="7654002575156149298">"Video kamera"</string> @@ -1327,6 +1324,8 @@ <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečice pretrage"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za skupljanje"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za proširivanje"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Pozadinsko osvetljenje tastature"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. nivo od %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrole za dom"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 1455a9c0d1b5..4fe7c5a0d09f 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"З чым была звязана праблема, якая вам сустрэлася?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Выберыце тып праблемы"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запіс экрана"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Прадукцыйнасць"</item> - <item msgid="1627504621139124393">"Карыстальніцкі інтэрфейс"</item> - <item msgid="8309220355268900335">"Акумулятар"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Рэжым кіравання адной рукой"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слыхавыя апараты"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слыхавыя апараты"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Спалучыць новую прыладу"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Націсніце, каб спалучыць новую прыладу"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Кнопка <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Назад"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Стрэлка ўверх"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Стрэлка ўніз"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Стрэлка ўлева"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Стрэлка ўправа"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Цэнтр"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Прабел"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"складзена"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"раскладзена"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Засталося зараду: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Падключыце пяро да зараднай прылады"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Нізкі ўзровень зараду пяра"</string> <string name="video_camera" msgid="7654002575156149298">"Відэакамера"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Нядаўна выкарыстоўваўся праграмай \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Зараз выкарыстоўваецца праграмай \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Нядаўна выкарыстоўваўся праграмай \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Сістэма"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Шматзадачнасць"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Увод"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Ярлыкі праграм"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Спецыяльныя магчымасці"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Спалучэнні клавіш"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Пошук спалучэнняў клавіш"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок \"Згарнуць\""</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок \"Разгарнуць\""</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Падсветка клавіятуры"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Узровень %1$d з %2$d"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index a59ca852b442..2cd65db11d54 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"С какво имахте проблем?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Изберете тип проблем"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запис на екрана"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Ефективност"</item> - <item msgid="1627504621139124393">"Потребителски интерфейс"</item> - <item msgid="8309220355268900335">"Батерия"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим за работа с една ръка"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слухови апарати"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слухови апарати"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Сдвояване на ново устройство"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Кликнете за сдвояване на ново устройство"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Бутон „<xliff:g id="NAME">%1$s</xliff:g>“"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Начало"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Назад"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Стрелка за нагоре"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Стрелка за надолу"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Стрелка за наляво"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Стрелка за надясно"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Център"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Интервал"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"затворено"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"отворено"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Оставаща батерия: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Свържете писалката към зарядно устройство"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Батерията на писалката е изтощена"</string> <string name="video_camera" msgid="7654002575156149298">"Видеокамера"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Наскоро използвано от <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Използва се от <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Наскоро използвано от <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Системни"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Изпълняване на няколко задачи едновременно"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Въвеждане"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Преки пътища към приложения"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Достъпност"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Клавишни комбинации"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Търсете клавишни комбинации"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за свиване"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за разгъване"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Подсветка на клавиатурата"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Ниво %1$d от %2$d"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 72e9d5153bfe..f8e350a3d6ad 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ডিভাইস ব্যবহার করার সময় কোথায় অসুবিধা হয়েছিল?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"সমস্যার প্রকার বেছে নিন"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"স্ক্রিন রেকর্ড"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"পারফর্ম্যান্স"</item> - <item msgid="1627504621139124393">"ইউজার ইন্টারফেস"</item> - <item msgid="8309220355268900335">"ব্যাটারি"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"এক হাতে ব্যবহার করার মোড"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"হিয়ারিং ডিভাইস"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"হিয়ারিং ডিভাইস"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"নতুন ডিভাইস পেয়ার করুন"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"নতুন ডিভাইস পেয়ার করতে ক্লিক করুন"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"প্রিসেট আপডেট করা যায়নি"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"প্রিসেট"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"লাইভ ক্যাপশন"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ডিভাইসের মাইক্রোফোন আনব্লক করতে চান?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ডিভাইসের ক্যামেরা আনব্লক করতে চান?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ডিভাইসের ক্যামেরা এবং মাইক্রোফোন আনব্লক করতে চান?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> বোতাম"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"হোম"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"ফিরুন"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"ঊর্ধমুখী তীরচিহ্ন"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"নিম্নমুখী তীরচিহ্ন"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"বাঁদিকের তীরচিহ্ন"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"ডানদিকের তীরচিহ্ন"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"কেন্দ্র"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"এন্টার"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ফোল্ড করা রয়েছে"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ফোল্ড করা নেই"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ব্যাটারির চার্জ বাকি আছে"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"কোনও চার্জারের সাথে আপনার স্টাইলাস কানেক্ট করুন"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"স্টাইলাস ব্যাটারিতে চার্জ কম আছে"</string> <string name="video_camera" msgid="7654002575156149298">"ভিডিও ক্যামেরা"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"সম্প্রতি <xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপে (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) ব্যবহার করা হয়েছে"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপে (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ব্যবহার করা হচ্ছে"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"সম্প্রতি <xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপে (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ব্যবহার করা হয়েছে"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"সিস্টেম"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"মাল্টিটাস্কিং"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ইনপুট"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"অ্যাপ শর্টকাট"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"অ্যাক্সেসিবিলিটি"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"কীবোর্ড শর্টকাট"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"সার্চ শর্টকাট"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"আইকন আড়াল করুন"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"আইকন বড় করুন"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"কীবোর্ড ব্যাকলাইট"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d-এর মধ্যে %1$d লেভেল"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 93c89956dc4c..60c936e04d18 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Koji dio uređaja je imao problem?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Odaberite vrstu problema"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Snimanje ekrana"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Performanse"</item> - <item msgid="1627504621139124393">"Korisnički interfejs"</item> - <item msgid="8309220355268900335">"Baterija"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Način rada jednom rukom"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušni aparati"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušni aparati"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Uparite novi uređaj"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite da uparite novi uređaj"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Ažuriranje zadane postavke nije uspjelo"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Zadana postavka"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Automatski titlovi"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblokirati mikrofon uređaja?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Deblokirati kameru uređaja?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Deblokirati kameru i mikrofon uređaja?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Dugme <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Tipka za početak"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Nazad"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Strelica nagore"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Strelica nadolje"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Strelica ulijevo"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Strelica udesno"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Sredina"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Tipka za razmak"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Tipka za novi red"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"sklopljeno"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"otklopljeno"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Preostalo baterije: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Priključite pisaljku na punjač"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Baterija pisaljke je slaba"</string> <string name="video_camera" msgid="7654002575156149298">"Video kamera"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Nedavno je koristila aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Koristi aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Nedavno je koristila aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Sistem"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Unos"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Prečice aplikacije"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Pristupačnost"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Prečice tastature"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečica pretraživanja"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona sužavanja"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona proširivanja"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Pozadinsko osvjetljenje tastature"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. nivo od %2$d"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 8ad4b922f7f8..a82d6f10a7d8 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"L\'experiència amb el dispositiu s\'ha vist afectada?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecciona el tipus de problema"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravació de pantalla"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Rendiment"</item> - <item msgid="1627504621139124393">"Interfície d\'usuari"</item> - <item msgid="8309220355268900335">"Bateria"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode d\'una mà"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Audiòfons"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Audiòfons"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Vincula un dispositiu nou"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Fes clic per vincular un dispositiu nou"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"No s\'ha pogut actualitzar el valor predefinit"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Valors predefinits"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Subtítols instantanis"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vols desbloquejar el micròfon del dispositiu?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vols desbloquejar la càmera del dispositiu?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vols desbloquejar la càmera i el micròfon del dispositiu?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Botó <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Inici"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Enrere"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Fletxa amunt"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Fletxa avall"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Fletxa esquerra"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Fletxa dreta"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Centre"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Espai"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Retorn"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plegat"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"desplegat"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de bateria"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connecta el llapis òptic a un carregador"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Bateria del llapis òptic baixa"</string> <string name="video_camera" msgid="7654002575156149298">"Càmera de vídeo"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Utilitzat recentment per <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"En ús per <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Utilitzat recentment per <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Sistema"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasca"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Dreceres d\'aplicacions"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibilitat"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Tecles de drecera"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Dreceres de cerca"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Replega la icona"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Desplega la icona"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroil·luminació del teclat"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivell %1$d de %2$d"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 1474458fc84f..9b540ff06f63 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Co v zařízení bylo ovlivněno?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Vyberte druh problém"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Záznam obrazovky"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Výkon"</item> - <item msgid="1627504621139124393">"Uživatelské rozhraní"</item> - <item msgid="8309220355268900335">"Baterie"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Režim jedné ruky"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Naslouchátka"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Naslouchátka"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Spárovat nové zařízení"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknutím spárujete nové zařízení"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Tlačítko <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Zpět"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Šipka nahoru"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Šipka dolů"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Šipka vlevo"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Šipka doprava"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Střed"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"TAB"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Mezerník"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"složené"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"rozložené"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Zbývá <xliff:g id="PERCENTAGE">%s</xliff:g> baterie"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Připojte dotykové pero k nabíječce"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Slabá baterie dotykového pera"</string> <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Nedávno použila aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Právě používán aplikací <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Nedávno použila aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Systém"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Vstup"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Zkratky aplikací"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Přístupnost"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Klávesové zkratky"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Vyhledat zkratky"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona sbalení"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozbalení"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podsvícení klávesnice"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Úroveň %1$d z %2$d"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index d10d3e01ce9c..57353f7f785d 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Hvilken del af din enhedsoplevelse blev påvirket?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Vælg problemtype"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skærmoptagelse"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Ydeevne"</item> - <item msgid="1627504621139124393">"Brugerflade"</item> - <item msgid="8309220355268900335">"Batteri"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enhåndstilstand"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Høreapparater"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Høreapparater"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Par ny enhed"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik for at parre en ny enhed"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Forindstillingen kunne ikke opdateres"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Forindstilling"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Livetekstning"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vil du fjerne blokeringen af enhedens mikrofon?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vil du fjerne blokeringen af enhedens kamera?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vil du fjerne blokeringen af enhedens kamera og mikrofon?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g>-knap"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Tilbage"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Pil op"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Pil ned"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Venstrepil"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Højrepil"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Midtertast"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Mellemrumstast"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"foldet"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"foldet ud"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> batteri tilbage"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Slut din styluspen til en oplader"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Lavt batteriniveau på styluspen"</string> <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Brugt for nylig af <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Bruges af <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Brugt for nylig af <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"System"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Appgenveje"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Hjælpefunktioner"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Tastaturgenveje"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Genveje til søgning"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikon for Skjul"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikon for Udvid"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Tastaturets baggrundslys"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d af %2$d"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 20707acb3bb9..e7fa9b18b5e6 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Welche Bereiche des Geräts waren betroffen?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Art des Problems auswählen"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Bildschirmaufnahme"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Leistung"</item> - <item msgid="1627504621139124393">"Benutzeroberfläche"</item> - <item msgid="8309220355268900335">"Akku"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Einhandmodus"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hörgeräte"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hörgeräte"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Neues Gerät koppeln"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klicken, um neues Gerät zu koppeln"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Voreinstellung konnte nicht aktualisiert werden"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Voreinstellung"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Automatische Untertitel"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Blockierung des Gerätemikrofons aufheben?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Blockierung der Gerätekamera aufheben?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Blockierung von Gerätekamera und Gerätemikrofon aufheben?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Taste <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Pos1"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Zurück"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Aufwärtspfeil"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Abwärtspfeil"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Linkspfeil"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Rechtspfeil"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Zentrieren"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tabulatortaste"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Leertaste"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Eingabetaste"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zugeklappt"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aufgeklappt"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Akku bei <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Schließe deinen Eingabestift an ein Ladegerät an"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Stylus-Akkustand niedrig"</string> <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Kürzlich von <xliff:g id="APP_NAME">%1$s</xliff:g> verwendet (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Verwendet von <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Kürzlich von <xliff:g id="APP_NAME">%1$s</xliff:g> verwendet (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"System"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Eingabe"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"App-Verknüpfungen"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Bedienungshilfen"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Tastenkürzel"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Tastenkürzel suchen"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Symbol „Minimieren“"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Symbol „Maximieren“"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Tastaturbeleuchtung"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d von %2$d"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 403ca4dceaff..23d704da4f3b 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Ποιο κομμάτι της εμπειρίας συσκευής επηρεάστηκε;"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Επιλογή τύπου προβλήματος"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Εγγραφή οθόνης"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Απόδοση"</item> - <item msgid="1627504621139124393">"Διεπαφή χρήστη"</item> - <item msgid="8309220355268900335">"Μπαταρία"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Λειτουργία ενός χεριού"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Συσκευές ακοής"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Συσκευές ακοής"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Σύζευξη νέας συσκευής"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Κάντε κλικ για σύζευξη νέας συσκευής"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Δεν ήταν δυνατή η ενημέρωση της προεπιλογής"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Προεπιλογή"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Ζωντανοί υπότιτλοι"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Κατάργηση αποκλεισμού μικροφώνου συσκευής;"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Κατάργηση αποκλεισμού κάμερας συσκευής;"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Κατάργηση αποκλεισμού κάμερας και μικροφώνου συσκευής;"</string> @@ -620,7 +624,7 @@ <string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"Χωρικός ήχος"</string> <string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"Ανενεργός"</string> <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"Σταθερός"</string> - <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Παρακ. κίνησ. κεφαλ."</string> + <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Παρακ. κίνησ. κεφαλής"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Πατήστε για να αλλάξετε τη λειτουργία ειδοποίησης ήχου"</string> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"σίγαση"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"κατάργηση σίγασης"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Κουμπί <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Πίσω"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Επάνω βέλος"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Κάτω βέλος"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Αριστερό βέλος"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Δεξί βέλος"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Κέντρο"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Πλήκτρο διαστήματος"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"διπλωμένη"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ξεδιπλωμένη"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Απομένει το <xliff:g id="PERCENTAGE">%s</xliff:g> της μπαταρίας"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Συνδέστε τη γραφίδα σε έναν φορτιστή"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Χαμηλή στάθμη μπαταρίας γραφίδας"</string> <string name="video_camera" msgid="7654002575156149298">"Βιντεοκάμερα"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Χρησιμοποιήθηκε πρόσφατα από την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Χρησιμοποιείται από την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Χρησιμοποιήθηκε πρόσφατα από την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Σύστημα"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Πολυδιεργασία"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Είσοδος"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Συντομεύσεις εφαρμογών"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Προσβασιμότητα"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Συντομεύσεις πληκτρολογίου"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Συντομεύσεις αναζήτησης"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Εικονίδιο σύμπτυξης"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Εικονίδιο ανάπτυξης"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Οπίσθιος φωτισμός πληκτρολογίου"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Επίπεδο %1$d από %2$d"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 83dffc8ea6c1..d71ff1cc42be 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -361,13 +361,15 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"What part of your device experience was affected?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Select issue type"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Screen record"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Performance"</item> - <item msgid="1627504621139124393">"User interface"</item> - <item msgid="8309220355268900335">"Battery"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"Performance"</string> + <string name="user_interface" msgid="3712869377953950887">"User interface"</string> + <string name="thermal" msgid="6758074791325414831">"Thermal"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hearing devices"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hearing devices"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string> @@ -727,11 +729,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Button <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Back"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Up arrow"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Down arrow"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Left arrow"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Right arrow"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Centre"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1272,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"folded"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"unfolded"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> battery remaining"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Stylus battery <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connect your stylus to a charger"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Stylus battery low"</string> <string name="video_camera" msgid="7654002575156149298">"Video camera"</string> @@ -1318,23 +1315,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Recently used by <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"In use by <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Recently used by <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"System"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"App shortcuts"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibility"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Keyboard shortcuts"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index b1cdcb10d861..44e9d25a4d7f 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -361,13 +361,13 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"What part of your device experience was affected?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Select issue type"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Screen record"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Performance"</item> - <item msgid="1627504621139124393">"User Interface"</item> - <item msgid="8309220355268900335">"Battery"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"Performance"</string> + <string name="user_interface" msgid="3712869377953950887">"User Interface"</string> + <string name="thermal" msgid="6758074791325414831">"Thermal"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hearing devices"</string> + <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Active"</string> + <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Disconnected"</string> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hearing devices"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string> @@ -727,11 +727,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Button <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Back"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Up arrow"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Down arrow"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Left arrow"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Right arrow"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Center"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1270,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"folded"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"unfolded"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> battery remaining"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Stylus battery <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connect your stylus to a charger"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Stylus battery low"</string> <string name="video_camera" msgid="7654002575156149298">"Video camera"</string> @@ -1327,6 +1322,8 @@ <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Home Controls"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 83dffc8ea6c1..d71ff1cc42be 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -361,13 +361,15 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"What part of your device experience was affected?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Select issue type"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Screen record"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Performance"</item> - <item msgid="1627504621139124393">"User interface"</item> - <item msgid="8309220355268900335">"Battery"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"Performance"</string> + <string name="user_interface" msgid="3712869377953950887">"User interface"</string> + <string name="thermal" msgid="6758074791325414831">"Thermal"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hearing devices"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hearing devices"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string> @@ -727,11 +729,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Button <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Back"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Up arrow"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Down arrow"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Left arrow"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Right arrow"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Centre"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1272,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"folded"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"unfolded"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> battery remaining"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Stylus battery <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connect your stylus to a charger"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Stylus battery low"</string> <string name="video_camera" msgid="7654002575156149298">"Video camera"</string> @@ -1318,23 +1315,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Recently used by <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"In use by <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Recently used by <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"System"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"App shortcuts"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibility"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Keyboard shortcuts"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 83dffc8ea6c1..d71ff1cc42be 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -361,13 +361,15 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"What part of your device experience was affected?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Select issue type"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Screen record"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Performance"</item> - <item msgid="1627504621139124393">"User interface"</item> - <item msgid="8309220355268900335">"Battery"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"Performance"</string> + <string name="user_interface" msgid="3712869377953950887">"User interface"</string> + <string name="thermal" msgid="6758074791325414831">"Thermal"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hearing devices"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hearing devices"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string> @@ -727,11 +729,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Button <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Back"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Up arrow"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Down arrow"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Left arrow"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Right arrow"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Centre"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1272,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"folded"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"unfolded"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> battery remaining"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Stylus battery <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connect your stylus to a charger"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Stylus battery low"</string> <string name="video_camera" msgid="7654002575156149298">"Video camera"</string> @@ -1318,23 +1315,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Recently used by <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"In use by <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Recently used by <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"System"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"App shortcuts"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibility"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Keyboard shortcuts"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index bfaccd0595f7..c2f709878881 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -361,13 +361,13 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"What part of your device experience was affected?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Select issue type"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Screen record"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Performance"</item> - <item msgid="1627504621139124393">"User Interface"</item> - <item msgid="8309220355268900335">"Battery"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"Performance"</string> + <string name="user_interface" msgid="3712869377953950887">"User Interface"</string> + <string name="thermal" msgid="6758074791325414831">"Thermal"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hearing devices"</string> + <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Active"</string> + <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Disconnected"</string> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hearing devices"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string> @@ -727,11 +727,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Button <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Back"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Up arrow"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Down arrow"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Left arrow"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Right arrow"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Center"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1270,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"folded"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"unfolded"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> battery remaining"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Stylus battery <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connect your stylus to a charger"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Stylus battery low"</string> <string name="video_camera" msgid="7654002575156149298">"Video camera"</string> @@ -1327,6 +1322,8 @@ <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Home Controls"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 01d2130e0f0c..fd800ad30ee6 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"¿Qué parte de tu exp. del disp. se vio afectada?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Seleccionar tipo de problema"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Grabadora de pant."</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Rendimiento"</item> - <item msgid="1627504621139124393">"Interfaz de usuario"</item> - <item msgid="8309220355268900335">"Batería"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo una mano"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dispositivos auditivos"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dispositivos auditivos"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Vincular dispositivo nuevo"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Haz clic para vincular un dispositivo nuevo"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Botón <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Inicio"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Atrás"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Flecha hacia arriba"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Flecha hacia abajo"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Flecha a la izquierda"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Flecha a la derecha"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Centro"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Espacio"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Intro"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plegado"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"desplegado"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> de batería restante"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecta tu pluma stylus a un cargador"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"La pluma stylus tiene poca batería"</string> <string name="video_camera" msgid="7654002575156149298">"Videocámara"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Uso reciente en <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"En uso por <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Uso reciente en <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Sistema"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Tareas múltiples"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Accesos directos a aplicaciones"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accesibilidad"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Combinaciones de teclas"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Buscar combinaciones de teclas"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícono de contraer"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícono de expandir"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroiluminación del teclado"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivel %1$d de %2$d"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 7fd07f01f030..5bcf582afb13 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"¿Qué parte de tu experiencia se ha visto afectada?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecciona el tipo de problema"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Grabar pantalla"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Rendimiento"</item> - <item msgid="1627504621139124393">"Interfaz de usuario"</item> - <item msgid="8309220355268900335">"Batería"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo Una mano"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Audífonos"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Audífonos"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Emparejar nuevo dispositivo"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Haz clic para emparejar un nuevo dispositivo"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"No se ha podido actualizar el preajuste"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preajuste"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Subtítulos automáticos"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"¿Desbloquear el micrófono del dispositivo?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"¿Desbloquear la cámara del dispositivo?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"¿Desbloquear la cámara y el micrófono del dispositivo?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Botón <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Inicio"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Atrás"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Flecha hacia arriba"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Flecha hacia abajo"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Flecha izquierda"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Flecha derecha"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Centro"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tabulador"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Espacio"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Intro"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plegado"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"desplegado"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Batería restante: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecta tu lápiz óptico a un cargador"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Batería del lápiz óptico baja"</string> <string name="video_camera" msgid="7654002575156149298">"Videocámara"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Usado recientemente por <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"En uso por <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Usado recientemente por <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Sistema"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitarea"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Accesos directos a aplicaciones"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accesibilidad"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Combinaciones de teclas"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atajos de búsqueda"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icono de contraer"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icono de desplegar"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroiluminación del teclado"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivel %1$d de %2$d"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 29f0799a36ae..e7d5e2f42797 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Millist seadme kasutuskogemuse osa see mõjutas?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Valige probleemi tüüp"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekraanisalvestus"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Toimivus"</item> - <item msgid="1627504621139124393">"Kasutajaliides"</item> - <item msgid="8309220355268900335">"Aku"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Ühekäerežiim"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Kuuldeseadmed"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Kuuldeseadmed"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Uue seadme sidumine"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Uue seadme sidumiseks klõpsake"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Nupp <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Avakuva"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Tagasi"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Ülesnool"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Allanool"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Vasaknool"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Paremnool"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Keskele"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Tühik"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Sisestusklahv"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kokku volditud"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"lahti volditud"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Akutase on <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ühendage elektronpliiats laadijaga"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Elektronpliiatsi akutase on madal"</string> <string name="video_camera" msgid="7654002575156149298">"Videokaamera"</string> @@ -1327,6 +1328,8 @@ <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Otsingu otseteed"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ahendamisikoon"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Laiendamisikoon"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatuuri taustavalgustus"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Tase %1$d/%2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Kodu juhtelemendid"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 5d0d77814488..5e4c5acdfc12 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Gailuaren erabileraren zer alderdiri eragin dio?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Hautatu arazo mota"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Pantaila-grabaketa"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Errendimendua"</item> - <item msgid="1627504621139124393">"Erabiltzaile-interfazea"</item> - <item msgid="8309220355268900335">"Bateria"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Esku bakarreko modua"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Entzumen-gailuak"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Entzumen-gailuak"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parekatu beste gailu bat"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Egin klik beste gailu bat parekatzeko"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Ezin izan da eguneratu aurrezarpena"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Aurrezarpena"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Istanteko azpitituluak"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Gailuaren mikrofonoa desblokeatu nahi duzu?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Gailuaren kamera desblokeatu nahi duzu?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Gailuaren kamera eta mikrofonoa desblokeatu nahi dituzu?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> botoia"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Hasiera"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Atzera"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Gora egiteko gezi-tekla"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Behera egiteko gezi-tekla"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Ezkerrera egiteko gezi-tekla"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Eskuinera egiteko gezi-tekla"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Erdiratu"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Zuriunea"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Sartu"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"tolestuta"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"tolestu gabe"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Bateriaren <xliff:g id="PERCENTAGE">%s</xliff:g> geratzen da"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Konektatu arkatza kargagailu batera"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Arkatzak bateria gutxi du"</string> <string name="video_camera" msgid="7654002575156149298">"Bideokamera"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) aplikazioak erabili du duela gutxi"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak darabil (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) aplikazioak erabili du duela gutxi"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Sistema"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Zeregin bat baino gehiago aldi berean exekutatzea"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Sarrera"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Aplikazioetarako lasterbideak"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Erabilerraztasuna"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Lasterbideak"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Bilatu lasterbideak"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Tolesteko ikonoa"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Zabaltzeko ikonoa"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Teklatuaren hondoko argia"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d/%2$d maila"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index f856a7ea86ac..ad24c1b45a24 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -361,19 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"کدام بخش تجربه استفاده از دستگاه تحتتأثیر قرار گرفت؟"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"انتخاب نوع مشکل"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ضبط صفحهنمایش"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"عملکرد"</item> - <item msgid="1627504621139124393">"واسط کاربر"</item> - <item msgid="8309220355268900335">"باتری"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"حالت یکدستی"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"سمعک"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"سمعک"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"جفت کردن دستگاه جدید"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"برای جفت کردن دستگاه جدید، کلیک کنید"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"پیشتنظیم بهروزرسانی نشد"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"پیشتنظیم"</string> - <string name="live_caption_title" msgid="8916875614623730005">"زیرنویس ناشنوایان زنده"</string> + <string name="live_caption_title" msgid="8916875614623730005">"زیرنویس زنده"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"میکروفون دستگاه لغو انسداد شود؟"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"دوربین دستگاه لغو انسداد شود؟"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"دوربین و میکروفون دستگاه لغو انسداد شود؟"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"دکمه <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"ابتدا"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"برگشت"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"پیکان رو بهبالا"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"پیکان روبهپایین"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"پیکان چپ"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"پیکان راست"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"مرکز"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"تاشده"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"تانشده"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> باتری باقی مانده است"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"قلم را به شارژر وصل کنید"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"باتری قلم ضعیف است"</string> <string name="video_camera" msgid="7654002575156149298">"دوربین ویدیویی"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"اخیراً <xliff:g id="APP_NAME">%1$s</xliff:g> از آن استفاده کرده است (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> از آن استفاده میکند (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"اخیراً <xliff:g id="APP_NAME">%1$s</xliff:g> از آن استفاده کرده است (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"سیستم"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"چندوظیفگی"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ورودی"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"میانبرهای برنامه"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"دسترسپذیری"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"میانبرهای صفحهکلید"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"جستجوی میانبرها"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"نماد جمع کردن"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"نماد ازهم بازکردن"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"نور پسزمینه صفحهکلید"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"سطح %1$d از %2$d"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 459bec98d458..0fed3d546eae 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -201,7 +201,7 @@ <string name="fingerprint_reenroll_failure_dialog_content" msgid="4733768492747300666">"Sormenjälkiavauksen määritys epäonnistui. Siirry asetuksiin ja yritä uudelleen."</string> <string name="face_re_enroll_notification_title" msgid="1850838867718410520">"Ota kasvojentunnistusavaus uudelleen käyttöön"</string> <string name="face_re_enroll_notification_name" msgid="7384545252206120659">"Kasvojentunnistusavaus"</string> - <string name="face_re_enroll_dialog_title" msgid="6392173708176069994">"Kasvojentunnistusavauksen käyttöönotto"</string> + <string name="face_re_enroll_dialog_title" msgid="6392173708176069994">"Kasvojen&shy;tunnistus&shy;avauksen käyttöönotto"</string> <string name="face_re_enroll_dialog_content" msgid="7353502359464038511">"Jos haluat ottaa kasvojentunnistusavauksen uudelleen käyttöön, nykyinen kasvomalli poistetaan.\n\nJos haluat avata puhelimen lukituksen kasvoilla, sinun on otettava ominaisuus uudelleen käyttöön."</string> <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Kasvojentunnistusavauksen käyttöönotto epäonnistui. Siirry asetuksiin ja yritä uudelleen."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Kosketa sormenjälkitunnistinta"</string> @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Mitä osaa käyttökokemuksesta ongelma koski?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Valitse ongelman tyyppi"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Näytön tallentaja"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Suorituskyky"</item> - <item msgid="1627504621139124393">"Käyttöliittymä"</item> - <item msgid="8309220355268900335">"Akku"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Yhden käden moodi"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Kuulolaitteet"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Kuulolaitteet"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Muodosta uusi laitepari"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Muodosta uusi laitepari klikkaamalla"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Esiasetusta ei voitu muuttaa"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Esiasetus"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Livetekstitys"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Kumotaanko laitteen mikrofonin esto?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Kumotaanko laitteen kameran esto?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Kumotaanko laitteen kameran ja mikrofonin esto?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Painike <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Takaisin"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Ylänuoli"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Alanuoli"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Vasen nuoli"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Oikea nuoli"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Keskelle"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Välilyönti"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"taitettu"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"taittamaton"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Akkua jäljellä <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Yhdistä näyttökynä laturiin"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Näyttökynän akku vähissä"</string> <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"<xliff:g id="APP_NAME">%1$s</xliff:g> käytti tätä äskettäin (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Tämän käytössä: <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"<xliff:g id="APP_NAME">%1$s</xliff:g> käytti tätä äskettäin (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Järjestelmä"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitaskaus"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Syöte"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Sovellusten pikakuvakkeet"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Saavutettavuus"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Pikanäppäimet"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pikahaut"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Tiivistyskuvake"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Laajennuskuvake"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Näppämistön taustavalo"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Taso %1$d/%2$d"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 0eab07e850b1..95c788aab6e7 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Quelle composante de l\'appareil a été affectée?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Sélectionner un type"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Enregistrement écran"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Performance"</item> - <item msgid="1627504621139124393">"Interface utilisateur"</item> - <item msgid="8309220355268900335">"Pile"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode Une main"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Appareils auditifs"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Appareils auditifs"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Associer un nouvel appareil"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Cliquez ici pour associer un nouvel appareil"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Bouton <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Accueil"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Précédent"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Flèche vers le haut"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Flèche vers le bas"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Flèche vers la gauche"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Flèche vers la droite"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Centrer"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Espace"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Entrée"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plié"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"déplié"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Charge restante de la pile : <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connectez votre stylet à un chargeur"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Pile du stylet faible"</string> <string name="video_camera" msgid="7654002575156149298">"Caméra"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Récemment utilisé par <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Utilisé par <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Récemment utilisé par <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Système"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitâche"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrée"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Raccourcis des applis"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibilité"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Raccourcis-clavier"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Recherchez des raccourcis"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icône Réduire"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icône Développer"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Rétroéclairage du clavier"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d de %2$d"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index d3983b90e747..b7abd0ec5a5b 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Quel problème avez-vous rencontré avec votre appareil ?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Sélectionnez un type de problème"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Enregistrement de l\'écran"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Performances"</item> - <item msgid="1627504621139124393">"Interface utilisateur"</item> - <item msgid="8309220355268900335">"Batterie"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode une main"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Appareils auditifs"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Appareils auditifs"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Associer un nouvel appareil"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Cliquer pour associer un nouvel appareil"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Bouton <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Accueil"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Précédent"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Flèche vers le haut"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Flèche vers le bas"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Flèche vers la gauche"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Flèche vers la droite"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Centre"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Espace"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Entrée"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plié"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"déplié"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> de batterie restante"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connectez votre stylet à un chargeur"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"La batterie du stylet est faible"</string> <string name="video_camera" msgid="7654002575156149298">"Caméra"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Récemment utilisé par <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"En cours d\'utilisation par <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Récemment utilisé par <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Système"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitâche"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrée"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Raccourcis d\'application"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibilité"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Raccourcis clavier"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Raccourcis de recherche"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icône Réduire"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icône Développer"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Rétroéclairage du clavier"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d sur %2$d"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 6c494c17d4c9..55dd05a58bb3 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cal foi o problema na experiencia co dispositivo?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecciona o tipo de problema"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravación de pant."</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Rendemento"</item> - <item msgid="1627504621139124393">"Interface de usuario"</item> - <item msgid="8309220355268900335">"Batería"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo dunha soa man"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dispositivos auditivos"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dispositivos auditivos"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Vincular dispositivo novo"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Fai clic para vincular un novo dispositivo"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Non se puido actualizar a configuración predeterminada"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Configuración predeterminada"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Subtítulos instantáneos"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Queres desbloquear o micrófono do dispositivo?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Queres desbloquear a cámara do dispositivo?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Queres desbloquear a cámara e o micrófono do dispositivo?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Botón <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Inicio"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Volver"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Frecha arriba"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Frecha abaixo"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Frecha esquerda"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Frecha dereita"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Centro"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Espazo"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Intro"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"dispositivo pregado"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"dispositivo despregado"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Batería restante: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecta o lapis óptico a un cargador"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"O lapis óptico ten pouca batería"</string> <string name="video_camera" msgid="7654002575156149298">"Videocámara"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"En uso recentemente por <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"En uso por <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"En uso recentemente por <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Sistema"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitarefa"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Atallos de aplicacións"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accesibilidade"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Atallos de teclado"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atallos de busca"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icona de contraer"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icona de despregar"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroiluminación do teclado"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivel %1$d de %2$d"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index f2516c9df212..425a76869587 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ડિવાઇસ સંબંધી તમારા અનુભવના કયા ભાગને અસર થઈ હતી?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"સમસ્યાનો પ્રકાર પસંદ કરો"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"સ્ક્રીન રેકોર્ડ કરો"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"પર્ફોર્મન્સ"</item> - <item msgid="1627504621139124393">"યૂઝર ઇન્ટરફેસ"</item> - <item msgid="8309220355268900335">"બૅટરી"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"એક-હાથે વાપરો મોડ"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"સાંભળવામાં મદદ આપતા ડિવાઇસ"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"સાંભળવામાં મદદ આપતા ડિવાઇસ"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"નવા ડિવાઇસ સાથે જોડાણ કરો"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"નવા ડિવાઇસ સાથે જોડાણ કરવા માટે ક્લિક કરો"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"બટન <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Back"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"ઉપરની ઍરો કી"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"નીચેની ઍરો કી"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"ડાબી ઍરો કી"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"જમણી ઍરો કી"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Center"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ફોલ્ડ કરેલું"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"અનફોલ્ડ કરેલું"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> બૅટરી બાકી છે"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"તમારા સ્ટાઇલસને ચાર્જર સાથે કનેક્ટ કરો"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"સ્ટાઇલસની બૅટરીમાં ચાર્જ ઓછો છે"</string> <string name="video_camera" msgid="7654002575156149298">"વીડિયો કૅમેરા"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) દ્વારા તાજેતરમાં ઉપયોગ કરવામાં આવ્યો"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) દ્વારા ઉપયોગ ચાલુ છે"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) દ્વારા તાજેતરમાં ઉપયોગ કરવામાં આવ્યો"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"સિસ્ટમ"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"એકથી વધુ કાર્યો કરવા"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ઇનપુટ"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ઍપ શૉર્ટકટ"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ઍક્સેસિબિલિટી"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"કીબોર્ડ શૉર્ટકટ"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"શૉર્ટકટ શોધો"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"\'નાનું કરો\'નું આઇકન"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"\'મોટું કરો\'નું આઇકન"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"કીબોર્ડની બૅકલાઇટ"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dમાંથી %1$d લેવલ"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 0e6e77da8465..8f7b87cbc23e 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -295,7 +295,7 @@ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"स्क्रीन सेवर"</string> <string name="quick_settings_camera_label" msgid="5612076679385269339">"कैमरे का ऐक्सेस"</string> <string name="quick_settings_mic_label" msgid="8392773746295266375">"माइक्रोफ़ोन का ऐक्सेस"</string> - <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"उपलब्ध"</string> + <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"उपलब्ध है"</string> <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"ब्लॉक किया गया है"</string> <string name="quick_settings_media_device_label" msgid="8034019242363789941">"मीडिया डिवाइस"</string> <string name="quick_settings_user_title" msgid="8673045967216204537">"उपयोगकर्ता"</string> @@ -361,21 +361,26 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"आपके डिवाइस की कौनसी सुविधा पर असर पड़ा था?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"समस्या का टाइप चुनें"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"स्क्रीन रिकॉर्डर"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"परफ़ॉर्मेंस"</item> - <item msgid="1627504621139124393">"यूज़र इंटरफ़ेस"</item> - <item msgid="8309220355268900335">"बैटरी"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"वन-हैंडेड मोड"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"कान की मशीनें"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"कान की मशीनें"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"नया डिवाइस जोड़ें"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"नया डिवाइस जोड़ने के लिए क्लिक करें"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"प्रीसेट अपडेट नहीं किया जा सका"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"प्रीसेट"</string> - <string name="live_caption_title" msgid="8916875614623730005">"लाइव कैप्शन की सुविधा"</string> - <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"क्या आपको डिवाइस का माइक्रोफ़ोन अनब्लॉक करना है?"</string> - <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"क्या आपको डिवाइस का कैमरा अनब्लॉक करना है?"</string> + <string name="live_caption_title" msgid="8916875614623730005">"लाइव कैप्शन"</string> + <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"क्या आपको माइक्रोफ़ोन का ऐक्सेस अनब्लॉक करना है?"</string> + <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"क्या आपको कैमरे का ऐक्सेस अनब्लॉक करना है?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"क्या आप डिवाइस का कैमरा और माइक्रोफ़ोन अनब्लॉक करना चाहते हैं?"</string> <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"ऐसा करने से, सभी ऐप्लिकेशन और सेवाओं के लिए माइक्रोफ़ोन का ऐक्सेस अनब्लॉक हो जाएगा और वे इसका इस्तेमाल कर पाएंगी."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ऐसा करने से, सभी ऐप्लिकेशन और सेवाओं के लिए कैमरे का ऐक्सेस अनब्लॉक हो जाएगा और वे इसका इस्तेमाल कर पाएंगी."</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"बटन <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Back"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"अप ऐरो"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"डाउन ऐरो"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"लेफ़्ट ऐरो"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"राइट ऐरो"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"मध्य तीर"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -997,7 +997,7 @@ <string name="accessibility_magnification_right_handle" msgid="9055988237319397605">"दायां हैंडल"</string> <string name="accessibility_magnification_bottom_handle" msgid="6531646968813821258">"नीचे का हैंडल"</string> <string name="accessibility_magnification_settings_panel_description" msgid="8174187340747846953">"ज़ूम करने की सुविधा वाली सेटिंग"</string> - <string name="accessibility_magnifier_size" msgid="3038755600030422334">"ज़ूम करने की सुविधा का साइज़"</string> + <string name="accessibility_magnifier_size" msgid="3038755600030422334">"ज़ूम का साइज़"</string> <string name="accessibility_magnification_zoom" msgid="4222088982642063979">"ज़ूम करें"</string> <string name="accessibility_magnification_medium" msgid="6994632616884562625">"मध्यम"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"छोटा"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"डिवाइस फ़ोल्ड किया गया"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"डिवाइस अनफ़ोल्ड किया गया"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> बैटरी बची है"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"अपने स्टाइलस को चार्ज करें"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"स्टाइलस की बैटरी कम है"</string> <string name="video_camera" msgid="7654002575156149298">"वीडियो कैमरा"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"हाल ही में, <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) ने इस्तेमाल किया"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) पर इस्तेमाल किया जा रहा है"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"हाल ही में, <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ने इस्तेमाल किया"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"सिस्टम"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"मल्टीटास्किंग (एक साथ कई काम करना)"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"इनपुट"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ऐप शॉर्टकट"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"सुलभता"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"कीबोर्ड शॉर्टकट"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"सर्च शॉर्टकट"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"छोटा करने का आइकॉन"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"बड़ा करने का आइकॉन"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"कीबोर्ड की बैकलाइट"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d में से %1$d लेवल"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 2e6ae04617c2..bc84c1d0bc65 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Na koji dio doživljaja na uređaju to utjecalo?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Odaberite vrstu problema"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Snimanje zaslona"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Izvedba"</item> - <item msgid="1627504621139124393">"Korisničko sučelje"</item> - <item msgid="8309220355268900335">"Baterija"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Način rada jednom rukom"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušna pomagala"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušna pomagala"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Uparite novi uređaj"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite da biste uparili novi uređaj"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Ažuriranje unaprijed definiranih postavki nije uspjelo"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Unaprijed definirana postavka"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Automatski titlovi"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Želite li deblokirati mikrofon uređaja?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Želite li deblokirati kameru uređaja?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Želite li deblokirati kameru i mikrofon uređaja?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Tipka <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Početak"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Natrag"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Strelica prema gore"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Strelica prema dolje"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Strelica lijevo"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Strelica desno"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Sredina"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Razmaknica"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Unos"</string> @@ -933,7 +932,7 @@ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Način Ne uznemiravaj uključilo je automatsko pravilo ili aplikacija."</string> <string name="running_foreground_services_title" msgid="5137313173431186685">"Izvođenje aplikacija u pozadini"</string> <string name="running_foreground_services_msg" msgid="3009459259222695385">"Dodirnite da biste vidjeli pojedinosti o potrošnji baterije i podatkovnom prometu"</string> - <string name="mobile_data_disable_title" msgid="5366476131671617790">"Isključiti mobilne podatke?"</string> + <string name="mobile_data_disable_title" msgid="5366476131671617790">"Želite li isključiti mobilne podatke?"</string> <string name="mobile_data_disable_message" msgid="8604966027899770415">"Nećete imati pristup mobilnim podacima ili internetu putem operatera <xliff:g id="CARRIER">%s</xliff:g>. Internet će biti dostupan samo putem Wi-Fija."</string> <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"vaš mobilni operater"</string> <string name="auto_data_switch_disable_title" msgid="5146527155665190652">"Vratiti se na mobilnog operatera <xliff:g id="CARRIER">%s</xliff:g>?"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zatvoreno"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"otvoreno"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Preostalo je <xliff:g id="PERCENTAGE">%s</xliff:g> baterije"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Priključite pisaljku na punjač"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Slaba baterija pisaljke"</string> <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Nedavno koristila aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Koristi: <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Nedavno koristila aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Sustav"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Obavljanje više zadataka"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Unos"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Prečaci aplikacija"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Pristupačnost"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Tipkovni prečaci"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečaci za pretraživanje"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za sažimanje"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za proširivanje"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Pozadinsko osvjetljenje tipkovnice"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Razina %1$d od %2$d"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index d5649b7c4d78..4b36026b5f06 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Az eszközhasználati élmény mely része érintett?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Problématípus kiválasztása"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Képernyőrögzítés"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Teljesítmény"</item> - <item msgid="1627504621139124393">"Kezelőfelület"</item> - <item msgid="8309220355268900335">"Akkumulátor"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Egykezes mód"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hallókészülékek"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hallókészülékek"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Új eszköz párosítása"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kattintson új eszköz párosításához"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> gomb"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Kezdőképernyő"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Vissza"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Felfelé nyíl"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Lefelé nyíl"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Balra nyíl"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Jobbra nyíl"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Középre"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Szóköz"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"összehajtva"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kihajtva"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Akkumulátor töltöttségi szintje: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Tegye töltőre az érintőceruzát"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Az érintőceruza töltöttsége alacsony"</string> <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Legutóbb használta: <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Használatban a következő által: <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Legutóbb használta: <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Rendszer"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Bevitel"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Alkalmazás-parancsikonok"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Kisegítő lehetőségek"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Billentyűparancsok"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Billentyűparancsok keresése"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Összecsukás ikon"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Kibontás ikon"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"A billentyűzet háttérvilágítása"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Fényerő: %2$d/%1$d"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 3860921783e4..d8e36ad93c04 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Սարքի ո՞ր մասի հետ է կապված խնդիրը։"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Ընտրեք խնդրի տեսակը"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Էկրանի տեսագրում"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Աշխատանք"</item> - <item msgid="1627504621139124393">"Միջերես"</item> - <item msgid="8309220355268900335">"Մարտկոց"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Մեկ ձեռքի ռեժիմ"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Լսողական սարքեր"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Լսողական սարքեր"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Նոր սարքի զուգակցում"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Սեղմեք՝ նոր սարք զուգակցելու համար"</string> @@ -594,9 +599,9 @@ <string name="screen_pinning_negative" msgid="6882816864569211666">"Ոչ"</string> <string name="screen_pinning_start" msgid="7483998671383371313">"Հավելվածն ամրացվեց"</string> <string name="screen_pinning_exit" msgid="4553787518387346893">"Հավելվածն ապամրացվեց"</string> - <string name="stream_voice_call" msgid="7468348170702375660">"Զանգ"</string> + <string name="stream_voice_call" msgid="7468348170702375660">"Զանգելը"</string> <string name="stream_system" msgid="7663148785370565134">"Համակարգ"</string> - <string name="stream_ring" msgid="7550670036738697526">"Զանգ"</string> + <string name="stream_ring" msgid="7550670036738697526">"Զանգ ստանալը"</string> <string name="stream_music" msgid="2188224742361847580">"Մեդիա"</string> <string name="stream_alarm" msgid="16058075093011694">"Զարթուցիչ"</string> <string name="stream_notification" msgid="7930294049046243939">"Ծանուցում"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> կոճակ"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Գլխավոր էջ"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Հետ"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Վերև սլաք"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Ներքև սլաք"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Ձախ սլաք"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Աջ սլաք"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Կենտրոն"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Բացատ"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Մուտք"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ծալված"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"բացված"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Մարտկոցի լիցքը՝ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ձեր ստիլուսը միացրեք լիցքավորիչի"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Ստիլուսի մարտկոցի լիցքի ցածր մակարդակ"</string> <string name="video_camera" msgid="7654002575156149298">"Տեսախցիկ"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Վերջերս օգտագործվել է <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի կողմից (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Օգտագործվում է <xliff:g id="APP_NAME">%1$s</xliff:g>ի կողմից (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Վերջերս օգտագործվել է <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի կողմից (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Համակարգ"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Բազմախնդրություն"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Ներածում"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Հավելվածի դյուրանցումներ"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Հատուկ գործառույթներ"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Ստեղնային դյուրանցումներ"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Դյուրանցումների որոնում"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ծալել պատկերակը"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ծավալել պատկերակը"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Հետին լուսավորությամբ ստեղնաշար"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d՝ %2$d-ից"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index b0ca07e5ce74..22d0de5ecc0c 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Bagian pengalaman perangkat mana yang terpengaruh?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Pilih jenis masalah"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Perekaman layar"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Performa"</item> - <item msgid="1627504621139124393">"Antarmuka Pengguna"</item> - <item msgid="8309220355268900335">"Baterai"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode satu tangan"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Alat bantu dengar"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Alat bantu dengar"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Sambungkan perangkat baru"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik untuk menyambungkan perangkat baru"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Tidak dapat memperbarui preset"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preset"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Teks Otomatis"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Berhenti memblokir mikrofon perangkat?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Berhenti memblokir kamera perangkat?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Berhenti memblokir kamera dan mikrofon perangkat?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Tombol <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Back"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Panah atas"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Panah bawah"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Panah kiri"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Panah kanan"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Center"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ditutup"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"dibuka"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Baterai tersisa <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Hubungkan stilus ke pengisi daya"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Baterai stilus lemah"</string> <string name="video_camera" msgid="7654002575156149298">"Kamera video"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Baru saja digunakan oleh <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Sedang digunakan oleh <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Baru saja digunakan oleh <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Sistem"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Pintasan aplikasi"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Aksesibilitas"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Pintasan keyboard"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pintasan penelusuran"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikon ciutkan"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikon luaskan"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Lampu latar keyboard"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Tingkat %1$d dari %2$d"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 02bc343d0310..b631c47363d4 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Hvað í tækjaupplifuninni varð fyrir áhrifum?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Veldu gerð vandamáls"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skjáupptaka"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Afköst"</item> - <item msgid="1627504621139124393">"Notandaviðmót"</item> - <item msgid="8309220355268900335">"Rafhlaða"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Einhent stilling"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Heyrnartæki"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Heyrnartæki"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Para nýtt tæki"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Smelltu til að para nýtt tæki"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Tókst ekki að uppfæra forstillingu"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Forstilling"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Skjátextar í rauntíma"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Opna fyrir hljóðnema tækisins?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Opna fyrir myndavél tækisins?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Opna fyrir myndavél og hljóðnema tækisins?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Hnappur <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Til baka"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Ör upp"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Ör niður"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Ör til vinstri"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Ör til hægri"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Miðja"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Bilslá"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"samanbrotið"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"opið"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> hleðsla eftir á rafhlöðu"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Tengdu pennann við hleðslutæki"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Rafhlaða pennans er að tæmast"</string> <string name="video_camera" msgid="7654002575156149298">"Kvikmyndatökuvél"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Nýlega notað af <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Í notkun í <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Nýlega notað af <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Kerfi"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Fjölvinnsla"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Inntak"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Flýtileiðir forrita"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Aðgengi"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Flýtilyklar"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Leitarflýtileiðir"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Minnka tákn"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Stækka tákn"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Baklýsing lyklaborðs"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Stig %1$d af %2$d"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index eb90d583d58b..5494b165bda3 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -361,13 +361,15 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Quali problemi ha l\'esperienza del dispositivo?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Seleziona il tipo di problema"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Regis. dello schermo"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Prestazioni"</item> - <item msgid="1627504621139124393">"Interfaccia utente"</item> - <item msgid="8309220355268900335">"Batteria"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"Prestazioni"</string> + <string name="user_interface" msgid="3712869377953950887">"Interfaccia utente"</string> + <string name="thermal" msgid="6758074791325414831">"Termico"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modalità a una mano"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Apparecchi acustici"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Protesi uditive"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Accoppia nuovo dispositivo"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Fai clic per accoppiare un nuovo dispositivo"</string> @@ -580,11 +582,11 @@ <string name="csd_button_keep_listening" product="default" msgid="4093794049149286784">"Continua ad ascoltare"</string> <string name="csd_button_lower_volume" product="default" msgid="5347210412376264579">"Abbassa il volume"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"L\'app è bloccata sullo schermo"</string> - <string name="screen_pinning_description" msgid="8699395373875667743">"La schermata rimane visibile finché non viene sganciata. Per sganciarla, tieni premuto Indietro e Panoramica."</string> - <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"La schermata rimane visibile finché non viene disattivato il blocco su schermo. Per disattivarlo, tocca e tieni premuto Indietro e Home."</string> + <string name="screen_pinning_description" msgid="8699395373875667743">"La schermata rimane visibile finché non viene sbloccata. Per sbloccarla, tieni premuto Indietro e Panoramica."</string> + <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"La schermata rimane visibile finché non viene sbloccata. Per sbloccarla, tocca e tieni premuto Indietro e Home."</string> <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Rimarrà visibile finché non viene sbloccata. Scorri verso l\'alto e tieni premuto per sbloccarla."</string> - <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"La schermata rimane visibile finché non viene sganciata. Per sganciarla, tieni premuto Panoramica."</string> - <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"La schermata rimane visibile finché non viene disattivato il blocco su schermo. Per disattivarlo, tocca e tieni premuto Home."</string> + <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"La schermata rimane visibile finché non viene sbloccata. Per sbloccarla, tieni premuto Panoramica."</string> + <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"La schermata rimane visibile finché non viene sbloccata. Per sbloccarla, tocca e tieni premuto Home."</string> <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"I dati personali potrebbero essere accessibili (ad esempio i contatti e i contenuti delle email)."</string> <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"L\'app bloccata sullo schermo potrebbe aprire altre app."</string> <string name="screen_pinning_toast" msgid="8177286912533744328">"Per sbloccare questa app, tocca e tieni premuti i pulsanti Indietro e Panoramica"</string> @@ -727,11 +729,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Pulsante <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home page"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Indietro"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Freccia su"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Freccia giù"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Freccia sinistra"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Freccia destra"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Al centro"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Spazio"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Invio"</string> @@ -1275,7 +1272,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"Piegato"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"Non piegato"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> batteria rimanente"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Batteria dello stilo: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connetti lo stilo a un caricabatterie"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Batteria stilo in esaurimento"</string> <string name="video_camera" msgid="7654002575156149298">"Videocamera"</string> @@ -1318,23 +1315,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Recentemente in uso da <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"In uso da <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Recentemente in uso da <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Sistema"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Scorciatoie app"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibilità"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Scorciatoie da tastiera"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Scorciatoie per la ricerca"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icona Comprimi"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icona Espandi"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroilluminazione della tastiera"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Livello %1$d di %2$d"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 5fc6cdede29e..2ad95fb93e82 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -361,13 +361,15 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"איזה חלק בחוויית השימוש שלך במכשיר הושפע?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"בחירה בסוג הבעיה"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"הקלטת המסך"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"ביצועים"</item> - <item msgid="1627504621139124393">"ממשק משתמש"</item> - <item msgid="8309220355268900335">"סוללה"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"ביצועים"</string> + <string name="user_interface" msgid="3712869377953950887">"ממשק משתמש"</string> + <string name="thermal" msgid="6758074791325414831">"תרמי"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"מצב שימוש ביד אחת"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"מכשירי שמיעה"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"מכשירי שמיעה"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"התאמה של מכשיר חדש"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"צריך ללחוץ כדי להתאים מכשיר חדש"</string> @@ -727,11 +729,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"לחצן <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"דף הבית"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"הקודם"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"חץ למעלה"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"חץ למטה"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"חץ שמאלה"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"חץ ימינה"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"מרכז"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"רווח"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1272,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"מצב מקופל"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"מצב לא מקופל"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"רמת הטעינה שנותרה בסוללה: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"רמת הטעינה בסוללה של הסטיילוס: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"כדאי לחבר את הסטיילוס למטען"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"הסוללה של הסטיילוס חלשה"</string> <string name="video_camera" msgid="7654002575156149298">"מצלמת וידאו"</string> @@ -1318,23 +1315,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"נעשה שימוש לאחרונה על ידי <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"בשימוש על ידי <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"נעשה שימוש לאחרונה על ידי <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"מערכת"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ריבוי משימות"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"קלט"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"קיצורי דרך של אפליקציות"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"נגישות"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"מקשי קיצור"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"קיצורי דרך לחיפוש"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"סמל הכיווץ"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"סמל ההרחבה"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"התאורה האחורית במקלדת"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"רמה %1$d מתוך %2$d"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 81fa09496e17..15c1f8b4ca77 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -361,13 +361,15 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"デバイスのどの部分が影響を受けましたか?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"問題の種類を選択する"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"スクリーン レコード"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"パフォーマンス"</item> - <item msgid="1627504621139124393">"ユーザー インターフェース"</item> - <item msgid="8309220355268900335">"バッテリー"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"パフォーマンス"</string> + <string name="user_interface" msgid="3712869377953950887">"ユーザー インターフェース"</string> + <string name="thermal" msgid="6758074791325414831">"温度"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"片手モード"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"補聴器"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"補聴器"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"新しいデバイスとペア設定"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"クリックすると、新しいデバイスをペア設定できます"</string> @@ -727,11 +729,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> ボタン"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"戻る"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"上矢印"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"下矢印"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"左矢印"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"右矢印"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"中央"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1272,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"折りたたんだ状態"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"広げた状態"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"バッテリー残量 <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"タッチペンのバッテリー残量 <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"タッチペンを充電器に接続してください"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"タッチペンのバッテリー残量が少なくなっています"</string> <string name="video_camera" msgid="7654002575156149298">"ビデオカメラ"</string> @@ -1327,6 +1324,8 @@ <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"検索ショートカット"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"閉じるアイコン"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"開くアイコン"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"キーボード バックライト"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"レベル %1$d/%2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"ホーム コントロール"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index d367f4fb9815..4d17179f9ead 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -361,20 +361,21 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"თქვენი მოწყობილობის გამოცდილების რა ნაწილზე მოხდა ზეგავლენა?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"აირჩიეთ პრობლემის ტიპი"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ეკრანის ჩანაწერი"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"ეფექტურობა"</item> - <item msgid="1627504621139124393">"სამომხმარებლო ინტერფეისი"</item> - <item msgid="8309220355268900335">"ბატარეა"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"ეფექტურობა"</string> + <string name="user_interface" msgid="3712869377953950887">"სამომხმარებლო ინტერფეისი"</string> + <string name="thermal" msgid="6758074791325414831">"თერმული"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ცალი ხელის რეჟიმი"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"სმენის აპარატები"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"სმენის აპარატები"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ახალი მოწყობილობის დაწყვილება"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"დააწკაპუნეთ ახალი მოწყობილობის დასაწყვილებლად"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"წინასწარ დაყენებული პარამეტრების განახლება ვერ მოხერხდა"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"წინასწარ დაყენებული"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"პირდაპირი სუბტიტრები"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"გსურთ მოწყობილობის მიკროფონის განბლოკვა?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"გსურთ მოწყობილობის კამერის განბლოკვა?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"გსურთ მოწყობილობის კამერის და მიკროფონის განბლოკვა?"</string> @@ -728,11 +729,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"ღილაკი „<xliff:g id="NAME">%1$s</xliff:g>“"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"უკან"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"ზემოთ მიმართული ისარი"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"ქვემოთ მიმართული ისარი"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"მარცხნივ მიმართული ისარი"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"მარჯვნივ მიმართული ისარი"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"ცენტრში"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"შორისი"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1276,7 +1272,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"დაკეცილი"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"გაშლილი"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"დარჩენილია ბატარეის <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"სტილუსის ბატარეა <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"დააკავშირეთ თქვენი სტილუსი დამტენს"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"სტილუსის ბატარეა დაცლის პირასაა"</string> <string name="video_camera" msgid="7654002575156149298">"ვიდეოკამერა"</string> @@ -1328,6 +1324,8 @@ <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ძიების მალსახმობები"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ხატულის ჩაკეცვა"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ხატულის გაფართოება"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"კლავიატურის შენათება"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"დონე: %1$d %2$d-დან"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"სახლის კონტროლი"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index fd7160fa418f..08e9fa203463 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Құрылғы қызметінің қандай түріне әсер етті?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Мәселе түрін таңдаңыз."</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Экранды жазу"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Өнімділік"</item> - <item msgid="1627504621139124393">"Пайдаланушы интерфейсі"</item> - <item msgid="8309220355268900335">"Батарея"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Бір қолмен басқару режимі"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Есту құрылғылары"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Есту құрылғылары"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Жаңа құрылғыны жұптау"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Жаңа құрылғыны жұптау үшін басыңыз."</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Параметрлер жинағын жаңарту мүмкін болмады."</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Параметрлер жинағы"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Live Caption"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Құрылғы микрофонын блоктан шығару керек пе?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Құрылғы камерасын блоктан шығару керек пе?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Құрылғы камерасы мен микрофонын блоктан шығару керек пе?"</string> @@ -597,7 +601,7 @@ <string name="screen_pinning_exit" msgid="4553787518387346893">"Қолданба босатылды."</string> <string name="stream_voice_call" msgid="7468348170702375660">"Қоңырау шалу"</string> <string name="stream_system" msgid="7663148785370565134">"Жүйе"</string> - <string name="stream_ring" msgid="7550670036738697526">"Шылдырлау"</string> + <string name="stream_ring" msgid="7550670036738697526">"Шылдыр"</string> <string name="stream_music" msgid="2188224742361847580">"Мультимедиа"</string> <string name="stream_alarm" msgid="16058075093011694">"Дабыл"</string> <string name="stream_notification" msgid="7930294049046243939">"Хабарландыру"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> түймесі"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Артқа"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Жоғары бағыт пернесі"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Төмен бағыт пернесі"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Сол бағыт пернесі"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Оң бағыт пернесі"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Орталық"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Бос орын"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"жабық"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ашық"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Қалған батарея заряды: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Стилусты зарядтағышқа жалғаңыз."</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Стилус батареясының заряды аз"</string> <string name="video_camera" msgid="7654002575156149298">"Бейнекамера"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Соңғы рет <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) қолданбасы пайдаланды."</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) қолданбасы пайдаланып жатыр"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Соңғы рет <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) қолданбасы пайдаланды."</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Жүйе"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Мультитаскинг"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Кіріс"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Қолданба таңбашалары"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Арнайы мүмкіндіктер"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Перне тіркесімдері"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Іздеу жылдам пәрмендері"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Жию белгішесі"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Жаю белгішесі"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Пернетақта жарығы"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Деңгей: %1$d/%2$d"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 9adcfb5d40ff..d6538bdf9bfe 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"តើផ្នែកអ្វីនៃបទពិសោធប្រើប្រាស់ឧបករណ៍របស់អ្នកបានរងការប៉ះពាល់?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ជ្រើសរើសប្រភេទបញ្ហា"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ការថតវីដេអូអេក្រង់"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"ប្រតិបត្តិការ"</item> - <item msgid="1627504621139124393">"ផ្ទៃប៉ះ"</item> - <item msgid="8309220355268900335">"ថ្ម"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"មុខងារប្រើដៃម្ខាង"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ឧបករណ៍ជំនួយការស្ដាប់"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ឧបករណ៍ជំនួយការស្ដាប់"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ផ្គូផ្គងឧបករណ៍ថ្មី"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ចុច ដើម្បីផ្គូផ្គងឧបករណ៍ថ្មី"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"ប៊ូតុង <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Back"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"ព្រួញឡើងលើ"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"ព្រួញចុះក្រោម"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"ព្រួញទៅឆ្វេង"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"ព្រួញទៅស្ដាំ"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Center"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"បត់"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"លា"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"ថ្មនៅសល់ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ភ្ជាប់ប៊ិករបស់អ្នកជាមួយឆ្នាំងសាក"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"ថ្មប៊ិកនៅសល់តិច"</string> <string name="video_camera" msgid="7654002575156149298">"កាមេរ៉ាវីដេអូ"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"បានប្រើនាពេលថ្មីៗនេះដោយ <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"កំពុងប្រើដោយ <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"បានប្រើនាពេលថ្មីៗនេះដោយ <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"ប្រព័ន្ធ"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ការដំណើរការបានច្រើន"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ធាតុចូល"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ផ្លូវកាត់កម្មវិធី"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ភាពងាយស្រួល"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"ផ្លូវកាត់ក្ដារចុច"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ផ្លូវកាត់ការស្វែងរក"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"រូបតំណាង \"បង្រួម\""</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"រូបតំណាង \"ពង្រីក\""</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ពន្លឺក្រោយក្ដារចុច"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"កម្រិតទី %1$d នៃ %2$d"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index ecc0fdf72204..92a8b6be128b 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -361,19 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ಸಾಧನ ಬಳಸುವಾಗ ನೀವು ಯಾವ ರೀತಿಯ ಸಮಸ್ಯೆ ಎದುರಿಸುತ್ತೀರಿ?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ಸಮಸ್ಯೆಯ ಪ್ರಕಾರವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡ್"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"ಕಾರ್ಯಕ್ಷಮತೆ"</item> - <item msgid="1627504621139124393">"ಬಳಕೆದಾರರ ಇಂಟರ್ಫೇಸ್"</item> - <item msgid="8309220355268900335">"ಬ್ಯಾಟರಿ"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ಒಂದು ಕೈ ಮೋಡ್"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ಶ್ರವಣ ಸಾಧನಗಳು"</string> - <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ಹಿಯರಿಂಗ್ ಸಾಧನಗಳು"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> + <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ಶ್ರವಣ ಸಾಧನಗಳು"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ಹೊಸ ಸಾಧನವನ್ನು ಪೇರ್ ಮಾಡಿ"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ಹೊಸ ಸಾಧನವನ್ನು ಜೋಡಿಸಲು ಕ್ಲಿಕ್ ಮಾಡಿ"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"ಪ್ರಿಸೆಟ್ ಅನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"ಪ್ರಿಸೆಟ್"</string> - <string name="live_caption_title" msgid="8916875614623730005">"ಲೈವ್ ಕ್ಯಾಪ್ಶನ್"</string> + <string name="live_caption_title" msgid="8916875614623730005">"ಲೈವ್ ಶೀರ್ಷಿಕೆ"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ಸಾಧನದ ಮೈಕ್ರೋಫೋನ್ ನಿರ್ಬಂಧವನ್ನು ತೆಗೆಯಬೇಕೆ?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ಸಾಧನದ ಕ್ಯಾಮರಾ ನಿರ್ಬಂಧವನ್ನು ತೆಗೆಯಬೇಕೆ?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ಸಾಧನದ ಕ್ಯಾಮರಾ ಮತ್ತು ಮೈಕ್ರೋಫೋನ್ ಅನ್ನು ಅನ್ಬ್ಲಾಕ್ ಮಾಡಬೇಕೇ?"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> ಬಟನ್"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"ಹಿಂದೆ"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"ಅಪ್ ಆ್ಯರೋ"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"ಡೌನ್ ಆ್ಯರೋ"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"ಲೆಫ್ಟ್ ಆ್ಯರೋ"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"ರೈಟ್ ಆ್ಯರೋ"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"ಮಧ್ಯ"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"ಸ್ಪೇಸ್"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ಫೋಲ್ಡ್ ಮಾಡಿರುವುದು"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ಅನ್ಫೋಲ್ಡ್ ಮಾಡಿರುವುದು"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ಬ್ಯಾಟರಿ ಉಳಿದಿದೆ"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ನಿಮ್ಮ ಸ್ಟೈಲಸ್ ಅನ್ನು ಚಾರ್ಜರ್ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಿ"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"ಸ್ಟೈಲಸ್ ಬ್ಯಾಟರಿ ಕಡಿಮೆಯಿದೆ"</string> <string name="video_camera" msgid="7654002575156149298">"ವೀಡಿಯೊ ಕ್ಯಾಮರಾ"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"ಇತ್ತೀಚೆಗೆ <xliff:g id="APP_NAME">%1$s</xliff:g> ಇದನ್ನು ಬಳಸಿದೆ (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> ನಿಂದ ಬಳಕೆಯಲ್ಲಿದೆ (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"ಇತ್ತೀಚೆಗೆ <xliff:g id="APP_NAME">%1$s</xliff:g> ಇದನ್ನು ಬಳಸಿದೆ (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"ಸಿಸ್ಟಂ"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ಮಲ್ಟಿಟಾಸ್ಕಿಂಗ್"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ಇನ್ಪುಟ್"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ಆ್ಯಪ್ ಶಾರ್ಟ್ಕಟ್ಗಳು"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್ಕಟ್ಗಳು"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ಹುಡುಕಾಟದ ಶಾರ್ಟ್ಕಟ್ಗಳು"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ಕುಗ್ಗಿಸುವ ಐಕಾನ್"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ವಿಸ್ತೃತಗೊಳಿಸುವ ಐಕಾನ್"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ಕೀಬೋರ್ಡ್ ಬ್ಯಾಕ್ಲೈಟ್"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d ರಲ್ಲಿ %1$d ಮಟ್ಟ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 889026e90eef..b141b48de023 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"기기 경험의 어떤 부분에 영향이 있었나요?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"문제 유형 선택"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"화면 녹화"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"성능"</item> - <item msgid="1627504621139124393">"사용자 인터페이스"</item> - <item msgid="8309220355268900335">"배터리"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"한 손 사용 모드"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"청각 보조 기기"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"청각 보조 기기"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"새 기기와 페어링"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"새 기기와 페어링하려면 클릭하세요"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> 버튼"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"뒤로"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"위쪽 화살표"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"아래쪽 화살표"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"왼쪽 화살표"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"오른쪽 화살표"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"중앙"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"접은 상태"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"펼친 상태"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"배터리 <xliff:g id="PERCENTAGE">%s</xliff:g> 남음"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"스타일러스를 충전기에 연결하세요"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"스타일러스 배터리 부족"</string> <string name="video_camera" msgid="7654002575156149298">"비디오 카메라"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"최근 <xliff:g id="APP_NAME">%1$s</xliff:g>에서 사용됨(<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 사용 중(<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"최근 <xliff:g id="APP_NAME">%1$s</xliff:g>에서 사용됨(<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"시스템"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"멀티태스킹"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"입력"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"앱 바로가기"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"접근성"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"단축키"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"검색 바로가기"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"접기 아이콘"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"확장 아이콘"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"키보드 백라이트"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d단계 중 %1$d단계"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 0ec15587dfd0..dc7227ee4779 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Түзмөгүңүздүн кайсы бөлүгүнө кедергиси тийди?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Маселенин түрүн тандоо"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Экрандан видео жаздырып алуу"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Иштин майнаптуулугу"</item> - <item msgid="1627504621139124393">"Колдонуучунун интерфейси"</item> - <item msgid="8309220355268900335">"Батарея"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Бир кол режими"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Угуу аппараттары"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Угуу аппараттары"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Жаңы түзмөк кошуу"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Жаңы түзмөк кошуу үчүн басыңыз"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Алдын ала коюлган параметрлер жаңыртылган жок"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Алдын ала коюлган параметрлер"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Ыкчам коштомо жазуулар"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Түзмөктүн микрофонун бөгөттөн чыгарасызбы?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Түзмөктүн камерасын бөгөттөн чыгарасызбы?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Түзмөктүн камерасы менен микрофону бөгөттөн чыгарылсынбы?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> баскычы"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Башкы бет"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Артка"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Өйдө жебе"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Ылдый жебе"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Солго жебе"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Оңго жебе"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Ортолотуу"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Боштук"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"бүктөлгөн"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ачылган"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Батареянын кубаты: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Стилусту кубаттаңыз"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Стилустун батареясы отурайын деп калды"</string> <string name="video_camera" msgid="7654002575156149298">"Видео камера"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Акыркы жолу <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) колдонмосунда иштетилди"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда иштеп жатат (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Акыркы жолу <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) колдонмосунда иштетилди"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Система"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Бир нече тапшырма аткаруу"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Киргизүү"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Колдонмодогу кыска жолдор"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Атайын мүмкүнчүлүктөр"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Ыкчам баскычтар"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Ыкчам баскычтарды издөө"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Жыйыштыруу сүрөтчөсү"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Жайып көрсөтүү сүрөтчөсү"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Баскычтоптун жарыгы"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d ичинен %1$d-деңгээл"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 6ba0b093044c..58940842729b 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ສ່ວນໃດຂອງປະສົບການອຸປະກອນຂອງທ່ານໄດ້ຮັບຜົນກະທົບ?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ເລືອກປະເພດບັນຫາ"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ບັນທຶກໜ້າຈໍ"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"ປະສິດທິພາບ"</item> - <item msgid="1627504621139124393">"ສ່ວນຕິດຕໍ່ຜູ້ໃຊ້"</item> - <item msgid="8309220355268900335">"ແບັດເຕີຣີ"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ໂໝດມືດຽວ"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ອຸປະກອນຊ່ວຍຟັງ"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ອຸປະກອນຊ່ວຍຟັງ"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ຈັບຄູ່ອຸປະກອນໃໝ່"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ຄລິກເພື່ອຈັບຄູ່ອຸປະກອນໃໝ່"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"ບໍ່ສາມາດອັບເດດການຕັ້ງຄ່າລ່ວງໜ້າໄດ້"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"ຄ່າທີ່ກຳນົດລ່ວງໜ້າ"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"ຄຳບັນຍາຍສົດ"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ປົດບລັອກໄມໂຄຣໂຟນອຸປະກອນບໍ?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ປົດບລັອກກ້ອງຖ່າຍຮູບອຸປະກອນບໍ?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ຍົກເລີກການບລັອກກ້ອງຖ່າຍຮູບ ຫຼື ໄມໂຄຣໂຟນອຸປະກອນບໍ?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"ປຸ່ມ <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"ກັບຄືນ"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"ລູກສອນຂຶ້ນ"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"ລູກສອນລົງ"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"ລູກສອນຊ້າຍ"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"ລູກສອນຂວາ"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"ເຄິ່ງກາງ"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ພັບແລ້ວ"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ກາງອອກແລ້ວ"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"ແບັດເຕີຣີເຫຼືອ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ເຊື່ອມຕໍ່ປາກກາຂອງທ່ານກັບສາຍສາກ"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"ແບັດເຕີຣີປາກກາເຫຼືອໜ້ອຍ"</string> <string name="video_camera" msgid="7654002575156149298">"ກ້ອງວິດີໂອ"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"ໃຊ້ຫຼ້າສຸດໂດຍ <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"ໃຊ້ຢູ່ໂດຍ <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"ໃຊ້ຫຼ້າສຸດໂດຍ <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"ລະບົບ"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ການເຮັດຫຼາຍໜ້າວຽກພ້ອມກັນ"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ອິນພຸດ"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ທາງລັດແອັບ"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ການຊ່ວຍເຂົ້າເຖິງ"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"ຄີລັດ"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ທາງລັດການຊອກຫາ"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ໄອຄອນຫຍໍ້ລົງ"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ໄອຄອນຂະຫຍາຍ"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ໄຟປຸ່ມແປ້ນພິມ"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"ລະດັບທີ %1$d ຈາກ %2$d"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 40418f0ca7ca..2c9eed8e6d53 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Kuri įrenginio funkcija buvo paveikta?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Pasirinkite problemos tipą"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekrano įrašas"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Našumas"</item> - <item msgid="1627504621139124393">"Naudotojo sąsaja"</item> - <item msgid="8309220355268900335">"Akumuliatorius"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Vienos rankos režimas"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Klausos įrenginiai"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Klausos įrenginiai"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Susieti naują įrenginį"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Spustelėkite, kad susietumėte naują įrenginį"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Išankstinių nustatymų atnaujinti nepavyko"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Išankstiniai nustatymai"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Subtitrai realiuoju laiku"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Panaikinti įrenginio mikrofono blokavimą?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Panaikinti įrenginio fotoaparato blokavimą?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Panaikinti įrenginio fotoaparato ir mikrofono blokavimą?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Mygtukas <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Pagrindinis"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Atgal"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Rodyklė aukštyn"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Rodyklė žemyn"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Rodyklė kairėn"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Rodyklė dešinėn"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Centras"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Tarpas"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Įvesti"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"sulenkta"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"nesulenkta"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Liko akumuliatoriaus įkrovos: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Prijunkite rašiklį prie kroviklio"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Senka rašiklio akumuliatorius"</string> <string name="video_camera" msgid="7654002575156149298">"Vaizdo kamera"</string> @@ -1328,6 +1328,8 @@ <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Paieškos šaukiniai"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Sutraukimo piktograma"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Išskleidimo piktograma"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatūros foninis apšvietimas"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d lygis iš %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Namų sistemos valdymas"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 53c54082515f..6a5d0681d7df 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Kuras ierīces funkcijas tika ietekmētas?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Atlasiet problēmas veidu"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekrāna ierakstīšana"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Veiktspēja"</item> - <item msgid="1627504621139124393">"Lietotāja saskarne"</item> - <item msgid="8309220355268900335">"Akumulators"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Vienas rokas režīms"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dzirdes aparāti"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dzirdes aparāti"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Savienot pārī jaunu ierīci"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Noklikšķiniet, lai savienotu pārī jaunu ierīci"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Nevarēja atjaunināt pirmsiestatījumu"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Pirmsiestatījums"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Subtitri reāllaikā"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vai atbloķēt ierīces mikrofonu?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vai vēlaties atbloķēt ierīces kameru?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vai atbloķēt ierīces kameru un mikrofonu?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Poga <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Sākumvietas taustiņš"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Atpakaļ"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Augšupvērstā bultiņa"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Lejupvērstā bultiņa"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Kreisā bultiņa"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Labā bultiņa"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Centrā"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Atstarpe"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Ievadīšanas taustiņš"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"aizvērta"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"atvērta"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Atlikušais uzlādes līmenis: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Pievienojiet skārienekrāna pildspalvu lādētājam"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Zems skārienekrāna pildspalvas akumulatora līmenis"</string> <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Nesen to izmantoja lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"To izmanto lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Nesen to izmantoja lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Sistēma"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Vairākuzdevumu režīms"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Ievade"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Lietotņu saīsnes"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Pieejamība"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Īsinājumtaustiņi"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Meklēšanas saīsnes"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Sakļaušanas ikona"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Izvēršanas ikona"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Tastatūras fona apgaismojums"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Līmenis numur %1$d, kopā ir %2$d"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 8eb0537030d7..7c410965bfa2 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Кој дел од доживувањето на уредот беше засегнат?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Изберете тип проблем"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Снимање екран"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Изведба"</item> - <item msgid="1627504621139124393">"Кориснички интерфејс"</item> - <item msgid="8309220355268900335">"Батерија"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим со една рака"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слушни апарати"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слушни апарати"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Спари нов уред"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Кликнете за да спарите нов уред"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Не можеше да се ажурира зададената вредност"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Зададени вредности"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Автоматски титлови"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Да се одблокира пристапот до микрофонот на уредот?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Да се одблокира пристапот до камерата на уредот?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Да се одблокира пристапот до камерата и микрофонот на уредот?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Копче <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home-копче"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Назад"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Стрелка нагоре"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Стрелка надолу"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Стрелка налево"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Стрелка надесно"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Центар"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -989,7 +988,7 @@ <string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Затворете ги поставките за зголемување"</string> <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"Излегување од „Режим на изменување“"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Повлечете на аголот за да ја промените големината"</string> - <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Дозволете дијагонално лизгање"</string> + <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Дозволи дијагонално лизгање"</string> <string name="accessibility_resize" msgid="5733759136600611551">"Промени големина"</string> <string name="accessibility_change_magnification_type" msgid="666000085077432421">"Променете го типот на зголемување"</string> <string name="accessibility_magnification_end_resizing" msgid="4881690585800302628">"Заврши ја промената на големина"</string> @@ -998,7 +997,7 @@ <string name="accessibility_magnification_right_handle" msgid="9055988237319397605">"Десна рачка"</string> <string name="accessibility_magnification_bottom_handle" msgid="6531646968813821258">"Долна рачка"</string> <string name="accessibility_magnification_settings_panel_description" msgid="8174187340747846953">"Поставки за зголемување"</string> - <string name="accessibility_magnifier_size" msgid="3038755600030422334">"Големина на лупа"</string> + <string name="accessibility_magnifier_size" msgid="3038755600030422334">"Големина на лупата"</string> <string name="accessibility_magnification_zoom" msgid="4222088982642063979">"Зум"</string> <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Средно"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Мало"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"затворен"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"отворен"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Преостаната батерија: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Поврзете го пенкалото со полнач"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Слаба батерија на пенкало"</string> <string name="video_camera" msgid="7654002575156149298">"Видеокамера"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Неодамна користено од <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Се користи од <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Неодамна користено од <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Систем"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Мултитаскинг"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Внесување"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Кратенки за апликации"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Пристапност"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Кратенки од тастатура"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Кратенки за пребарување"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за собирање"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за проширување"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Осветлување на тастатура"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Ниво %1$d од %2$d"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 291ee6a7733e..540358c359d7 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"നിങ്ങളുടെ ഉപകരണ അനുഭവത്തിന്റെ ഏത് ഭാഗമാണ് ബാധിച്ചത്?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"പ്രശ്ന തരം തിരഞ്ഞെടുക്കുക"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"സ്ക്രീൻ റെക്കോർഡ്"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"പ്രകടനം"</item> - <item msgid="1627504621139124393">"ഉപയോക്തൃ ഇന്റര്ഫേസ്"</item> - <item msgid="8309220355268900335">"ബാറ്ററി"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ഒറ്റക്കൈ മോഡ്"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"കേൾവിക്കുള്ള ഉപകരണങ്ങൾ"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"കേൾവിക്കുള്ള ഉപകരണങ്ങൾ"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"പുതിയ ഉപകരണം ജോടിയാക്കുക"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"പുതിയ ഉപകരണം ജോടിയാക്കാൻ ക്ലിക്ക് ചെയ്യുക"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"പ്രീസെറ്റ് അപ്ഡേറ്റ് ചെയ്യാനായില്ല"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"പ്രീസെറ്റ്"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"തത്സമയ ക്യാപ്ഷനുകൾ"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ഉപകരണ മൈക്രോഫോൺ അൺബ്ലോക്ക് ചെയ്യണോ?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ഉപകരണ ക്യാമറ അൺബ്ലോക്ക് ചെയ്യണോ?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ഉപകരണ ക്യാമറയോ മൈക്രോഫോണോ അൺബ്ലോക്ക് ചെയ്യണോ?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"ബട്ടൺ <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"ഹോം"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"ബാക്ക്"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"മുകളിലേക്കുള്ള അമ്പടയാളം"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"താഴേക്കുള്ള അമ്പടയാളം"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"ഇടത് അമ്പടയാളം"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"വലത് അമ്പടയാളം"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"മധ്യം"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"TAB"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"സ്പെയ്സ്"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"എന്റർ"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ഫോൾഡ് ചെയ്തത്"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"അൺഫോൾഡ് ചെയ്തത്"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ബാറ്ററി ചാർജ് ശേഷിക്കുന്നു"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"നിങ്ങളുടെ സ്റ്റൈലസ് ചാർജറുമായി കണക്റ്റ് ചെയ്യുക"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"സ്റ്റൈലസിന്റെ ബാറ്ററി ചാർജ് കുറവാണ്"</string> <string name="video_camera" msgid="7654002575156149298">"വീഡിയോ ക്യാമറ"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) അടുത്തിടെ ഉപയോഗിച്ചു"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ഉപയോഗിക്കുന്നു"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) അടുത്തിടെ ഉപയോഗിച്ചു"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"സിസ്റ്റം"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"മൾട്ടിടാസ്കിംഗ്"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ഇൻപുട്ട്"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ആപ്പ് കുറുക്കുവഴികൾ"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ഉപയോഗസഹായി"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"കീബോഡ് കുറുക്കുവഴികൾ"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"തിരയൽ കുറുക്കുവഴികൾ"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ചുരുക്കൽ ഐക്കൺ"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"വികസിപ്പിക്കൽ ഐക്കൺ"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"കീബോഡ് ബാക്ക്ലൈറ്റ്"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d-ൽ %1$d-ാമത്തെ ലെവൽ"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index da8db8db14a4..47e6936ea5f1 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Таны төхөөрөмжийн хэрэглээний аль хэсэгт нөлөөлсөн бэ?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Асуудлын төрөл сонгоно уу"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Дэлгэцийн бичлэг"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Гүйцэтгэл"</item> - <item msgid="1627504621139124393">"Хэрэглэгчийн интерфейс"</item> - <item msgid="8309220355268900335">"Батарей"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Нэг гарын горим"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Сонсголын төхөөрөмжүүд"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Сонсголын төхөөрөмжүүд"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Шинэ төхөөрөмж хослуулах"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Шинэ төхөөрөмж хослуулахын тулд товшино уу"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Урьдчилсан тохируулгыг шинэчилж чадсангүй"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Урьдчилсан тохируулга"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Шууд тайлбар"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Төхөөрөмжийн микрофоныг блокоос гаргах уу?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Төхөөрөмжийн камерыг блокоос гаргах уу?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Төхөөрөмжийн камер болон микрофоныг блокоос гаргах уу?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> товчлуур"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Нүүр хуудас"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Буцах"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Дээш сум"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Доош сум"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Зүүн сум"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Баруун сум"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Гол хэсэг"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Зай"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Оруулах"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"эвхсэн"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"дэлгэсэн"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> батарей үлдлээ"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Мэдрэгч үзгээ цэнэглэгчтэй холбоорой"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Мэдрэгч үзэгний батарей бага байна"</string> <string name="video_camera" msgid="7654002575156149298">"Видео камер"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Саяхан <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) ашигласан"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ашиглаж байна"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Саяхан <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ашигласан"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Систем"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Олон ажил зэрэг хийх"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Оролт"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Аппын товчлол"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Хандалт"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Товчлуурын шууд холбоос"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Товчлолууд хайх"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Хураах дүрс тэмдэг"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Дэлгэх дүрс тэмдэг"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Гарын арын гэрэл"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d-с %1$d-р түвшин"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 7dd9308cc1b0..39f14133eb2b 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -361,13 +361,15 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"तुमच्या डिव्हाइसबाबत कोणत्या अनुभवावर परिणाम झाला?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"समस्येचा प्रकार निवडा"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"स्क्रीन रेकॉर्ड"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"परफॉर्मन्स"</item> - <item msgid="1627504621139124393">"यूझर इंटरफेस"</item> - <item msgid="8309220355268900335">"बॅटरी"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"परफॉर्मन्स"</string> + <string name="user_interface" msgid="3712869377953950887">"यूझर इंटरफेस"</string> + <string name="thermal" msgid="6758074791325414831">"थर्मल"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"एकहाती मोड"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"श्रवणयंत्रे"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"श्रवणयंत्रे"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"नवीन डिव्हाइस पेअर करा"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"नवीन डिव्हाइस पेअर करण्यासाठी क्लिक करा"</string> @@ -727,11 +729,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"बटण <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"परत"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"अप अॅरो"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"डाउन अॅरो"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"लेफ्ट अॅरो"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"राइट अॅरो"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"मध्यवर्ती"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1272,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"फोल्ड केलेले"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"फोल्ड न केलेले"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> बॅटरी शिल्लक आहे"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"स्टायलस बॅटरी <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"तुमचे स्टायलस चार्जरशी कनेक्ट करा"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"स्टायलस बॅटरी कमी आहे"</string> <string name="video_camera" msgid="7654002575156149298">"व्हिडिओ कॅमेरा"</string> @@ -1327,6 +1324,8 @@ <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"शोधण्यासाठी शॉर्टकट"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"कोलॅप्स करा आयकन"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"विस्तार करा आयकन"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"कीबोर्ड बॅकलाइट"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d पैकी %1$d पातळी"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"होम कंट्रोल"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index abd9d01980e6..8fce993b6d74 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Pengalaman peranti yang manakah yang terjejas?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Pilih jenis masalah"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Rakam skrin"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Prestasi"</item> - <item msgid="1627504621139124393">"Antara Muka Pengguna"</item> - <item msgid="8309220355268900335">"Bateri"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mod sebelah tangan"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Peranti pendengaran"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Peranti pendengaran"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Gandingkan peranti baharu"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik untuk menggandingkan peranti baharu"</string> @@ -377,8 +382,8 @@ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Nyahsekat mikrofon peranti?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Nyahsekat kamera peranti?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Nyahsekat kamera dan mikrofon peranti?"</string> - <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Tindakan ini menyahsekat akses bagi semua apl dan perkhidmatan yang dibenarkan untuk menggunakan mikrofon anda."</string> - <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Tindakan ini menyahsekat akses bagi semua apl dan perkhidmatan yang dibenarkan untuk menggunakan kamera anda."</string> + <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Tindakan ini menyahsekat akses bagi semua apl dan perkhidmatan yang dibenarkan untuk menggunakan mikrofon."</string> + <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Tindakan ini menyahsekat akses bagi semua apl dan perkhidmatan yang dibenarkan untuk menggunakan kamera."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Tindakan ini menyahsekat akses bagi semua apl dan perkhidmatan yang dibenarkan untuk menggunakan kamera atau mikrofon anda."</string> <string name="sensor_privacy_start_use_mic_blocked_dialog_title" msgid="2640140287496469689">"Mikrofon disekat"</string> <string name="sensor_privacy_start_use_camera_blocked_dialog_title" msgid="7398084286822440384">"Kamera disekat"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Butang <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Skrin Utama"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Kembali"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Anak panah ke atas"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Anak panah ke bawah"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Anak panah ke kiri"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Anak panah ke kanan"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Tengah"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -933,7 +933,7 @@ <string name="running_foreground_services_title" msgid="5137313173431186685">"Apl yang berjalan di latar belakang"</string> <string name="running_foreground_services_msg" msgid="3009459259222695385">"Ketik untuk mendapatkan butiran tentang penggunaan kuasa bateri dan data"</string> <string name="mobile_data_disable_title" msgid="5366476131671617790">"Matikan data mudah alih?"</string> - <string name="mobile_data_disable_message" msgid="8604966027899770415">"Anda tidak akan mempunyai akses kepada data atau Internet melalui <xliff:g id="CARRIER">%s</xliff:g>. Internet hanya tersedia melaui Wi-Fi."</string> + <string name="mobile_data_disable_message" msgid="8604966027899770415">"Anda tidak akan dapat mengakses data atau Internet melalui <xliff:g id="CARRIER">%s</xliff:g>. Internet hanya akan tersedia melalui Wi-Fi."</string> <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"pembawa anda"</string> <string name="auto_data_switch_disable_title" msgid="5146527155665190652">"Tukar kembali kepada <xliff:g id="CARRIER">%s</xliff:g>?"</string> <string name="auto_data_switch_disable_message" msgid="5885533647399535852">"Data mudah alih tidak akan ditukar secara automatik berdasarkan ketersediaan"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"terlipat"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"tidak terlipat"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Bateri tinggal <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Sambungkan stilus anda kepada pengecas"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Bateri stilus lemah"</string> <string name="video_camera" msgid="7654002575156149298">"Kamera video"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Digunakan baru-baru ini oleh <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Digunakan oleh <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Digunakan baru-baru ini oleh <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Sistem"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Berbilang tugas"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Pintasan apl"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Kebolehaksesan"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Pintasan papan kekunci"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pintasan carian"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Kuncupkan ikon"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Kembangkan ikon"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Cahaya latar papan kekunci"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Tahap %1$d daripada %2$d"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index a376ecfeb4e6..926426120720 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"စက်အသုံးပြုမှု၏ မည်သည့်အပိုင်းကို သက်ရောက်သလဲ။"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ပြဿနာအမျိုးအစား ရွေးရန်"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ဖန်သားပြင်ရိုက်ကူးရန်"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"စွမ်းဆောင်ရည်"</item> - <item msgid="1627504621139124393">"သုံးသူအတွက် ကြားခံစနစ်"</item> - <item msgid="8309220355268900335">"ဘက်ထရီ"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"လက်တစ်ဖက်သုံးမုဒ်"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"နားကြားကိရိယာ"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"နားကြားကိရိယာ"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"စက်အသစ်တွဲချိတ်ရန်"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"စက်အသစ် တွဲချိတ်ရန် နှိပ်ပါ"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"ခလုတ် <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"ပင်မ"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"နောက်သို့"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"အပေါ်ညွှန်မြား"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"အောက်ညွှန်မြား"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"ဘယ်ညွှန်မြား"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"ညာညွှန်မြား"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"ဌာန"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter ခလုတ်"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ခေါက်ထားသည်"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ဖြန့်ထားသည်"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"ဘက်ထရီ <xliff:g id="PERCENTAGE">%s</xliff:g> ကျန်သေးသည်"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"စတိုင်လပ်စ်ကို အားသွင်းကိရိယာနှင့် ချိတ်ဆက်ခြင်း"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"စတိုင်လပ်စ် ဘက်ထရီ အားနည်းနေသည်"</string> <string name="video_camera" msgid="7654002575156149298">"ဗီဒီယိုကင်မရာ"</string> @@ -1327,6 +1328,8 @@ <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ရှာဖွေစာလုံး ဖြတ်လမ်း"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"လျှော့ပြရန် သင်္ကေတ"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ပိုပြရန် သင်္ကေတ"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ကီးဘုတ်နောက်မီး"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"အဆင့် %2$d အနက် %1$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"အိမ်ထိန်းချုပ်မှုများ"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 23dc7fd02131..9c2193ef1a13 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Hvilken del av enhetsopplevelsen din ble påvirket?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Velg problemtype"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skjermopptak"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Ytelse"</item> - <item msgid="1627504621139124393">"Brukergrensesnitt"</item> - <item msgid="8309220355268900335">"Batteri"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enhåndsmodus"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Høreapparater"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Høreapparater"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Koble til en ny enhet"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klikk for å koble til en ny enhet"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g>-knappen"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Startskjerm"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Tilbake"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Oppoverpil"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Nedoverpil"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Venstrepil"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Høyrepil"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Midttasten"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Mellomrom"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"lagt sammen"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"åpen"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> batteri gjenstår"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Koble pekepennen til en lader"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Det er lite batteri i pekepennen"</string> <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Nylig brukt av <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"I bruk av <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Nylig brukt av <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"System"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Inndata"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"App-snarveier"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Tilgjengelighet"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Hurtigtaster"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Snarveier til søk"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Skjul-ikon"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Vis-ikon"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Bakgrunnslys for tastatur"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivå %1$d av %2$d"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index f442427a5ebb..94b197b3f238 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"तपाईंको डिभाइसको कुन चाहिँ सुविधा प्रभावित भएको छ?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"समस्याको प्रकार चयन गर्नुहोस्"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"स्क्रिन रेकर्ड"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"पर्फर्मेन्स"</item> - <item msgid="1627504621139124393">"युजर इन्टरफेस"</item> - <item msgid="8309220355268900335">"ब्याट्री"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"एक हाते मोड"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"हियरिङ डिभाइसहरू"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"हियरिङ डिभाइसहरू"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"नयाँ डिभाइस कनेक्ट गर्नुहोस्"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"नयाँ डिभाइसमा कनेक्ट गर्न क्लिक गर्नुहोस्"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"प्रिसेट अपडेट गर्न सकिएन"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"पूर्वनिर्धारित"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"लाइभ क्याप्सन"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"डिभाइसको माइक्रोफोन अनब्लक गर्ने हो?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"डिभाइसको क्यामेरा अनब्लक गर्ने हो?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"डिभाइसको क्यामेरा र माइक्रोफोन अनब्लक गर्ने हो?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> बटन"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"पछाडि"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"अप एरो"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"डाउन एरो"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"लेफ्ट एरो"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"राइट एरो"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"केन्द्र"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"स्पेस"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"फोल्ड गरिएको"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"अनफोल्ड गरिएको"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ब्याट्री बाँकी छ"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"आफ्नो स्टाइलस चार्जरमा कनेक्ट गर्नुहोस्"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"स्टाइलसको ब्याट्री लो छ"</string> <string name="video_camera" msgid="7654002575156149298">"भिडियो क्यामेरा"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) ले हालसालै प्रयोग गरेको"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ले प्रयोग गरिरहेको छ"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ले हालसालै प्रयोग गरेको"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"सिस्टम"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"एकै पटक एकभन्दा बढी एप चलाउन मिल्ने सुविधा"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"इनपुट"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"एपका सर्टकटहरू"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"सर्वसुलभता"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"किबोर्डका सर्टकटहरू"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"खोजका सर्टकटहरू"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"\"कोल्याप्स गर्नुहोस्\" आइकन"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"\"एक्स्पान्ड गर्नुहोस्\" आइकन"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"किबोर्ड ब्याकलाइट"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d मध्ये %1$d औँ स्तर"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index a68e8a25cc50..8cdbf6139a7d 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -361,13 +361,15 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Op welk onderdeel van de apparaatfunctionaliteit had dit effect?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Probleemtype selecteren"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Schermopname"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Prestaties"</item> - <item msgid="1627504621139124393">"Gebruikersinterface"</item> - <item msgid="8309220355268900335">"Batterij"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"Prestaties"</string> + <string name="user_interface" msgid="3712869377953950887">"Gebruikersinterface"</string> + <string name="thermal" msgid="6758074791325414831">"Thermisch"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Bediening met 1 hand"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hoortoestellen"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hoortoestellen"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Nieuw apparaat koppelen"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik om nieuw apparaat te koppelen"</string> @@ -727,11 +729,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Knop <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Terug"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Pijl-omhoog"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Pijl-omlaag"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Pijl-links"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Pijl-rechts"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Midden"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Spatiebalk"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1272,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"dichtgevouwen"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"opengevouwen"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Nog <xliff:g id="PERCENTAGE">%s</xliff:g> batterijlading"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Stylusbatterij <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Verbind je stylus met een oplader"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Batterij van stylus bijna leeg"</string> <string name="video_camera" msgid="7654002575156149298">"Videocamera"</string> @@ -1318,23 +1315,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Recent gebruikt door <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Gebruikt door <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Recent gebruikt door <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Systeem"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Invoer"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"App-snelkoppelingen"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Toegankelijkheid"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Sneltoetsen"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Snelkoppelingen voor zoekopdrachten"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icoon voor samenvouwen"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icoon voor uitvouwen"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Achtergrondverlichting van toetsenbord"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d van %2$d"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index 4bdd980b5ff3..287d1a71dd04 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ଆପଣଙ୍କ ଡିଭାଇସ ଅନୁଭୂତିର କେଉଁ ଅଂଶ ପ୍ରଭାବିତ ହୋଇଛି?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ସମସ୍ୟାର ପ୍ରକାର ଚୟନ କରନ୍ତୁ"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ସ୍କ୍ରିନ ରେକର୍ଡ"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"ପରଫରମାନ୍ସ"</item> - <item msgid="1627504621139124393">"ୟୁଜର ଇଣ୍ଟରଫେସ"</item> - <item msgid="8309220355268900335">"ବେଟେରୀ"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ଏକ-ହାତ ମୋଡ"</string> - <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ହିଅରିଂ ଡିଭାଇସଗୁଡ଼ିକ"</string> - <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ହିଅରିଂ ଡିଭାଇସଗୁଡ଼ିକ"</string> + <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ଶ୍ରବଣ ଡିଭାଇସଗୁଡ଼ିକ"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> + <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ଶ୍ରବଣ ଡିଭାଇସଗୁଡ଼ିକ"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ନୂଆ ଡିଭାଇସ ପେୟାର କରନ୍ତୁ"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ନୂଆ ଡିଭାଇସ ପେୟାର କରିବାକୁ କ୍ଲିକ କରନ୍ତୁ"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"ପ୍ରିସେଟକୁ ଅପଡେଟ କରାଯାଇପାରିଲା ନାହିଁ"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"ପ୍ରିସେଟ"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"ଲାଇଭ କେପ୍ସନ"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ଡିଭାଇସର ମାଇକ୍ରୋଫୋନକୁ ଅନବ୍ଲକ କରିବେ?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ଡିଭାଇସର କେମେରାକୁ ଅନବ୍ଲକ କରିବେ?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ଡିଭାଇସର କ୍ୟାମେରା ଏବଂ ମାଇକ୍ରୋଫୋନକୁ ଅନବ୍ଲକ୍ କରିବେ?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"ବଟନ୍ <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"ହୋମ"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"ଫେରନ୍ତୁ"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"ଅପ ତୀର କୀ"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"ଡାଉନ ଆରୋ"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"ବାମ ତୀର କୀ"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"ଡାହାଣ ତୀର କୀ"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"କେନ୍ଦ୍ର"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"ସ୍ପେସ୍"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"ଏଣ୍ଟର୍"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ଫୋଲ୍ଡେଡ"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ଅନଫୋଲ୍ଡେଡ"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ବେଟେରୀ ଚାର୍ଜ ବାକି ଅଛି"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ଏକ ଚାର୍ଜର ସହ ଆପଣଙ୍କ ଷ୍ଟାଇଲସକୁ କନେକ୍ଟ କରନ୍ତୁ"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"ଷ୍ଟାଇଲସ ବେଟେରୀର ଚାର୍ଜ କମ ଅଛି"</string> <string name="video_camera" msgid="7654002575156149298">"ଭିଡିଓ କେମେରା"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"ଏବେ <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) ଦ୍ୱାରା ବ୍ୟବହାର କରାଯାଉଛି"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> ଦ୍ୱାରା ବ୍ୟବହାର କରାଯାଉଛି (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"ଏବେ <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ଦ୍ୱାରା ବ୍ୟବହାର କରାଯାଉଛି"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"ସିଷ୍ଟମ"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ମଲ୍ଟିଟାସ୍କିଂ"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ଇନପୁଟ"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ଆପ ସର୍ଟକଟ"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ଆକ୍ସେସିବିଲିଟୀ"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"କୀବୋର୍ଡ ସର୍ଟକଟ"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ସର୍ଚ୍ଚ ସର୍ଟକଟ"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ଆଇକନକୁ ସଙ୍କୁଚିତ କରନ୍ତୁ"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ଆଇକନକୁ ବିସ୍ତାର କରନ୍ତୁ"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"କୀବୋର୍ଡ ବେକଲାଇଟ"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dରୁ %1$d ନମ୍ବର ଲେଭେଲ"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 2558fca53ffe..a16a8a5cbc8c 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀ ਕਿਹੜੀ ਸੁਵਿਧਾ ਪ੍ਰਭਾਵਿਤ ਹੋਈ ਸੀ?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ਸਮੱਸਿਆ ਦੀ ਕਿਸਮ ਚੁਣੋ"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡ"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"ਕਾਰਗੁਜ਼ਾਰੀ"</item> - <item msgid="1627504621139124393">"ਯੂਜ਼ਰ ਇੰਟਰਫ਼ੇਸ"</item> - <item msgid="8309220355268900335">"ਬੈਟਰੀ"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ਇੱਕ ਹੱਥ ਮੋਡ"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ਸੁਣਨ ਵਾਲੇ ਡੀਵਾਈਸ"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ਸੁਣਨ ਵਾਲੇ ਡੀਵਾਈਸ"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"\'ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ\' \'ਤੇ ਕਲਿੱਕ ਕਰੋ"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"ਬਟਨ <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Back"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"ਉੱਪਰ ਤੀਰ"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"ਹੇਠਾਂ ਤੀਰ"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"ਖੱਬਾ ਤੀਰ"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"ਸੱਜਾ ਤੀਰ"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Center"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ਫੋਲਡਯੋਗ ਡੀਵਾਈਸ"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ਅਣਫੋਲਡਯੋਗ ਡੀਵਾਈਸ"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ਬੈਟਰੀ ਬਾਕੀ"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ਆਪਣੇ ਸਟਾਈਲਸ ਨੂੰ ਚਾਰਜਰ ਨਾਲ ਕਨੈਕਟ ਕਰੋ"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"ਸਟਾਈਲਸ ਦੀ ਬੈਟਰੀ ਘੱਟ ਹੈ"</string> <string name="video_camera" msgid="7654002575156149298">"ਵੀਡੀਓ ਕੈਮਰਾ"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"ਹਾਲ ਹੀ ਵਿੱਚ <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) ਵੱਲੋਂ ਵਰਤਿਆ ਗਿਆ"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ਵੱਲੋਂ ਵਰਤੋਂ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"ਹਾਲ ਹੀ ਵਿੱਚ <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ਵੱਲੋਂ ਵਰਤਿਆ ਗਿਆ"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"ਸਿਸਟਮ"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ਮਲਟੀਟਾਸਕਿੰਗ"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ਇਨਪੁੱਟ"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ਐਪ ਸ਼ਾਰਟਕੱਟ"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ਪਹੁੰਚਯੋਗਤਾ"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ਖੋਜ ਸੰਬੰਧੀ ਸ਼ਾਰਟਕੱਟ"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ਪ੍ਰਤੀਕ ਨੂੰ ਸਮੇਟੋ"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ਪ੍ਰਤੀਕ ਦਾ ਵਿਸਤਾਰ ਕਰੋ"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ਕੀ-ਬੋਰਡ ਬੈਕਲਾਈਟ"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d ਵਿੱਚੋਂ %1$d ਪੱਧਰ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 747d922b8609..58561f112456 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -361,13 +361,15 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Którego aspektu korzystania z urządzenia dotyczył problem?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Wybierz typ problemu"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Nagrywanie ekranu"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Wydajność"</item> - <item msgid="1627504621139124393">"Interfejs"</item> - <item msgid="8309220355268900335">"Bateria"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"Wydajność"</string> + <string name="user_interface" msgid="3712869377953950887">"Interfejs"</string> + <string name="thermal" msgid="6758074791325414831">"Termografia"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Tryb jednej ręki"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Urządzenia słuchowe"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Urządzenia słuchowe"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Sparuj nowe urządzenie"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknij, aby sparować nowe urządzenie"</string> @@ -727,11 +729,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Przycisk <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Wstecz"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Strzałka w górę"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Strzałka w dół"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Strzałka w lewo"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Strzałka w prawo"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Do środka"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Spacja"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1272,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"po zamknięciu"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"po otwarciu"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Pozostało <xliff:g id="PERCENTAGE">%s</xliff:g> baterii"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Bateria rysika: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Podłącz rysik do ładowarki"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Słaba bateria w rysiku"</string> <string name="video_camera" msgid="7654002575156149298">"Kamera"</string> @@ -1318,23 +1315,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Ostatnio używany przez aplikację <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Używany przez aplikację <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Ostatnio używany przez aplikację <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"System"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Wielozadaniowość"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Wprowadzanie"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Skróty do aplikacji"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Ułatwienia dostępu"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Skróty klawiszowe"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Skróty do wyszukiwania"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona zwijania"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozwijania"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podświetlenie klawiatury"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Poziom %1$d z %2$d"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index a3bfad737ec1..8f5c5192133c 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Que parte da sua experiência no dispositivo foi afetada?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecionar tipo de problema"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravação de tela"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Desempenho"</item> - <item msgid="1627504621139124393">"Interface do usuário"</item> - <item msgid="8309220355268900335">"Bateria"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo uma mão"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Aparelhos auditivos"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Aparelhos auditivos"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parear novo dispositivo"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Clique para parear o novo dispositivo"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Voltar"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Seta para cima"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Seta para baixo"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Seta para a esquerda"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Seta para a direita"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Centralizar"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"fechado"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aberto"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Bateria restante: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecte sua stylus a um carregador"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Bateria da stylus fraca"</string> <string name="video_camera" msgid="7654002575156149298">"Filmadora"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Usado recentemente pelo app <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Em uso pelo app <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Usado recentemente pelo app <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Sistema"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitarefas"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Atalhos de apps"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Acessibilidade"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Atalhos do teclado"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atalhos de pesquisa"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone \"Fechar\""</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone \"Abrir\""</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Luz de fundo do teclado"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nível %1$d de %2$d"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index d76aa8de938f..df735727b893 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -361,13 +361,15 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Que parte da experiência do disposit. foi afetada?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecione o tipo de problema"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravação de ecrã"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Desempenho"</item> - <item msgid="1627504621139124393">"Interface do utilizador"</item> - <item msgid="8309220355268900335">"Bateria"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"Desempenho"</string> + <string name="user_interface" msgid="3712869377953950887">"Interface do utilizador"</string> + <string name="thermal" msgid="6758074791325414831">"Térmico"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo para uma mão"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dispositivos auditivos"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dispositivos auditivos"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Sincronizar novo dispositivo"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Clique para sincronizar um novo dispositivo"</string> @@ -727,11 +729,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Início"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Anterior"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Seta para cima"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Seta para baixo"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Seta para a esquerda"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Seta para a direita"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Ao centro"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Espaço"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -988,7 +985,7 @@ <string name="magnification_close_settings_click_label" msgid="4642477260651704517">"Fechar definições de ampliação"</string> <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"Sair do modo de edição"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Arrastar o canto para redimensionar"</string> - <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Permitir deslocamento da página na diagonal"</string> + <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Permitir deslocamento diagonal"</string> <string name="accessibility_resize" msgid="5733759136600611551">"Redimensionar"</string> <string name="accessibility_change_magnification_type" msgid="666000085077432421">"Alterar tipo de ampliação"</string> <string name="accessibility_magnification_end_resizing" msgid="4881690585800302628">"Terminar redimensionamento"</string> @@ -1275,7 +1272,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"fechado"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aberto"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> de bateria restante"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Bateria da caneta stylus a <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ligue a caneta stylus a um carregador"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Bateria da caneta stylus fraca"</string> <string name="video_camera" msgid="7654002575156149298">"Câmara de vídeo"</string> @@ -1327,6 +1324,8 @@ <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atalhos de pesquisa"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone de reduzir"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone de expandir"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Luz do teclado"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nível %1$d de %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Controlos domésticos"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index a3bfad737ec1..8f5c5192133c 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Que parte da sua experiência no dispositivo foi afetada?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecionar tipo de problema"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravação de tela"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Desempenho"</item> - <item msgid="1627504621139124393">"Interface do usuário"</item> - <item msgid="8309220355268900335">"Bateria"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo uma mão"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Aparelhos auditivos"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Aparelhos auditivos"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parear novo dispositivo"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Clique para parear o novo dispositivo"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Voltar"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Seta para cima"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Seta para baixo"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Seta para a esquerda"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Seta para a direita"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Centralizar"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"fechado"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aberto"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Bateria restante: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecte sua stylus a um carregador"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Bateria da stylus fraca"</string> <string name="video_camera" msgid="7654002575156149298">"Filmadora"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Usado recentemente pelo app <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Em uso pelo app <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Usado recentemente pelo app <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Sistema"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitarefas"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Atalhos de apps"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Acessibilidade"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Atalhos do teclado"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atalhos de pesquisa"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone \"Fechar\""</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone \"Abrir\""</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Luz de fundo do teclado"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nível %1$d de %2$d"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index c24ab85e0608..366480ed96db 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Ce parte a experienței pe dispozitiv a fost afectată?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selectează tipul problemei"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Înregistrarea ecranului"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Performanță"</item> - <item msgid="1627504621139124393">"Interfața de utilizare"</item> - <item msgid="8309220355268900335">"Baterie"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modul cu o mână"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Aparate auditive"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Aparate auditive"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Asociază un nou dispozitiv"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Dă clic pentru a asocia un nou dispozitiv"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Nu s-a putut actualiza presetarea"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Presetare"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Subtitrări live"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblochezi microfonul dispozitivului?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Deblochezi camera dispozitivului?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Deblochezi camera și microfonul dispozitivului?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Butonul <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"La început"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Înapoi"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Săgeată în sus"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Săgeată în jos"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Săgeată spre stânga"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Săgeată spre dreapta"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"În centru"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Spațiu"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"închis"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"deschis"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> baterie rămasă"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conectează-ți creionul la un încărcător"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Nivelul bateriei creionului este scăzut"</string> <string name="video_camera" msgid="7654002575156149298">"Cameră video"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Folosit recent de <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Se folosește pentru <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Folosit recent de <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Sistem"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Intrare"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Comenzi rapide pentru aplicații"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accesibilitate"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Comenzi rapide de la tastatură"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Comenzi directe de căutare"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Pictograma de restrângere"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Pictograma de extindere"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Iluminarea din spate a tastaturii"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivelul %1$d din %2$d"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 2313a93bd61b..f48e42823f0d 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -361,25 +361,29 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"С чем связана проблема, с которой вы столкнулись?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Выберите тип проблемы"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запись экрана"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Производительность"</item> - <item msgid="1627504621139124393">"Интерфейс"</item> - <item msgid="8309220355268900335">"Батарея"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим управления одной рукой"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слуховые аппараты"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слуховые аппараты"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Подключить новое устройство"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Нажмите, чтобы подключить новое устройство"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Не удалось обновить набор настроек."</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Набор настроек"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Автоматические субтитры"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Разблокировать микрофон устройства?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Разблокировать камеру устройства?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Разблокировать камеру и микрофон устройства?"</string> - <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Будет снята блокировка доступа для всех приложений и сервисов с разрешением на использование микрофона."</string> - <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Будет снята блокировка доступа для всех приложений и сервисов с разрешением на использование камеры."</string> + <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Все приложения и сервисы, у которых есть разрешение на использование микрофона, получат к нему доступ."</string> + <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Все приложения и сервисы, у которых есть разрешение на использование камеры, получат к ней доступ."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Будет снята блокировка доступа для всех приложений и сервисов с разрешением на использование камеры или микрофона."</string> <string name="sensor_privacy_start_use_mic_blocked_dialog_title" msgid="2640140287496469689">"Микрофон заблокирован"</string> <string name="sensor_privacy_start_use_camera_blocked_dialog_title" msgid="7398084286822440384">"Камера заблокирована"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Кнопка <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Главный экран"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Назад"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Стрелка вверх"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Стрелка вниз"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Стрелка влево"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Стрелка вправо"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Центральная стрелка"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Пробел"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Ввод"</string> @@ -933,8 +932,8 @@ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Режим \"Не беспокоить\" был включен специальным правилом или приложением."</string> <string name="running_foreground_services_title" msgid="5137313173431186685">"Приложения, работающие в фоновом режиме"</string> <string name="running_foreground_services_msg" msgid="3009459259222695385">"Нажмите, чтобы проверить энергопотребление и трафик"</string> - <string name="mobile_data_disable_title" msgid="5366476131671617790">"Отключить мобильный Интернет?"</string> - <string name="mobile_data_disable_message" msgid="8604966027899770415">"Вы не сможете передавать данные или выходить в Интернет через оператора \"<xliff:g id="CARRIER">%s</xliff:g>\". Интернет будет доступен только по сети Wi-Fi."</string> + <string name="mobile_data_disable_title" msgid="5366476131671617790">"Отключить мобильный интернет?"</string> + <string name="mobile_data_disable_message" msgid="8604966027899770415">"Вы не сможете передавать данные или выходить в интернет через оператора \"<xliff:g id="CARRIER">%s</xliff:g>\". Интернет будет доступен только по сети Wi-Fi."</string> <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"ваш оператор"</string> <string name="auto_data_switch_disable_title" msgid="5146527155665190652">"Переключиться на сеть \"<xliff:g id="CARRIER">%s</xliff:g>\"?"</string> <string name="auto_data_switch_disable_message" msgid="5885533647399535852">"Мобильный интернет не будет переключаться автоматически."</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"устройство сложено"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"устройство разложено"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Уровень заряда батареи: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Поставьте стилус на зарядку."</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Низкий заряд батареи стилуса"</string> <string name="video_camera" msgid="7654002575156149298">"Видеокамера"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Недавно использовалось приложением \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Сейчас используется приложением \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Недавно использовалось приложением \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Система"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Многозадачность"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Ввод"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Ярлыки приложений"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Специальные возможности"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Быстрые клавиши"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Найти быстрые клавиши"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок \"Свернуть\""</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок \"Развернуть\""</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Подсветка клавиатуры"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Уровень %1$d из %2$d"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 91a68430288b..0e621c6eae5f 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ඔබේ උපාංග අත්දැකීමේ කුමන කොටසට බලපෑවේ ද?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ගැටලු වර්ගය තෝරන්න"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"තිර පටිගත කිරීම"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"කාර්ය සාධනය"</item> - <item msgid="1627504621139124393">"පරිශීලක අතුරු මුහුණත"</item> - <item msgid="8309220355268900335">"බැටරිය"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"තනි අත් ප්රකාරය"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ශ්රවණ උපාංග"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ශ්රවණ උපාංග"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"නව උපාංගය යුගල කරන්න"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"නව උපාංගය යුගල කිරීමට ක්ලික් කරන්න"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"පෙර සැකසීම යාවත්කාලීන කළ නොහැකි විය"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"පෙරසැකසුම"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"සජීවී සිරස්තලය"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"උපාංග මයික්රෆෝනය අවහිර කිරීම ඉවත් කරන්නද?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"උපාංග කැමරාව අවහිර කිරීම ඉවත් කරන්නද?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"උපාංග කැමරාව සහ මයික්රෆෝනය අවහිර කිරීම ඉවත් කරන්නද?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> බොත්තම"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home යතුර"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"ආපසු"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"ඉහළ ඊතලය"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"පහළ ඊතලය"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"වම් ඊතලය"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"දකුණු ඊතලය"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"මැද"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"ඉඩ යතුර"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter යතුර"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"නැවූ"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"නොනැවූ"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> බැටරිය ඉතිරිව ඇත"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ඔබේ පන්හිඳ චාජරයකට සම්බන්ධ කරන්න"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"පන්හිඳ බැටරිය අඩුයි"</string> <string name="video_camera" msgid="7654002575156149298">"වීඩියෝ කැමරාව"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"<xliff:g id="APP_NAME">%1$s</xliff:g> විසින් මෑතකදී භාවිත කරන ලදි (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> භාවිත කරයි (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"<xliff:g id="APP_NAME">%1$s</xliff:g> විසින් මෑතකදී භාවිත කරන ලදි (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"පද්ධතිය"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"බහුකාර්ය"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ආදානය"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"යෙදුම් කෙටිමං"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ප්රවේශ්යතාව"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"යතුරු පුවරු කෙටි මං"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"කෙටි මං සොයන්න"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"හැකුළුම් නිරූපකය"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"දිගහැරීම් නිරූපකය"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"යතුරු පුවරු පසු ආලෝකය"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dන් %1$d වැනි මට්ටම"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 0df58c24e473..ba72fb491ac9 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Čo v zariadení bolo ovplyvnené?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Vyberte typ problému"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Rekordér obrazovky"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Výkon"</item> - <item msgid="1627504621139124393">"Používateľské rozhranie"</item> - <item msgid="8309220355268900335">"Batéria"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Režim jednej ruky"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Načúvacie zariadenia"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Načúvacie zariadenia"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Spárovať nové zariadenie"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknutím spárujete nové zariadenie"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Predvoľbu sa nepodarilo aktualizovať"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Predvoľba"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Živý prepis"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Chcete odblokovať mikrofón zariadenia?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Chcete odblokovať kameru zariadenia?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Chcete odblokovať fotoaparát a mikrofón zariadenia?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Tlačidlo <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Domov"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Späť"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Šípka nahor"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Šípka nadol"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Šípka doľava"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Šípka doprava"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Do stredu"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Medzerník"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zložené"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"rozložené"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Zostáva <xliff:g id="PERCENTAGE">%s</xliff:g> batérie"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Pripojte dotykové pero k nabíjačke"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Stav batérie dotykového pera je nízky"</string> <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Nedávno využila aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Využíva <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Nedávno využila aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Systém"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Vstup"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Odkazy do aplikácií"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Dostupnosť"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Klávesové skratky"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Vyhľadávacie odkazy"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona zbalenia"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozbalenia"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podsvietenie klávesnice"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. úroveň z %2$d"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 9bbe70e1724e..c6c1439f284d 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Na kateri del izkušnje z napravo je to vplivalo?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Izberite vrsto težave"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Snemanje zaslona"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Učinkovitost delovanja"</item> - <item msgid="1627504621139124393">"Uporabniški vmesnik"</item> - <item msgid="8309220355268900335">"Baterija"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enoročni način"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušni pripomočki"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušni pripomočki"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Seznanitev nove naprave"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite za seznanitev nove naprave"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Gumb <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Začetek"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Nazaj"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Puščica gor"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Puščica dol"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Puščica levo"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Puščica desno"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Sredina"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Preslednica"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Vnesi"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zaprto"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"razprto"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Preostanek energije baterije: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Povežite pisalo s polnilnikom."</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Skoraj prazna baterija pisala"</string> <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string> @@ -1327,6 +1328,8 @@ <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Bližnjice za iskanje"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za strnitev"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za razširitev"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Osvetlitev tipkovnice"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Stopnja %1$d od %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrolniki za dom"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 4aebab49320a..dc9407f8fd31 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -361,21 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cila pjesë e përvojës me pajisjen është prekur?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Zgjidh llojin e problemit"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Regjistrim i ekranit"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Performanca"</item> - <item msgid="1627504621139124393">"Ndërfaqja e përdoruesit"</item> - <item msgid="8309220355268900335">"Bateria"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modaliteti i përdorimit me një dorë"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Pajisje ndihmëse për dëgjimin"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Pajisjet e dëgjimit"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Çifto pajisje të re"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliko për të çiftuar një pajisje të re"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Paravendosja nuk mund të përditësohej"</string> - <!-- no translation found for hearing_devices_preset_label (7878267405046232358) --> - <skip /> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Paravendosja"</string> + <string name="live_caption_title" msgid="8916875614623730005">"Titra në çast"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Të zhbllokohet mikrofoni i pajisjes?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Të zhbllokohet kamera e pajisjes?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Të zhbllokohen kamera dhe mikrofoni i pajisjes?"</string> @@ -596,9 +599,9 @@ <string name="screen_pinning_negative" msgid="6882816864569211666">"Jo, faleminderit!"</string> <string name="screen_pinning_start" msgid="7483998671383371313">"Aplikacioni u gozhdua"</string> <string name="screen_pinning_exit" msgid="4553787518387346893">"Aplikacioni u zhgozhdua"</string> - <string name="stream_voice_call" msgid="7468348170702375660">"Telefono"</string> + <string name="stream_voice_call" msgid="7468348170702375660">"Telefonata"</string> <string name="stream_system" msgid="7663148785370565134">"Sistemi"</string> - <string name="stream_ring" msgid="7550670036738697526">"Bjeri ziles"</string> + <string name="stream_ring" msgid="7550670036738697526">"Zilja"</string> <string name="stream_music" msgid="2188224742361847580">"Media"</string> <string name="stream_alarm" msgid="16058075093011694">"Alarmi"</string> <string name="stream_notification" msgid="7930294049046243939">"Njoftimi"</string> @@ -729,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Butoni <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Kreu"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Prapa"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Shigjeta lart"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Shigjeta poshtë"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Shigjeta majtas"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Shigjeta djathtas"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Qendror"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Hapësirë"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1277,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"palosur"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"shpalosur"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Përqindja e mbetur e baterisë: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Lidhe stilolapsin me një karikues"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Bateria e stilolapsit në nivel të ulët"</string> <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string> @@ -1320,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Përdorur së fundi nga <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Në përdorim nga <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Përdorur së fundi nga <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Sistemi"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Kryerja e shumë detyrave"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Hyrja"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Shkurtoret e aplikacionit"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Qasshmëria"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Shkurtoret e tastierës"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Kërko për shkurtoret"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona e palosjes"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona e zgjerimit"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Drita e sfondit e tastierës"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveli: %1$d nga %2$d"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 0f0d78d10b40..1228eef8c88b 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -361,13 +361,15 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"На који део доживљаја на уређају је ово утицало?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Изаберите тип проблема"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Снимање екрана"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Учинак"</item> - <item msgid="1627504621139124393">"Кориснички интерфејс"</item> - <item msgid="8309220355268900335">"Батерија"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"Перформансе"</string> + <string name="user_interface" msgid="3712869377953950887">"Кориснички интерфејс"</string> + <string name="thermal" msgid="6758074791325414831">"Термална камера"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим једном руком"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слушни апарати"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слушни апарати"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Упари нови уређај"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Кликните да бисте упарили нов уређај"</string> @@ -727,11 +729,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Дугме <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Тастер Почетна"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Тастер Назад"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Стрелица нагоре"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Стрелица надоле"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Стрелица налево"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Стрелица надесно"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Тастер са централном стрелицом"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Размак"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1272,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"затворено"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"отворено"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Преостало је још<xliff:g id="PERCENTAGE">%s</xliff:g> батерије"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Батерија писаљке је на <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Повежите писаљку са пуњачем"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Низак ниво батерије писаљке"</string> <string name="video_camera" msgid="7654002575156149298">"Видео камера"</string> @@ -1327,6 +1324,8 @@ <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Пречице претраге"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за скупљање"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за проширивање"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Позадинско осветљење тастатуре"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. ниво од %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Контроле за дом"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 2b888292dffe..cf2b93cabe75 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -361,13 +361,15 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Vilken enhetsupplevelse påverkades?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Välj problemtyp"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skärminspelning"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Prestanda"</item> - <item msgid="1627504621139124393">"Användargränssnitt"</item> - <item msgid="8309220355268900335">"Batteri"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"Prestanda"</string> + <string name="user_interface" msgid="3712869377953950887">"Användargränssnitt"</string> + <string name="thermal" msgid="6758074791325414831">"Termisk"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enhandsläge"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hörhjälpmedel"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hörhjälpmedel"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parkoppla en ny enhet"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klicka för att parkoppla en ny enhet"</string> @@ -727,11 +729,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Knappen <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Start"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Tillbaka"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Uppåtpil"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Nedåtpil"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Vänsterpil"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Högerpil"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Centrera"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Blanksteg"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Retur"</string> @@ -1275,7 +1272,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"hopvikt"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"uppvikt"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> av batteriet återstår"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"E-pennans batteri: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Anslut e-pennan till en laddare"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"E-pennans batterinivå är låg"</string> <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string> @@ -1318,23 +1315,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Användes nyligen av <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Används av <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Användes nyligen av <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"System"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multikörning"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Ingång"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Genvägar till appar"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Tillgänglighet"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Kortkommandon"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Sökgenvägar"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikonen Komprimera"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikonen Utöka"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Bakgrundsbelysning för tangentbord"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivå %1$d av %2$d"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 5260a5af87d0..1ee1d0cf6165 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Ni sehemu gani ya matumizi ya kifaa iliathiriwa?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Chagua aina ya tatizo"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Rekodi ya skrini"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Utendaji"</item> - <item msgid="1627504621139124393">"Kiolesura cha Mtumiaji"</item> - <item msgid="8309220355268900335">"Betri"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Hali ya kutumia kwa mkono mmoja"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Vifaa vya kusikilizia"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Vifaa vya kusikilizia"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Unganisha kifaa kipya"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Bofya ili uunganishe kifaa kipya"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Kitufe cha <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Mwanzo"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Nyuma"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Kishale cha juu"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Kishale cha chini"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Kishale cha kushoto"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Kishale cha kulia"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Katikati"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kimekunjwa"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kimefunguliwa"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Chaji ya betri imesalia <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Unganisha stylus yako kwenye chaja"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Chaji ya betri ya Stylus imepungua"</string> <string name="video_camera" msgid="7654002575156149298">"Kamera ya video"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Ilitumiwa hivi majuzi na <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Inatumiwa na <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Ilitumiwa hivi majuzi na <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Mfumo"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Majukumu mengi"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Kifaa cha kuingiza data"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Njia za mikato za programu"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Ufikivu"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Mikato ya kibodi"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Njia mkato za kutafutia"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Kunja aikoni"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Panua aikoni"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Mwanga chini ya kibodi"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Kiwango cha %1$d kati ya %2$d"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 67a31af91eb7..6e95c3b5e2dc 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"சாதன அனுபவத்தின் எந்தப் பகுதி பாதிக்கப்பட்டது?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"சிக்கல் வகையைத் தேர்வுசெய்க"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ஸ்கிரீன் ரெக்கார்டு"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"செயல்திறன்"</item> - <item msgid="1627504621139124393">"பயனர் இடைமுகம்"</item> - <item msgid="8309220355268900335">"பேட்டரி"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ஒற்றைக் கைப் பயன்முறை"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"செவித்துணைக் கருவிகள்"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"செவித்துணைக் கருவிகள்"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"புதிய சாதனத்தை இணை"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"புதிய சாதனத்தை இணைக்க கிளிக் செய்யலாம்"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"முன்னமைவைப் புதுப்பிக்க முடியவில்லை"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"முன்னமைவு"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"உடனடி வசன உரை"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"சாதனத்தின் மைக்ரோஃபோனுக்கான தடுப்பை நீக்கவா?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"சாதனத்தின் கேமராவுக்கான தடுப்பை நீக்கவா?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"சாதனத்தின் கேமராவுக்கும் மைக்ரோஃபோனுக்குமான தடுப்பை நீக்கவா?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> பட்டன்"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"ஹோம்"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"பேக்"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"மேல்நோக்கிய அம்புக்குறி"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"கீழ்நோக்கிய அம்புக்குறி"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"இடது அம்புக்குறி"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"வலது அம்புக்குறி"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"நடு"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"ஸ்பேஸ்"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"என்டர்"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"மடக்கப்பட்டது"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"விரிக்கப்பட்டது"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> பேட்டரி மீதமுள்ளது"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"உங்கள் ஸ்டைலஸைச் சார்ஜருடன் இணையுங்கள்"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"ஸ்டைலஸின் பேட்டரி குறைவாக உள்ளது"</string> <string name="video_camera" msgid="7654002575156149298">"வீடியோ கேமரா"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) ஆப்ஸால் சமீபத்தில் பயன்படுத்தப்பட்டது"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ஆப்ஸால் பயன்படுத்தப்படுகிறது"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ஆப்ஸால் சமீபத்தில் பயன்படுத்தப்பட்டது"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"சிஸ்டம்"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"பல வேலைகளைச் செய்தல்"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"உள்ளீடு"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ஆப்ஸ் ஷார்ட்கட்கள்"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"அணுகல்தன்மை"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"கீபோர்டு ஷார்ட்கட்கள்"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"தேடல் ஷார்ட்கட்கள்"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"சுருக்குவதற்கான ஐகான்"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"விரிவாக்குவதற்கான ஐகான்"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"கீபோர்டு பேக்லைட்"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"நிலை, %2$d இல் %1$d"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 6e108964f4f1..64d6f9e2419c 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"మీ పరికర అనుభవంలో ఏ భాగం ప్రభావితమైంది?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"సమస్య రకాన్ని ఎంచుకోండి"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"స్క్రీన్ రికార్డ్"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"పనితీరు"</item> - <item msgid="1627504621139124393">"యూజర్ ఇంటర్ఫేస్"</item> - <item msgid="8309220355268900335">"బ్యాటరీ"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"వన్-హ్యాండెడ్ మోడ్"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"వినికిడి పరికరాలు"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"వినికిడి పరికరాలు"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"కొత్త పరికరాన్ని పెయిర్ చేయండి"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"కొత్త పరికరాన్ని పెయిర్ చేయడానికి క్లిక్ చేయండి"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"ప్రీసెట్ను అప్డేట్ చేయడం సాధ్యపడలేదు"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"ప్రీసెట్"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"లైవ్ క్యాప్షన్"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"పరికరం మైక్రోఫోన్ను అన్బ్లాక్ చేయమంటారా?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"పరికరంలోని కెమెరాను అన్బ్లాక్ చేయమంటారా?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"పరికరంలోని కెమెరా, మైక్రోఫోన్లను అన్బ్లాక్ చేయమంటారా?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"బటన్ <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"వెనుకకు"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"పై వైపు బాణం"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"కింది వైపు బాణం"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"ఎడమ వైపు బాణం"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"కుడి వైపు బాణం"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"మధ్య"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -989,7 +988,7 @@ <string name="magnification_close_settings_click_label" msgid="4642477260651704517">"మాగ్నిఫికేషన్ సెట్టింగ్లను మూసివేయండి"</string> <string name="magnification_exit_edit_mode_click_label" msgid="1664818325144887117">"సవరణ మోడ్ నుండి ఎగ్జిట్ అవ్వండి"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"సైజ్ మార్చడానికి మూలను లాగండి"</string> - <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"డయాగనల్ స్క్రోలింగ్ను అనుమతించండి"</string> + <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"డయాగోనల్ స్క్రోలింగ్ను అనుమతించండి"</string> <string name="accessibility_resize" msgid="5733759136600611551">"సైజ్ మార్చండి"</string> <string name="accessibility_change_magnification_type" msgid="666000085077432421">"మ్యాగ్నిఫికేషన్ రకాన్ని మార్చండి"</string> <string name="accessibility_magnification_end_resizing" msgid="4881690585800302628">"సైజ్ను మార్చడం ముగించండి"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"మడిచే సదుపాయం గల పరికరం"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"మడిచే సదుపాయం లేని పరికరం"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> బ్యాటరీ మిగిలి ఉంది"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"మీ స్టైలస్ను ఛార్జర్కి కనెక్ట్ చేయండి"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"తక్కువ స్టైలస్ బ్యాటరీ"</string> <string name="video_camera" msgid="7654002575156149298">"వీడియో కెమెరా"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) ద్వారా ఇటీవల వినియోగించబడింది"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ద్వారా వినియోగంలో ఉంది"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ద్వారా ఇటీవల ఉపయోగించబడింది"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"సిస్టమ్"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"మల్టీ-టాస్కింగ్"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ఇన్పుట్"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"యాప్ షార్ట్కట్లు"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"యాక్సెసిబిలిటీ"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"కీబోర్డ్ షార్ట్కట్లు"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"సెర్చ్ షార్ట్కట్లు"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"కుదించండి చిహ్నం"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"విస్తరించండి చిహ్నం"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"కీబోర్డ్ బ్యాక్లైట్"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dలో %1$dవ స్థాయి"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 1f0f45a160d6..8a766299f354 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -361,20 +361,21 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ประสบการณ์การใช้งานอุปกรณ์ส่วนใดที่ได้รับผลกระทบ"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"เลือกประเภทปัญหา"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"บันทึกหน้าจอ"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"ประสิทธิภาพ"</item> - <item msgid="1627504621139124393">"อินเทอร์เฟซผู้ใช้"</item> - <item msgid="8309220355268900335">"แบตเตอรี่"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"ประสิทธิภาพ"</string> + <string name="user_interface" msgid="3712869377953950887">"อินเทอร์เฟซผู้ใช้"</string> + <string name="thermal" msgid="6758074791325414831">"ความร้อน"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"โหมดมือเดียว"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"เครื่องช่วยฟัง"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"เครื่องช่วยฟัง"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"จับคู่อุปกรณ์ใหม่"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"คลิกเพื่อจับคู่อุปกรณ์ใหม่"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"ไม่สามารถอัปเดตค่าที่กำหนดล่วงหน้า"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"ค่าที่กำหนดล่วงหน้า"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"คำบรรยายสด"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"เลิกบล็อกไมโครโฟนของอุปกรณ์ใช่ไหม"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"เลิกบล็อกกล้องของอุปกรณ์ใช่ไหม"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"เลิกบล็อกกล้องและไมโครโฟนของอุปกรณ์ใช่ไหม"</string> @@ -728,11 +729,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"ปุ่ม <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"กลับ"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"ลูกศรขึ้น"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"ลูกศรลง"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"ลูกศรซ้าย"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"ลูกศรขวา"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"กึ่งกลาง"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"วรรค"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1276,7 +1272,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"พับ"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"กางออก"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"เหลือแบตเตอรี่ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"แบตเตอรี่สไตลัส <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"เชื่อมต่อสไตลัสกับที่ชาร์จ"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"แบตเตอรี่สไตลัสเหลือน้อย"</string> <string name="video_camera" msgid="7654002575156149298">"กล้องวิดีโอ"</string> @@ -1319,23 +1315,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"ใช้ล่าสุดโดย <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"ใช้อยู่โดย <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"ใช้ล่าสุดโดย <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"ระบบ"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"การทํางานหลายอย่างพร้อมกัน"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"อินพุต"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"แป้นพิมพ์ลัดของแอป"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"การช่วยเหลือพิเศษ"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"แป้นพิมพ์ลัด"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ค้นหาแป้นพิมพ์ลัด"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ไอคอนยุบ"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ไอคอนขยาย"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ไฟแบ็กไลต์ของแป้นพิมพ์"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"ระดับที่ %1$d จาก %2$d"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index d3517d40ba11..e74139f693a9 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -361,20 +361,21 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Ano\'ng naapektuhang parte ng experience sa device?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Piliin ang uri ng isyu"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Pag-record ng screen"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Performance"</item> - <item msgid="1627504621139124393">"User Interface"</item> - <item msgid="8309220355268900335">"Baterya"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"Performance"</string> + <string name="user_interface" msgid="3712869377953950887">"User Interface"</string> + <string name="thermal" msgid="6758074791325414831">"Thermal"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-hand mode"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Mga hearing device"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Mga hearing device"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Magpares ng bagong device"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"I-click para magpares ng bagong device"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Hindi ma-update ang preset"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preset"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Instant Caption"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"I-unblock ang mikropono ng device?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"I-unblock ang camera ng device?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"I-unblock ang camera at mikropono ng device?"</string> @@ -728,11 +729,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Button na <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Back"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Pataas na arrow"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Pababang arrow"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Pakaliwang arrow"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Pakanang arrow"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Center"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1276,7 +1272,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"naka-fold"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"hindi naka-fold"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> baterya na lang ang natitira"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Baterya ng stylus <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ikonekta sa charger ang iyong stylus"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Paubos na ang baterya ng stylus"</string> <string name="video_camera" msgid="7654002575156149298">"Video camera"</string> @@ -1319,23 +1315,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Kamakailang ginamit ng <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Ginagamit ng <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Kamakailang ginamit ng <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"System"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Pag-multitask"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Mga shortcut ng app"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibility"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Mga keyboard shortcut"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Mga shortcut ng paghahanap"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"I-collapse ang icon"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"I-expand ang icon"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Backlight ng keyboard"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d sa %2$d"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index b54fd95a73ff..a66fbedd4769 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cihaz deneyiminiz ne şekilde etkilendi?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Sorun türünü seçin"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekran kaydedicisi"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Performans"</item> - <item msgid="1627504621139124393">"Kullanıcı Arayüzü"</item> - <item msgid="8309220355268900335">"Pil"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Tek el modu"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"İşitme cihazları"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"İşitme cihazları"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Yeni cihaz eşle"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Yeni cihaz eşlemek için tıklayın"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> düğmesi"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Geri"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Yukarı ok"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Aşağı ok"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Sol ok"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Sağ ok"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Orta"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Boşluk"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"katlanmış"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"katlanmamış"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> pil kaldı"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ekran kaleminizi bir şarj cihazına bağlayın"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Ekran kaleminin pil seviyesi düşük"</string> <string name="video_camera" msgid="7654002575156149298">"Video kamera"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"En son <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) tarafından kullanıldı"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) tarafından kullanılıyor"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"En son <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) tarafından kullanıldı"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Sistem"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Çoklu görev becerisi"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Giriş"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Uygulama kısayolları"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Erişilebilirlik"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Klavye kısayolları"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Arama kısayolları"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Daralt simgesi"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Genişlet simgesi"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klavye aydınlatması"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Seviye %1$d / %2$d"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 4768dcb86781..5262d744336d 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"На який аспект роботи пристрою вплинула проблема?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Виберіть тип проблеми"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запис відео з екрана"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Продуктивність"</item> - <item msgid="1627504621139124393">"Інтерфейс користувача"</item> - <item msgid="8309220355268900335">"Акумулятор"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим керування однією рукою"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слухові апарати"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слухові апарати"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Підключити новий пристрій"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Натисніть, щоб підключити новий пристрій"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Не вдалось оновити набір налаштувань"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Набір налаштувань"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Живі субтитри"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Надати доступ до мікрофона?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Надати доступ до камери пристрою?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Надати доступ до камери й мікрофона?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Кнопка <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Назад"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Стрілка вгору"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Стрілка вниз"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Стрілка вліво"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Стрілка вправо"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Центр"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Пробіл"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"складений"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"розкладений"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Заряд акумулятора: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Підключіть стилус до зарядного пристрою"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Низький заряд акумулятора стилуса"</string> <string name="video_camera" msgid="7654002575156149298">"Відеокамера"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Нещодавно використано (<xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Використовується додатком <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Нещодавно використано (<xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Система"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Багатозадачність"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Введення"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Комбінації клавіш для додатків"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Доступність"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Комбінації клавіш"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Комбінації клавіш для пошуку"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок згортання"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок розгортання"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Підсвічування клавіатури"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Рівень %1$d з %2$d"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 9410327f8ce9..0d3f1feb406f 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -361,20 +361,21 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"آپ کے آلے کے تجربے کا کون سا حصہ متاثر ہوا؟"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"مسئلہ کی قسم منتخب کریں"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"اسکرین ریکارڈ"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"کارکردگی"</item> - <item msgid="1627504621139124393">"یوزر انٹرفیس"</item> - <item msgid="8309220355268900335">"بیٹری"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"کارکردگی"</string> + <string name="user_interface" msgid="3712869377953950887">"یوزر انٹرفیس"</string> + <string name="thermal" msgid="6758074791325414831">"تھرمل"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ایک ہاتھ کی وضع"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"سماعت کے آلات"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"سماعت کے آلات"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"نئے آلے کا جوڑا بنائیں"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"نئے آلے کا جوڑا بنانے کے لیے کلک کریں"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"پہلے سے ترتیب شدہ کو اپ ڈیٹ نہیں کیا جا سکا"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"پہلے سے ترتیب شدہ"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"لائیو کیپشن"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"آلے کا مائیکروفون غیر مسدود کریں؟"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"آلے کا کیمرا غیر مسدود کریں؟"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"آلے کا کیمرا اور مائیکروفون غیر مسدود کریں؟"</string> @@ -732,11 +733,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"بٹن <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"پیچھے"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"اوپر تیر کا نشان"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"نیچے تیر کا نشان"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"بایاں تیر"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"دایاں تیر"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"سینٹر"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1280,7 +1276,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"فولڈ کردہ"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"اَن فولڈ کردہ"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> بیٹری باقی ہے"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"<xliff:g id="PERCENTAGE">%s</xliff:g> اسٹائلس بیٹری"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"اپنے اسٹائلس کو چارجر منسلک کریں"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"اسٹائلس بیٹری کم ہے"</string> <string name="video_camera" msgid="7654002575156149298">"ویڈیو کیمرا"</string> @@ -1323,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) کے ذریعے حال ہی میں استعمال کیا گیا"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) کے زیر استعمال"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) کے ذریعے حال ہی میں استعمال کیا گیا"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"سسٹم"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ملٹی ٹاسکنگ"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ان پٹ"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ایپ شارٹ کٹس"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ایکسیسبیلٹی"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"کی بورڈ شارٹ کٹس"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"تلاش کے شارٹ کٹس"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"آئیکن سکیڑیں"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"آئیکن پھیلائیں"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"کی بورڈ بیک لائٹ"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d میں سے %1$d کا لیول"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 8ad7e1491237..3f3983d21fb0 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -361,13 +361,15 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Qurilma ishlashining qaysi qismiga taʼsir qildi?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Muammo turini tanlang"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekran yozuvi"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Unumdorlik"</item> - <item msgid="1627504621139124393">"Foydalanuvchi interfeysi"</item> - <item msgid="8309220355268900335">"Batareya"</item> - </string-array> + <string name="performance" msgid="6552785217174378320">"Unumdorlik"</string> + <string name="user_interface" msgid="3712869377953950887">"Foydalanuvchi interfeysi"</string> + <string name="thermal" msgid="6758074791325414831">"Termal"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Ixcham rejim"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Eshitish qurilmalari"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Eshitish qurilmalari"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Yangi qurilmani ulash"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Yangi qurilmani ulash uchun bosing"</string> @@ -727,11 +729,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> tugmasi"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Bosh ekran"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Orqaga"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Tepaga strelka"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Pastga strelka"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Chapga strelka"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Oʻngga strelka"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Markaziy ko‘rsatkichli chiziq"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Probel"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1272,7 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"buklangan"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"buklanmagan"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Batareya quvvati: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Stilus batareyasi: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Stilusni quvvat manbaiga ulang"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Stilus batareyasi kam"</string> <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string> @@ -1318,23 +1315,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Yaqinda <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) ishlatgan"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ishlatmoqda"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Yaqinda <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ishlatgan"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Tizim"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multi-vazifalilik"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Kiritish"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Ilova yorliqlari"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Qulayliklar"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Tezkor tugmalar"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Tezkor tugmalar qidiruvi"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Yigʻish belgisi"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Yoyish belgisi"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatura orqa yoritkichi"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Daraja: %1$d / %2$d"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 1efa9838a04b..dc4fa1241559 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -247,7 +247,7 @@ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Không làm phiền."</string> <string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string> <string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth bật."</string> - <string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Báo thức được đặt cho <xliff:g id="TIME">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Chuông báo được đặt cho <xliff:g id="TIME">%s</xliff:g>."</string> <string name="accessibility_quick_settings_more_time" msgid="7646479831704665284">"Nhiều thời gian hơn."</string> <string name="accessibility_quick_settings_less_time" msgid="9110364286464977870">"Ít thời gian hơn."</string> <string name="accessibility_casting_turned_off" msgid="1387906158563374962">"Đã ngừng truyền màn hình."</string> @@ -361,13 +361,18 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Bạn gặp loại vấn đề gì khi dùng thiết bị?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Chọn loại vấn đề"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ghi màn hình"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Hiệu suất"</item> - <item msgid="1627504621139124393">"Giao diện người dùng"</item> - <item msgid="8309220355268900335">"Pin"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Chế độ một tay"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Thiết bị trợ thính"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Thiết bị trợ thính"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Ghép nối thiết bị mới"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Nhấp để ghép nối thiết bị mới"</string> @@ -594,11 +599,11 @@ <string name="screen_pinning_negative" msgid="6882816864569211666">"Không, cảm ơn"</string> <string name="screen_pinning_start" msgid="7483998671383371313">"Đã ghim ứng dụng"</string> <string name="screen_pinning_exit" msgid="4553787518387346893">"Đã bỏ ghim ứng dụng"</string> - <string name="stream_voice_call" msgid="7468348170702375660">"Gọi"</string> + <string name="stream_voice_call" msgid="7468348170702375660">"Cuộc gọi"</string> <string name="stream_system" msgid="7663148785370565134">"Hệ thống"</string> <string name="stream_ring" msgid="7550670036738697526">"Chuông"</string> <string name="stream_music" msgid="2188224742361847580">"Nội dung nghe nhìn"</string> - <string name="stream_alarm" msgid="16058075093011694">"Báo thức"</string> + <string name="stream_alarm" msgid="16058075093011694">"Chuông báo"</string> <string name="stream_notification" msgid="7930294049046243939">"Thông báo"</string> <string name="stream_bluetooth_sco" msgid="6234562365528664331">"Bluetooth"</string> <string name="stream_dtmf" msgid="7322536356554673067">"Tần số đa chuông kép"</string> @@ -642,7 +647,7 @@ <string name="enable_demo_mode" msgid="3180345364745966431">"Bật chế độ trình diễn"</string> <string name="show_demo_mode" msgid="3677956462273059726">"Hiển thị chế độ trình diễn"</string> <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string> - <string name="status_bar_alarm" msgid="87160847643623352">"Báo thức"</string> + <string name="status_bar_alarm" msgid="87160847643623352">"Chuông báo"</string> <string name="wallet_title" msgid="5369767670735827105">"Ví"</string> <string name="wallet_empty_state_label" msgid="7776761245237530394">"Thiết lập để mua hàng nhanh hơn và an toàn hơn bằng điện thoại"</string> <string name="wallet_app_button_label" msgid="7123784239111190992">"Hiện tất cả"</string> @@ -655,7 +660,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Đang cập nhật"</string> <string name="status_bar_work" msgid="5238641949837091056">"Hồ sơ công việc"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Chế độ trên máy bay"</string> - <string name="zen_alarm_warning" msgid="7844303238486849503">"Bạn sẽ không nghe thấy báo thức tiếp theo lúc <xliff:g id="WHEN">%1$s</xliff:g> của mình"</string> + <string name="zen_alarm_warning" msgid="7844303238486849503">"Bạn sẽ không nghe thấy chuông báo tiếp theo lúc <xliff:g id="WHEN">%1$s</xliff:g> của mình"</string> <string name="alarm_template" msgid="2234991538018805736">"lúc <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"vào <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Điểm phát sóng"</string> @@ -727,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Nút <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Quay lại"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Mũi tên lên"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Mũi tên xuống"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Mũi tên trái"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Mũi tên phải"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Giữa"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Dấu cách"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -1275,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"gập"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"mở"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Còn <xliff:g id="PERCENTAGE">%s</xliff:g> pin"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Hãy kết nối bút cảm ứng với bộ sạc"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Bút cảm ứng bị yếu pin"</string> <string name="video_camera" msgid="7654002575156149298">"Máy quay video"</string> @@ -1318,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) đã dùng gần đây"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) đang dùng"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) đã dùng gần đây"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Hệ thống"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Đa nhiệm"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Phương thức nhập"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Lối tắt ứng dụng"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Hỗ trợ tiếp cận"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Phím tắt"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Lối tắt tìm kiếm"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Biểu tượng Thu gọn"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Biểu tượng Mở rộng"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Đèn nền bàn phím"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Độ sáng %1$d/%2$d"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 0860f31bb370..9b69f9ef2086 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -361,25 +361,29 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"设备体验的哪个方面受到影响?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"选择问题类型"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"屏幕录制"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"性能"</item> - <item msgid="1627504621139124393">"界面"</item> - <item msgid="8309220355268900335">"电池"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"单手模式"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"助听装置"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"助听装置"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"与新设备配对"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"点击即可与新设备配对"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"无法更新预设"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"预设"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"实时字幕"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要解锁设备麦克风吗?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"要解锁设备摄像头吗?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"要解锁设备摄像头和麦克风吗?"</string> - <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"这将会为所有获准使用您麦克风的应用和服务启用这项权限。"</string> - <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"这将会为所有获准使用您摄像头的应用和服务启用这项权限。"</string> + <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"解锁后,所有具有麦克风使用权的应用和服务都可使用您的麦克风。"</string> + <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"解锁后,所有具有摄像头使用权的应用和服务都可使用您的摄像头。"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"这将会为所有获准使用您的摄像头或麦克风的应用和服务启用这项权限。"</string> <string name="sensor_privacy_start_use_mic_blocked_dialog_title" msgid="2640140287496469689">"麦克风已被屏蔽"</string> <string name="sensor_privacy_start_use_camera_blocked_dialog_title" msgid="7398084286822440384">"摄像头已被屏蔽"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g>按钮"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"返回"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"向上键"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"向下键"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"向左键"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"向右键"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"中心"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"空格"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> @@ -934,7 +933,7 @@ <string name="running_foreground_services_title" msgid="5137313173431186685">"在后台运行的应用"</string> <string name="running_foreground_services_msg" msgid="3009459259222695385">"点按即可详细了解电量和流量消耗情况"</string> <string name="mobile_data_disable_title" msgid="5366476131671617790">"要关闭移动数据网络吗?"</string> - <string name="mobile_data_disable_message" msgid="8604966027899770415">"您将无法通过<xliff:g id="CARRIER">%s</xliff:g>使用移动数据或互联网,只能通过 WLAN 连接到互联网。"</string> + <string name="mobile_data_disable_message" msgid="8604966027899770415">"关闭后,您将无法通过<xliff:g id="CARRIER">%s</xliff:g>使用移动数据或互联网,只能通过 WLAN 连接到互联网。"</string> <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"您的运营商"</string> <string name="auto_data_switch_disable_title" msgid="5146527155665190652">"是否要切换回 <xliff:g id="CARRIER">%s</xliff:g>?"</string> <string name="auto_data_switch_disable_message" msgid="5885533647399535852">"移动流量不会根据网络可用情况自动切换"</string> @@ -1208,7 +1207,7 @@ <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"添加功能块"</string> <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"不添加功能块"</string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"选择用户"</string> - <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# 个应用处于活动状态}other{# 个应用处于活动状态}}"</string> + <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# 个应用处于运行状态}other{# 个应用处于运行状态}}"</string> <string name="fgs_dot_content_description" msgid="2865071539464777240">"新信息"</string> <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"已开启的应用"</string> <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"这些应用即使在闲置时仍处于活跃运行状态。应用的功能会因此提升,但可能会影响电池续航时间。"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"折叠状态"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"展开状态"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"电池还剩 <xliff:g id="PERCENTAGE">%s</xliff:g> 的电量"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"请将触控笔连接充电器"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"触控笔电池电量低"</string> <string name="video_camera" msgid="7654002575156149298">"摄像机"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”最近使用过(<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正在使用(<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”最近使用过(<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"系统"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"多任务处理"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"输入"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"应用快捷键"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"无障碍功能"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"键盘快捷键"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"搜索快捷键"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收起图标"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展开图标"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"键盘背光"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"第 %1$d 级,共 %2$d 级"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 39c1b2b46965..5c164ab23c28 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"哪些裝置使用體驗受影響?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"選取問題類型"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"螢幕錄影"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"效能"</item> - <item msgid="1627504621139124393">"使用者介面"</item> - <item msgid="8309220355268900335">"電池"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"單手模式"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"助聽器"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"助聽器"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"配對新裝置"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"㩒一下就可以配對新裝置"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"無法更新預設"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"預設"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"即時字幕"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要解除封鎖裝置麥克風嗎?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"要解除封鎖裝置相機嗎?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"要解除封鎖裝置相機和麥克風嗎?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> 鍵"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"返回"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"向上箭咀"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"向下箭咀"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"向左箭咀"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"向右箭咀"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"箭咀中央"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"空格"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"輸入 (Enter)"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"已摺疊"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"已打開"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"剩餘電量:<xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"將觸控筆連接充電器"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"觸控筆電量不足"</string> <string name="video_camera" msgid="7654002575156149298">"攝影機"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」最近使用過此權限 (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> 正在使用 (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」最近使用過此權限 (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"系統"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"多工處理"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"輸入"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"應用程式捷徑"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"無障礙功能"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"鍵盤快速鍵"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"搜尋快速鍵"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收合圖示"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展開圖示"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"鍵盤背光"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"第 %1$d 級,共 %2$d 級"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index f1a6f8112689..0d50ad57768d 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"哪些裝置使用體驗受到影響?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"選取問題類型"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"螢幕錄影"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"效能"</item> - <item msgid="1627504621139124393">"使用者介面"</item> - <item msgid="8309220355268900335">"電池"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"單手模式"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"助聽器"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"助聽器"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"配對新裝置"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"按一下即可配對新裝置"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"無法更新預設設定"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"預設"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"即時字幕"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要解除封鎖裝置麥克風嗎?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"要解除封鎖裝置相機嗎?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"要將裝置的相機和麥克風解除封鎖嗎?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> 按鈕"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home 鍵"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"返回"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"向上箭頭"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"向下箭頭"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"向左箭頭"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"向右箭頭"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"中央鍵"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"空格鍵"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter 鍵"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"已摺疊"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"已展開"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"剩餘電量:<xliff:g id="PERCENTAGE">%s</xliff:g>"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"將觸控筆接上充電器"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"觸控筆電力不足"</string> <string name="video_camera" msgid="7654002575156149298">"攝影機"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」最近用過這項權限 (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"正由「<xliff:g id="APP_NAME">%1$s</xliff:g>」使用 (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」最近用過這項權限 (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"系統"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"多工處理"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"輸入"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"應用程式捷徑"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"無障礙"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"鍵盤快速鍵"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"搜尋快速鍵"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收合圖示"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展開圖示"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"鍵盤背光"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"第 %1$d 級,共 %2$d 級"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 840d8a6db8ce..2e03bd502214 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -361,20 +361,24 @@ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Kuthinteke yiphi ingxenye yokusebenzisa idivayisi?"</string> <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Khetha uhlobo lwenkinga"</string> <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Irekhodi lesikrini"</string> - <string-array name="qs_record_issue_types"> - <item msgid="2947988124014085798">"Ukusebenza"</item> - <item msgid="1627504621139124393">"Okusetshenziswa Kubonwa"</item> - <item msgid="8309220355268900335">"Ibhethri"</item> - </string-array> + <!-- no translation found for performance (6552785217174378320) --> + <skip /> + <!-- no translation found for user_interface (3712869377953950887) --> + <skip /> + <!-- no translation found for thermal (6758074791325414831) --> + <skip /> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Imodi yesandla esisodwa"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Izinsizakuzwa"</string> + <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) --> + <skip /> + <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) --> + <skip /> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Izinsizakuzwa"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Bhangqa idivayisi entsha"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Chofoza ukuze ubhangqe idivayisi entsha"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Ayikwazanga ukubuyekeza ukusetha ngaphambilini"</string> <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Ukusetha ngaphambilini"</string> - <!-- no translation found for live_caption_title (8916875614623730005) --> - <skip /> + <string name="live_caption_title" msgid="8916875614623730005">"Amagama-ncazo abukhoma"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vulela imakrofoni yedivayisi?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vulela ikhamera yedivayisi?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vulela ikhamera yedivayisi nemakrofoni?"</string> @@ -728,11 +732,6 @@ <string name="keyboard_key_button_template" msgid="8005673627272051429">"Inkinobho <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Ekhaya"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Emuva"</string> - <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Umcibisholo waphezulu"</string> - <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Umcibisholo waphansi"</string> - <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Umcibisholo wangokwesokunxele"</string> - <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Umcibisholo wangokwesokudla"</string> - <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Maphakathi"</string> <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Isikhala"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Faka"</string> @@ -1276,7 +1275,8 @@ <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kugoqiwe"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kuvuliwe"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> - <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ibhethri elisele"</string> + <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) --> + <skip /> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Xhuma i-stylus yakho kushaja"</string> <string name="stylus_battery_low" msgid="7134370101603167096">"Ibhethri le-stylus liphansi"</string> <string name="video_camera" msgid="7654002575156149298">"Ikhamera yevidiyo"</string> @@ -1319,23 +1319,16 @@ <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Kusetshenziswe kamuva yi-<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Isetshenziswa yi-<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Kusetshenziswe kamuva yi-<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> - <!-- no translation found for shortcut_helper_category_system (462110876978937359) --> - <skip /> - <!-- no translation found for shortcut_helper_category_multitasking (7413381961404090136) --> - <skip /> - <!-- no translation found for shortcut_helper_category_input (8674018654124839566) --> - <skip /> - <!-- no translation found for shortcut_helper_category_app_shortcuts (8010249408308587117) --> - <skip /> - <!-- no translation found for shortcut_helper_category_a11y (6314444792641773464) --> - <skip /> - <!-- no translation found for shortcut_helper_title (8567500639300970049) --> - <skip /> - <!-- no translation found for shortcut_helper_search_placeholder (5488547526269871819) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_collapse_icon (8028015738431664954) --> - <skip /> - <!-- no translation found for shortcut_helper_content_description_expand_icon (1084435697860417390) --> + <string name="shortcut_helper_category_system" msgid="462110876978937359">"Isistimu"</string> + <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Ukwenza imisebenzi eminingi"</string> + <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Okokufaka"</string> + <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Izinqamuleli Zohlelo lokusebenza"</string> + <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Ukufinyeleleka"</string> + <string name="shortcut_helper_title" msgid="8567500639300970049">"Izinqamuleli zekhibhodi"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Sesha izinqamuleli"</string> + <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Goqa isithonjana"</string> + <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Nweba isithonjana"</string> + <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) --> <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Ilambu lekhibhodi"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Ileveli %1$d ka-%2$d"</string> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index fb883640c9a9..f8762f0a98d5 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -37,6 +37,9 @@ <item>400</item> </integer-array> + <!-- Whether to use deadzone with nav bar --> + <bool name="config_useDeadZone">true</bool> + <!-- decay duration (from size_max -> size), in ms --> <integer name="navigation_bar_deadzone_hold">333</integer> <integer name="navigation_bar_deadzone_decay">333</integer> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index f6ab4c854614..d979abbe0af9 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -912,6 +912,10 @@ obvious when corner radii differ.--> <dimen name="communal_enforced_rounded_corner_max_radius">28dp</dimen> + <!-- Width and height used to filter widgets displayed in the communal widget picker --> + <dimen name="communal_widget_picker_desired_width">360dp</dimen> + <dimen name="communal_widget_picker_desired_height">240dp</dimen> + <!-- The width/height of the unlock icon view on keyguard. --> <dimen name="keyguard_lock_height">42dp</dimen> <dimen name="keyguard_lock_padding">20dp</dimen> @@ -1101,6 +1105,7 @@ <dimen name="biometric_dialog_button_negative_max_width">160dp</dimen> <dimen name="biometric_dialog_button_positive_max_width">136dp</dimen> <dimen name="biometric_dialog_corner_size">28dp</dimen> + <dimen name="biometric_dialog_indicator_max_width">280dp</dimen> <!-- Y translation when showing/dismissing the dialog--> <dimen name="biometric_dialog_animation_translation_offset">350dp</dimen> <dimen name="biometric_dialog_border_padding">4dp</dimen> @@ -1117,9 +1122,7 @@ <dimen name="biometric_prompt_panel_max_width">640dp</dimen> <dimen name="biometric_prompt_land_small_horizontal_guideline_padding">344dp</dimen> <dimen name="biometric_prompt_two_pane_udfps_horizontal_guideline_padding">114dp</dimen> - <dimen name="biometric_prompt_two_pane_udfps_mid_guideline_padding">409dp</dimen> <dimen name="biometric_prompt_two_pane_medium_horizontal_guideline_padding">640dp</dimen> - <dimen name="biometric_prompt_two_pane_medium_mid_guideline_padding">330dp</dimen> <dimen name="biometric_prompt_one_pane_medium_top_guideline_padding">119dp</dimen> <dimen name="biometric_prompt_one_pane_medium_horizontal_guideline_padding">0dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index effaaf2653ee..c2ca4daa5afe 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -3529,6 +3529,14 @@ use. The helper shows shortcuts in categories, which can be collapsed or expanded. [CHAR LIMIT=NONE] --> <string name="shortcut_helper_content_description_expand_icon">Expand icon</string> + <!-- Word that separates different possible key combinations of a shortcut. For example the + "Go to home screen" shortcut could be triggered using "home button" OR "ctrl + h". + This is that "or" separator. + The keyboard shortcut helper is a component that shows the user which keyboard shortcuts + they can use. + [CHAR LIMIT=NONE] + --> + <string name="shortcut_helper_key_combinations_or_separator">or</string> <!-- Content description for keyboard backlight brightness dialog [CHAR LIMIT=NONE] --> <string name="keyboard_backlight_dialog_title">Keyboard backlight</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 1e0adec4e84f..73b7586f1210 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -338,8 +338,11 @@ <item name="android:textSize">16sp</item> </style> - <style name="AuthCredentialPanelStyle"> + <style name="AuthNonCredentialPanelStyle"> <item name="android:background">?androidprv:attr/materialColorSurfaceBright</item> + </style> + + <style name="AuthCredentialPanelStyle" parent="AuthNonCredentialPanelStyle"> <item name="android:clickable">true</item> <item name="android:clipToOutline">true</item> <item name="android:importantForAccessibility">no</item> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java index c33b7ce1d002..c225cbcc6e81 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java @@ -87,10 +87,15 @@ public class PipSurfaceTransactionHelper { mTmpDestinationRect.inset(insets); // Scale to the bounds no smaller than the destination and offset such that the top/left // of the scaled inset source rect aligns with the top/left of the destination bounds - final float scale; + final float scale, left, top; if (sourceRectHint.isEmpty() || sourceRectHint.width() == sourceBounds.width()) { scale = Math.max((float) destinationBounds.width() / sourceBounds.width(), (float) destinationBounds.height() / sourceBounds.height()); + // Work around the rounding error by fix the position at very beginning. + left = scale == 1 + ? 0 : destinationBounds.left - (insets.left + sourceBounds.left) * scale; + top = scale == 1 + ? 0 : destinationBounds.top - (insets.top + sourceBounds.top) * scale; } else { // scale by sourceRectHint if it's not edge-to-edge final float endScale = sourceRectHint.width() <= sourceRectHint.height() @@ -100,9 +105,9 @@ public class PipSurfaceTransactionHelper { ? (float) destinationBounds.width() / sourceBounds.width() : (float) destinationBounds.height() / sourceBounds.height(); scale = Math.min((1 - progress) * startScale + progress * endScale, 1.0f); + left = destinationBounds.left - (insets.left + sourceBounds.left) * scale; + top = destinationBounds.top - (insets.top + sourceBounds.top) * scale; } - final float left = destinationBounds.left - (insets.left + sourceBounds.left) * scale; - final float top = destinationBounds.top - (insets.top + sourceBounds.top) * scale; mTmpTransform.setScale(scale, scale); final float cornerRadius = getScaledCornerRadius(mTmpDestinationRect, destinationBounds); tx.setMatrix(leash, mTmpTransform, mTmpFloat9) diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.kt index dcf7754221bb..757760f63c0f 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.kt @@ -70,10 +70,10 @@ data class ThumbnailData( @JvmStatic fun wrap(taskIds: IntArray?, snapshots: Array<TaskSnapshot>?): HashMap<Int, ThumbnailData> { - return if (taskIds == null || snapshots == null || taskIds.size != snapshots.size) { - HashMap() - } else { - HashMap(taskIds.associateWith { taskId -> fromSnapshot(snapshots[taskId]) }) + return hashMapOf<Int, ThumbnailData>().apply { + if (taskIds != null && snapshots != null && taskIds.size == snapshots.size) { + repeat(snapshots.size) { put(taskIds[it], fromSnapshot(snapshots[it])) } + } } } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java index b4377eae4d1f..c0c8b755108c 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java @@ -122,6 +122,8 @@ public class QuickStepContract { public static final long SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY = 1L << 31; // Physical keyboard shortcuts helper is showing public static final long SYSUI_STATE_SHORTCUT_HELPER_SHOWING = 1L << 32; + // Touchpad gestures are disabled + public static final long SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED = 1L << 33; // Mask for SystemUiStateFlags to isolate SYSUI_STATE_AWAKE and // SYSUI_STATE_WAKEFULNESS_TRANSITION, to match WAKEFULNESS_* constants @@ -170,6 +172,7 @@ public class QuickStepContract { SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE, SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY, SYSUI_STATE_SHORTCUT_HELPER_SHOWING, + SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED, }) public @interface SystemUiStateFlags {} @@ -271,6 +274,9 @@ public class QuickStepContract { if ((flags & SYSUI_STATE_SHORTCUT_HELPER_SHOWING) != 0) { str.add("shortcut_helper_showing"); } + if ((flags & SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED) != 0) { + str.add("touchpad_gestures_disabled"); + } return str.toString(); } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesChecker.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesChecker.java new file mode 100644 index 000000000000..2d1cd03aea4d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesChecker.java @@ -0,0 +1,108 @@ +/* + * 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.accessibility.hearingaid; + +import android.bluetooth.BluetoothDevice; +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.WorkerThread; + +import com.android.settingslib.bluetooth.BluetoothUtils; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.systemui.dagger.SysUISingleton; + +import javax.inject.Inject; + +/** + * HearingDevicesChecker provides utility methods to determine the presence and status of + * connected hearing aid devices. + * + * <p>It also filters out devices that are exclusively managed by other applications to avoid + * interfering with their operation. + */ +@SysUISingleton +public class HearingDevicesChecker { + + private final Context mContext; + private final LocalBluetoothManager mLocalBluetoothManager; + + @Inject + public HearingDevicesChecker( + Context context, + @Nullable LocalBluetoothManager localBluetoothManager) { + mContext = context; + mLocalBluetoothManager = localBluetoothManager; + } + + /** + * Checks if any hearing device is already paired. + * + * <p>It includes {@link BluetoothDevice.BOND_BONDING} and {@link BluetoothDevice.BOND_BONDED}). + * + * <p>A bonded device means it has been paired, but may not connected now. + * + * @return {@code true} if any bonded hearing device is found, {@code false} otherwise. + */ + @WorkerThread + public boolean isAnyPairedHearingDevice() { + if (mLocalBluetoothManager == null) { + return false; + } + if (!mLocalBluetoothManager.getBluetoothAdapter().isEnabled()) { + return false; + } + + return mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy().stream() + .anyMatch(device -> device.isHearingAidDevice() + && device.getBondState() != BluetoothDevice.BOND_NONE + && !isExclusivelyManagedBluetoothDevice(device)); + } + + /** + * Checks if there are any active hearing device. + * + * <p>An active device means it is currently connected and streaming media. + * + * @return {@code true} if any active hearing device is found, {@code false} otherwise. + */ + @WorkerThread + public boolean isAnyActiveHearingDevice() { + if (mLocalBluetoothManager == null) { + return false; + } + if (!mLocalBluetoothManager.getBluetoothAdapter().isEnabled()) { + return false; + } + + return mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy().stream() + .anyMatch(device -> BluetoothUtils.isActiveMediaDevice(device) + && BluetoothUtils.isAvailableHearingDevice(device) + && !isExclusivelyManagedBluetoothDevice(device)); + } + + private boolean isExclusivelyManagedBluetoothDevice( + @NonNull CachedBluetoothDevice cachedDevice) { + if (com.android.settingslib.flags.Flags.enableHideExclusivelyManagedBluetoothDevice()) { + return BluetoothUtils.isExclusivelyManagedBluetoothDevice(mContext, + cachedDevice.getDevice()); + } + return false; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManager.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManager.java index 14e5f3422a27..bc4cb45582ff 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManager.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManager.java @@ -16,19 +16,24 @@ package com.android.systemui.accessibility.hearingaid; -import android.bluetooth.BluetoothDevice; import android.util.Log; -import androidx.annotation.Nullable; +import androidx.concurrent.futures.CallbackToFutureAdapter; import com.android.internal.jank.InteractionJankMonitor; -import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.systemui.animation.DialogCuj; import com.android.systemui.animation.DialogTransitionAnimator; import com.android.systemui.animation.Expandable; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.statusbar.phone.SystemUIDialog; +import com.google.common.util.concurrent.ListenableFuture; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; + import javax.inject.Inject; /** @@ -43,16 +48,22 @@ public class HearingDevicesDialogManager { private SystemUIDialog mDialog; private final DialogTransitionAnimator mDialogTransitionAnimator; private final HearingDevicesDialogDelegate.Factory mDialogFactory; - private final LocalBluetoothManager mLocalBluetoothManager; + private final HearingDevicesChecker mDevicesChecker; + private final Executor mBackgroundExecutor; + private final Executor mMainExecutor; @Inject public HearingDevicesDialogManager( DialogTransitionAnimator dialogTransitionAnimator, HearingDevicesDialogDelegate.Factory dialogFactory, - @Nullable LocalBluetoothManager localBluetoothManager) { + HearingDevicesChecker devicesChecker, + @Background Executor backgroundExecutor, + @Main Executor mainExecutor) { mDialogTransitionAnimator = dialogTransitionAnimator; mDialogFactory = dialogFactory; - mLocalBluetoothManager = localBluetoothManager; + mDevicesChecker = devicesChecker; + mBackgroundExecutor = backgroundExecutor; + mMainExecutor = mainExecutor; } /** @@ -68,36 +79,41 @@ public class HearingDevicesDialogManager { destroyDialog(); } - mDialog = mDialogFactory.create(!isAnyBondedHearingDevice()).createDialog(); + final ListenableFuture<Boolean> pairedHearingDeviceCheckTask = + CallbackToFutureAdapter.getFuture(completer -> { + mBackgroundExecutor.execute( + () -> { + completer.set(mDevicesChecker.isAnyPairedHearingDevice()); + }); + // This value is used only for debug purposes: it will be used in toString() + // of returned future or error cases. + return "isAnyPairedHearingDevice check"; + }); + pairedHearingDeviceCheckTask.addListener(() -> { + try { + mDialog = mDialogFactory.create(!pairedHearingDeviceCheckTask.get()).createDialog(); + + if (expandable != null) { + DialogTransitionAnimator.Controller controller = + expandable.dialogTransitionController( + new DialogCuj(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, + INTERACTION_JANK_TAG)); + if (controller != null) { + mDialogTransitionAnimator.show(mDialog, + controller, /* animateBackgroundBoundsChange= */ true); + return; + } + } + mDialog.show(); - if (expandable != null) { - DialogTransitionAnimator.Controller controller = expandable.dialogTransitionController( - new DialogCuj(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, - INTERACTION_JANK_TAG)); - if (controller != null) { - mDialogTransitionAnimator.show(mDialog, - controller, /* animateBackgroundBoundsChange= */ true); - return; + } catch (InterruptedException | ExecutionException e) { + Log.e(TAG, "Exception occurs while running pairedHearingDeviceCheckTask", e); } - } - mDialog.show(); + }, mMainExecutor); } private void destroyDialog() { mDialog.dismiss(); mDialog = null; } - - private boolean isAnyBondedHearingDevice() { - if (mLocalBluetoothManager == null) { - return false; - } - if (!mLocalBluetoothManager.getBluetoothAdapter().isEnabled()) { - return false; - } - - return mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy().stream() - .anyMatch(device -> device.isHearingAidDevice() - && device.getBondState() != BluetoothDevice.BOND_NONE); - } } diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/ShadeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/ambient/touch/ShadeTouchHandler.java index 9ef9938ab8ad..fcd7ef53d42a 100644 --- a/packages/SystemUI/src/com/android/systemui/ambient/touch/ShadeTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/ShadeTouchHandler.java @@ -18,11 +18,15 @@ package com.android.systemui.ambient.touch; import static com.android.systemui.ambient.touch.dagger.ShadeModule.NOTIFICATION_SHADE_GESTURE_INITIATION_HEIGHT; +import android.app.DreamManager; import android.graphics.Rect; import android.graphics.Region; import android.view.GestureDetector; import android.view.MotionEvent; +import androidx.annotation.NonNull; + +import com.android.systemui.Flags; import com.android.systemui.shade.ShadeViewController; import com.android.systemui.statusbar.phone.CentralSurfaces; @@ -38,28 +42,39 @@ import javax.inject.Named; public class ShadeTouchHandler implements TouchHandler { private final Optional<CentralSurfaces> mSurfaces; private final ShadeViewController mShadeViewController; + private final DreamManager mDreamManager; private final int mInitiationHeight; + /** + * Tracks whether or not we are capturing a given touch. Will be null before and after a touch. + */ + private Boolean mCapture; + @Inject ShadeTouchHandler(Optional<CentralSurfaces> centralSurfaces, ShadeViewController shadeViewController, + DreamManager dreamManager, @Named(NOTIFICATION_SHADE_GESTURE_INITIATION_HEIGHT) int initiationHeight) { mSurfaces = centralSurfaces; mShadeViewController = shadeViewController; + mDreamManager = dreamManager; mInitiationHeight = initiationHeight; } @Override public void onSessionStart(TouchSession session) { - if (mSurfaces.map(CentralSurfaces::isBouncerShowing).orElse(false)) { + if (mSurfaces.isEmpty()) { session.pop(); return; } - session.registerInputListener(ev -> { - mShadeViewController.handleExternalTouch((MotionEvent) ev); + session.registerCallback(() -> mCapture = null); + session.registerInputListener(ev -> { if (ev instanceof MotionEvent) { + if (mCapture != null && mCapture) { + sendTouchEvent((MotionEvent) ev); + } if (((MotionEvent) ev).getAction() == MotionEvent.ACTION_UP) { session.pop(); } @@ -68,19 +83,41 @@ public class ShadeTouchHandler implements TouchHandler { session.registerGestureListener(new GestureDetector.SimpleOnGestureListener() { @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, + public boolean onScroll(MotionEvent e1, @NonNull MotionEvent e2, float distanceX, float distanceY) { - return true; + if (mCapture == null) { + // Only capture swipes that are going downwards. + mCapture = Math.abs(distanceY) > Math.abs(distanceX) && distanceY < 0; + if (mCapture) { + // Send the initial touches over, as the input listener has already + // processed these touches. + sendTouchEvent(e1); + sendTouchEvent(e2); + } + } + return mCapture; } @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, + public boolean onFling(MotionEvent e1, @NonNull MotionEvent e2, float velocityX, float velocityY) { - return true; + return mCapture; } }); } + private void sendTouchEvent(MotionEvent event) { + if (Flags.communalHub() && !mDreamManager.isDreaming()) { + // Send touches to central surfaces only when on the glanceable hub while not dreaming. + // While sending touches where while dreaming will open the shade, the shade + // while closing if opened then closed in the same gesture. + mSurfaces.get().handleExternalShadeWindowTouch(event); + } else { + // Send touches to the shade view when dreaming. + mShadeViewController.handleExternalTouch(event); + } + } + @Override public void getTouchInitiationRegion(Rect bounds, Region region, Rect exclusionRect) { final Rect outBounds = new Rect(bounds); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index 1ee4908437a6..430ff0716ee0 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -515,7 +515,9 @@ public class AuthContainerView extends LinearLayout } else { throw new IllegalStateException("Unknown credential type: " + credentialType); } - mCredentialView = factory.inflate(layoutResourceId, null, false); + // TODO(b/288175645): Once AuthContainerView is removed, set 0dp in credential view xml + // files with the corresponding left/right or top/bottom constraints being set to "parent". + mCredentialView = factory.inflate(layoutResourceId, mLayout, false); // The background is used for detecting taps / cancelling authentication. Since the // credential view is full-screen and should not be canceled from background taps, @@ -552,8 +554,6 @@ public class AuthContainerView extends LinearLayout } mWakefulnessLifecycle.addObserver(this); - mPanelInteractionDetector.enable( - () -> animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED)); if (constraintBp()) { // Do nothing on attachment with constraintLayout } else if (mPromptViewModel.getPromptKind().getValue().isBiometric()) { @@ -566,6 +566,8 @@ public class AuthContainerView extends LinearLayout } if (!constraintBp()) { + mPanelInteractionDetector.enable( + () -> animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED)); updatePositionByCapability(false /* invalidate */); } @@ -977,7 +979,7 @@ public class AuthContainerView extends LinearLayout final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG, + WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, windowFlags, PixelFormat.TRANSLUCENT); lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index fb718d3412e3..85b5faf2d556 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -34,6 +34,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.graphics.Rect; import android.hardware.biometrics.BiometricFingerprintConstants; +import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.SensorProperties; import android.hardware.display.DisplayManager; import android.hardware.fingerprint.FingerprintManager; @@ -43,7 +44,9 @@ import android.hardware.fingerprint.IUdfpsOverlayController; import android.hardware.fingerprint.IUdfpsOverlayControllerCallback; import android.hardware.input.InputManager; import android.os.Build; +import android.os.CancellationSignal; import android.os.Handler; +import android.os.Looper; import android.os.PowerManager; import android.os.Trace; import android.os.VibrationAttributes; @@ -382,6 +385,26 @@ public class UdfpsController implements DozeReceiver, Dumpable { UdfpsController.this.mFingerprintManager.onUdfpsUiEvent( FingerprintManager.UDFPS_UI_READY, requestId, sensorId); } + + /** + * Debug to show biometric prompt + */ + public void debugBiometricPrompt() { + final BiometricPrompt.AuthenticationCallback authenticationCallback = + new BiometricPrompt.AuthenticationCallback() { + }; + + final BiometricPrompt biometricPrompt = new BiometricPrompt.Builder(mContext) + .setTitle("Test") + .setDeviceCredentialAllowed(true) + .setAllowBackgroundAuthentication(true) + .build(); + final Handler handler = new Handler(Looper.getMainLooper()); + biometricPrompt.authenticate( + new CancellationSignal(), + handler::post, + authenticationCallback); + } } /** diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt index 88b9e1bdfd97..f5e3d29cb878 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt @@ -45,16 +45,13 @@ private const val SENSOR_ID = 0 private const val MINOR = 10F private const val MAJOR = 10F -/** - * Used to show and hide the UDFPS overlay with statusbar commands. - */ +/** Used to show and hide the UDFPS overlay with statusbar commands. */ @SysUISingleton -class UdfpsShell @Inject constructor( - commandRegistry: CommandRegistry -) : Command { +class UdfpsShell @Inject constructor(commandRegistry: CommandRegistry) : Command { /** * Set in [UdfpsController.java] constructor, used to show and hide the UDFPS overlay. + * * TODO: inject after b/229290039 is resolved */ var udfpsOverlayController: UdfpsController.UdfpsOverlayController? = null @@ -76,6 +73,8 @@ class UdfpsShell @Inject constructor( simFingerDown() } else if (args.size == 1 && args[0] == "simFingerUp") { simFingerUp() + } else if (args.size == 1 && args[0] == "biometricPrompt") { + launchBiometricPrompt() } else { invalidCommand(pw) } @@ -85,8 +84,10 @@ class UdfpsShell @Inject constructor( pw.println("Usage: adb shell cmd statusbar udfps <cmd>") pw.println("Supported commands:") pw.println(" - show <reason>") - pw.println(" -> supported reasons: [enroll-find-sensor, enroll-enrolling, auth-bp, " + - "auth-keyguard, auth-other, auth-settings]") + pw.println( + " -> supported reasons: [enroll-find-sensor, enroll-enrolling, auth-bp, " + + "auth-keyguard, auth-other, auth-settings]" + ) pw.println(" -> reason otherwise defaults to unknown") pw.println(" - hide") pw.println(" - onUiReady") @@ -94,6 +95,8 @@ class UdfpsShell @Inject constructor( pw.println(" -> Simulates onFingerDown on sensor") pw.println(" - simFingerUp") pw.println(" -> Simulates onFingerUp on sensor") + pw.println(" - biometricPrompt") + pw.println(" -> Shows Biometric Prompt") } private fun invalidCommand(pw: PrintWriter) { @@ -115,14 +118,14 @@ class UdfpsShell @Inject constructor( private fun showOverlay(reason: Int) { udfpsOverlayController?.showUdfpsOverlay( - REQUEST_ID, - SENSOR_ID, - reason, - object : IUdfpsOverlayControllerCallback.Stub() { - override fun onUserCanceled() { - Log.e(TAG, "User cancelled") - } + REQUEST_ID, + SENSOR_ID, + reason, + object : IUdfpsOverlayControllerCallback.Stub() { + override fun onUserCanceled() { + Log.e(TAG, "User cancelled") } + } ) } @@ -130,6 +133,9 @@ class UdfpsShell @Inject constructor( udfpsOverlayController?.hideUdfpsOverlay(SENSOR_ID) } + private fun launchBiometricPrompt() { + udfpsOverlayController?.debugBiometricPrompt() + } @VisibleForTesting fun onUiReady() { @@ -140,12 +146,24 @@ class UdfpsShell @Inject constructor( fun simFingerDown() { val sensorBounds: Rect = udfpsOverlayController!!.sensorBounds - val downEvent: MotionEvent? = obtainMotionEvent(ACTION_DOWN, sensorBounds.exactCenterX(), - sensorBounds.exactCenterY(), MINOR, MAJOR) + val downEvent: MotionEvent? = + obtainMotionEvent( + ACTION_DOWN, + sensorBounds.exactCenterX(), + sensorBounds.exactCenterY(), + MINOR, + MAJOR + ) udfpsOverlayController?.debugOnTouch(downEvent) - val moveEvent: MotionEvent? = obtainMotionEvent(ACTION_MOVE, sensorBounds.exactCenterX(), - sensorBounds.exactCenterY(), MINOR, MAJOR) + val moveEvent: MotionEvent? = + obtainMotionEvent( + ACTION_MOVE, + sensorBounds.exactCenterX(), + sensorBounds.exactCenterY(), + MINOR, + MAJOR + ) udfpsOverlayController?.debugOnTouch(moveEvent) downEvent?.recycle() @@ -156,18 +174,24 @@ class UdfpsShell @Inject constructor( fun simFingerUp() { val sensorBounds: Rect = udfpsOverlayController!!.sensorBounds - val upEvent: MotionEvent? = obtainMotionEvent(ACTION_UP, sensorBounds.exactCenterX(), - sensorBounds.exactCenterY(), MINOR, MAJOR) + val upEvent: MotionEvent? = + obtainMotionEvent( + ACTION_UP, + sensorBounds.exactCenterX(), + sensorBounds.exactCenterY(), + MINOR, + MAJOR + ) udfpsOverlayController?.debugOnTouch(upEvent) upEvent?.recycle() } private fun obtainMotionEvent( - action: Int, - x: Float, - y: Float, - minor: Float, - major: Float + action: Int, + x: Float, + y: Float, + minor: Float, + major: Float ): MotionEvent? { val pp = MotionEvent.PointerProperties() pp.id = 1 @@ -176,7 +200,21 @@ class UdfpsShell @Inject constructor( pc.y = y pc.touchMinor = minor pc.touchMajor = major - return MotionEvent.obtain(0, 0, action, 1, arrayOf(pp), arrayOf(pc), - 0, 0, 1f, 1f, 0, 0, 0, 0) + return MotionEvent.obtain( + 0, + 0, + action, + 1, + arrayOf(pp), + arrayOf(pc), + 0, + 0, + 1f, + 1f, + 0, + 0, + 0, + 0 + ) } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt index c836f89a8ff4..628b5331d52e 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt @@ -367,21 +367,21 @@ object BiometricViewSizeBinder { smallConstraintSet.setGuidelineEnd(topGuideline.id, abs(bounds.top)) } - // Use rect bottom to set mid guideline of two-pane. if (midGuideline != null) { - if (bounds.bottom >= 0) { - midGuideline.setGuidelineEnd(bounds.bottom) - mediumConstraintSet.setGuidelineEnd( - midGuideline.id, - bounds.bottom - ) - } else if (bounds.bottom < 0) { - midGuideline.setGuidelineBegin(abs(bounds.bottom)) - mediumConstraintSet.setGuidelineBegin( - midGuideline.id, - abs(bounds.bottom) - ) - } + val left = + if (bounds.left >= 0) { + bounds.left + } else { + view.width - abs(bounds.left) + } + val right = + if (bounds.right >= 0) { + view.width - abs(bounds.right) + } else { + bounds.right + } + val mid = (left + right) / 2 + mediumConstraintSet.setGuidelineBegin(midGuideline.id, mid) } } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt index c17b83dd4fbe..a39a74f5ef83 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt @@ -306,10 +306,6 @@ constructor( context.resources.getDimensionPixelSize( R.dimen.biometric_prompt_two_pane_udfps_horizontal_guideline_padding ) - private val udfpsMidGuidelinePadding = - context.resources.getDimensionPixelSize( - R.dimen.biometric_prompt_two_pane_udfps_mid_guideline_padding - ) private val mediumTopGuidelinePadding = context.resources.getDimensionPixelSize( R.dimen.biometric_prompt_one_pane_medium_top_guideline_padding @@ -318,10 +314,6 @@ constructor( context.resources.getDimensionPixelSize( R.dimen.biometric_prompt_two_pane_medium_horizontal_guideline_padding ) - private val mediumMidGuidelinePadding = - context.resources.getDimensionPixelSize( - R.dimen.biometric_prompt_two_pane_medium_mid_guideline_padding - ) /** Rect for positioning biometric icon */ val iconPosition: Flow<Rect> = @@ -449,7 +441,7 @@ constructor( } /** - * Rect for positioning prompt guidelines (left, top, right, mid) + * Rect for positioning prompt guidelines (left, top, right, unused) * * Negative values are used to signify that guideline measuring should be flipped, measuring * from opposite side of the screen @@ -472,22 +464,17 @@ constructor( if (size.isSmall) { Rect(-smallHorizontalGuidelinePadding, 0, 0, 0) } else if (modalities.hasUdfps) { - Rect(udfpsHorizontalGuidelinePadding, 0, 0, udfpsMidGuidelinePadding) + Rect(udfpsHorizontalGuidelinePadding, 0, 0, 0) } else { - Rect(-mediumHorizontalGuidelinePadding, 0, 0, mediumMidGuidelinePadding) + Rect(-mediumHorizontalGuidelinePadding, 0, 0, 0) } PromptPosition.Left -> if (size.isSmall) { Rect(0, 0, -smallHorizontalGuidelinePadding, 0) } else if (modalities.hasUdfps) { - Rect(0, 0, udfpsHorizontalGuidelinePadding, -udfpsMidGuidelinePadding) + Rect(0, 0, udfpsHorizontalGuidelinePadding, 0) } else { - Rect( - 0, - 0, - -mediumHorizontalGuidelinePadding, - -mediumMidGuidelinePadding - ) + Rect(0, 0, -mediumHorizontalGuidelinePadding, 0) } PromptPosition.Top -> Rect() } diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt index 2be28caa71a9..fdb40fb01d79 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt @@ -98,7 +98,7 @@ constructor( broadcastDispatcher: BroadcastDispatcher, private val widgetRepository: CommunalWidgetRepository, private val communalPrefsRepository: CommunalPrefsRepository, - mediaRepository: CommunalMediaRepository, + private val mediaRepository: CommunalMediaRepository, smartspaceRepository: SmartspaceRepository, keyguardInteractor: KeyguardInteractor, keyguardTransitionInteractor: KeyguardTransitionInteractor, @@ -479,40 +479,41 @@ constructor( * A flow of ongoing content, including smartspace timers and umo, ordered by creation time and * sized dynamically. */ - val ongoingContent: Flow<List<CommunalContentModel.Ongoing>> = + fun getOngoingContent(mediaHostVisible: Boolean): Flow<List<CommunalContentModel.Ongoing>> = combine(smartspaceTargets, mediaRepository.mediaModel) { smartspace, media -> - val ongoingContent = mutableListOf<CommunalContentModel.Ongoing>() - - // Add smartspace - ongoingContent.addAll( - smartspace.map { target -> - CommunalContentModel.Smartspace( - smartspaceTargetId = target.smartspaceTargetId, - remoteViews = target.remoteViews!!, - createdTimestampMillis = target.creationTimeMillis, + val ongoingContent = mutableListOf<CommunalContentModel.Ongoing>() + + // Add smartspace + ongoingContent.addAll( + smartspace.map { target -> + CommunalContentModel.Smartspace( + smartspaceTargetId = target.smartspaceTargetId, + remoteViews = target.remoteViews!!, + createdTimestampMillis = target.creationTimeMillis, + ) + } + ) + + // Add UMO + if (mediaHostVisible && media.hasActiveMediaOrRecommendation) { + ongoingContent.add( + CommunalContentModel.Umo( + createdTimestampMillis = media.createdTimestampMillis, + ) ) } - ) - // Add UMO - if (media.hasActiveMediaOrRecommendation) { - ongoingContent.add( - CommunalContentModel.Umo( - createdTimestampMillis = media.createdTimestampMillis, - ) - ) - } + // Order by creation time descending + ongoingContent.sortByDescending { it.createdTimestampMillis } - // Order by creation time descending - ongoingContent.sortByDescending { it.createdTimestampMillis } + // Dynamic sizing + ongoingContent.forEachIndexed { index, model -> + model.size = dynamicContentSize(ongoingContent.size, index) + } - // Dynamic sizing - ongoingContent.forEachIndexed { index, model -> - model.size = dynamicContentSize(ongoingContent.size, index) + ongoingContent } - - return@combine ongoingContent - } + .flowOn(bgDispatcher) /** * Filter and retain widgets associated with an existing user, safeguarding against displaying diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalBackgroundType.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalBackgroundType.kt index 8b816db53970..4eaba065e078 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalBackgroundType.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalBackgroundType.kt @@ -21,4 +21,5 @@ enum class CommunalBackgroundType(val value: Int) { DEFAULT(0), STATIC_GRADIENT(1), ANIMATED(2), + NONE(3), } diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt index bc65ccb9ed5a..5312aec16b1b 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt @@ -24,6 +24,7 @@ import android.content.res.Resources import android.util.Log import androidx.activity.result.ActivityResultLauncher import com.android.internal.logging.UiEventLogger +import com.android.systemui.Flags.enableWidgetPickerSizeFilter import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor @@ -36,6 +37,7 @@ import com.android.systemui.log.core.Logger import com.android.systemui.log.dagger.CommunalLog import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.media.dagger.MediaModule +import com.android.systemui.res.R import javax.inject.Inject import javax.inject.Named import kotlinx.coroutines.CoroutineDispatcher @@ -138,6 +140,16 @@ constructor( return Intent(Intent.ACTION_PICK).apply { setPackage(packageName) + if (enableWidgetPickerSizeFilter()) { + putExtra( + EXTRA_DESIRED_WIDGET_WIDTH, + resources.getDimensionPixelSize(R.dimen.communal_widget_picker_desired_width) + ) + putExtra( + EXTRA_DESIRED_WIDGET_HEIGHT, + resources.getDimensionPixelSize(R.dimen.communal_widget_picker_desired_height) + ) + } putExtra( AppWidgetManager.EXTRA_CATEGORY_FILTER, communalSettingsInteractor.communalWidgetCategories.value @@ -163,6 +175,8 @@ constructor( companion object { private const val TAG = "CommunalEditModeViewModel" + private const val EXTRA_DESIRED_WIDGET_WIDTH = "desired_widget_width" + private const val EXTRA_DESIRED_WIDGET_HEIGHT = "desired_widget_height" private const val EXTRA_UI_SURFACE_KEY = "ui_surface" private const val EXTRA_UI_SURFACE_VALUE = "widgets_hub" const val EXTRA_ADDED_APP_WIDGETS_KEY = "added_app_widgets" diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt index 3e00b0455575..c6fa5a84c195 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt @@ -42,12 +42,15 @@ import com.android.systemui.res.R import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf import com.android.systemui.util.kotlin.BooleanFlowOperators.not +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated import javax.inject.Inject import javax.inject.Named +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job +import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -56,8 +59,10 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch /** The default view model used for showing the communal hub. */ @@ -66,6 +71,7 @@ import kotlinx.coroutines.launch class CommunalViewModel @Inject constructor( + @Main val mainDispatcher: CoroutineDispatcher, @Application private val scope: CoroutineScope, @Main private val resources: Resources, keyguardTransitionInteractor: KeyguardTransitionInteractor, @@ -79,6 +85,18 @@ constructor( @CommunalLog logBuffer: LogBuffer, ) : BaseCommunalViewModel(communalSceneInteractor, communalInteractor, mediaHost) { + private val _isMediaHostVisible = + conflatedCallbackFlow<Boolean> { + val callback = { visible: Boolean -> + trySend(visible) + Unit + } + mediaHost.addVisibilityChangeListener(callback) + awaitClose { mediaHost.removeVisibilityChangeListener(callback) } + } + .onStart { emit(mediaHost.visible) } + .flowOn(mainDispatcher) + private val logger = Logger(logBuffer, "CommunalViewModel") /** Communal content saved from the previous emission when the flow is active (not "frozen"). */ @@ -91,8 +109,10 @@ constructor( if (isTutorialMode) { return@flatMapLatest flowOf(communalInteractor.tutorialContent) } + val ongoingContent = + _isMediaHostVisible.flatMapLatest { communalInteractor.getOngoingContent(it) } combine( - communalInteractor.ongoingContent, + ongoingContent, communalInteractor.widgetContent, communalInteractor.ctaTileContent, ) { ongoing, widgets, ctaTile, diff --git a/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java b/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java index e284bc7752cf..92108e9e7103 100644 --- a/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java +++ b/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java @@ -36,7 +36,6 @@ import androidx.annotation.Nullable; import com.android.internal.logging.UiEventLogger; import com.android.settingslib.Utils; import com.android.systemui.CoreStartable; -import com.android.systemui.Flags; import com.android.systemui.animation.ActivityTransitionAnimator; import com.android.systemui.complication.dagger.DreamHomeControlsComplicationComponent; import com.android.systemui.controls.ControlsServiceInfo; @@ -137,9 +136,7 @@ public class DreamHomeControlsComplication implements Complication { private void updateHomeControlsComplication() { mControlsComponent.getControlsListingController().ifPresent(c -> { - final boolean replacedWithOpenHub = - Flags.glanceableHubShortcutButton() && mReplacedByOpenHub; - if (isHomeControlsAvailable(c.getCurrentServices()) && !replacedWithOpenHub) { + if (isHomeControlsAvailable(c.getCurrentServices())) { mDreamOverlayStateController.addComplication(mComplication); } else { mDreamOverlayStateController.removeComplication(mComplication); diff --git a/packages/SystemUI/src/com/android/systemui/complication/OpenHubComplication.java b/packages/SystemUI/src/com/android/systemui/complication/OpenHubComplication.java index a679bfb15476..05df2bb4aa59 100644 --- a/packages/SystemUI/src/com/android/systemui/complication/OpenHubComplication.java +++ b/packages/SystemUI/src/com/android/systemui/complication/OpenHubComplication.java @@ -28,7 +28,6 @@ import android.widget.ImageView; import com.android.settingslib.Utils; import com.android.systemui.CoreStartable; -import com.android.systemui.Flags; import com.android.systemui.communal.domain.interactor.CommunalInteractor; import com.android.systemui.communal.shared.model.CommunalScenes; import com.android.systemui.complication.dagger.OpenHubComplicationComponent; @@ -111,11 +110,11 @@ public class OpenHubComplication implements Complication { private void updateOpenHubComplication() { // TODO(b/339667383): don't show the complication if glanceable hub is disabled - if (Flags.glanceableHubShortcutButton()) { - mDreamOverlayStateController.addComplication(mComplication); - } else { - mDreamOverlayStateController.removeComplication(mComplication); - } +// if (Flags.glanceableHubShortcutButton()) { +// mDreamOverlayStateController.addComplication(mComplication); +// } else { +// mDreamOverlayStateController.removeComplication(mComplication); +// } } } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java index c2e1e33f5318..2fbb75ec720a 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java @@ -29,6 +29,7 @@ import com.android.systemui.screenshot.scroll.LongScreenshotActivity; import com.android.systemui.sensorprivacy.SensorUseStartedActivity; import com.android.systemui.settings.brightness.BrightnessDialog; import com.android.systemui.telephony.ui.activity.SwitchToManagedProfileForCallActivity; +import com.android.systemui.touchpad.tutorial.ui.view.TouchpadTutorialActivity; import com.android.systemui.tuner.TunerActivity; import com.android.systemui.usb.UsbAccessoryUriActivity; import com.android.systemui.usb.UsbConfirmActivity; @@ -156,4 +157,10 @@ public abstract class DefaultActivityBinder { @ClassKey(SwitchToManagedProfileForCallActivity.class) public abstract Activity bindSwitchToManagedProfileForCallActivity( SwitchToManagedProfileForCallActivity activity); + + /** Inject into TouchpadTutorialActivity. */ + @Binds + @IntoMap + @ClassKey(TouchpadTutorialActivity.class) + public abstract Activity bindTouchpadTutorialActivity(TouchpadTutorialActivity activity); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java index 7aab37e12b8c..9f0fc51abdd2 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java @@ -31,6 +31,7 @@ import com.android.systemui.display.ui.viewmodel.ConnectingDisplayViewModel; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerImpl; import com.android.systemui.doze.DozeHost; +import com.android.systemui.keyboard.shortcut.ShortcutHelperModule; import com.android.systemui.keyguard.ui.composable.blueprint.DefaultBlueprintModule; import com.android.systemui.keyguard.ui.view.layout.blueprints.KeyguardBlueprintModule; import com.android.systemui.keyguard.ui.view.layout.sections.KeyguardSectionsModule; @@ -137,7 +138,8 @@ import javax.inject.Named; UnfoldTransitionModule.Startables.class, ToastModule.class, VolumeModule.class, - WallpaperModule.class + WallpaperModule.class, + ShortcutHelperModule.class, }) public abstract class ReferenceSystemUIModule { diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 93111874c69b..4a9f741494f4 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -40,6 +40,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.InstanceId; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; +import com.android.systemui.Flags; import com.android.systemui.biometrics.AuthController; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dock.DockManager; @@ -564,6 +565,12 @@ public class DozeTriggers implements DozeMachine.Part { return; } + // When already in pulsing, we can show the new Notification without requesting a new pulse. + if (Flags.notificationPulsingFix() + && dozeState == State.DOZE_PULSING && reason == DozeLog.PULSE_REASON_NOTIFICATION) { + return; + } + if (!mAllowPulseTriggers || mDozeHost.isPulsePending() || !canPulse(dozeState, performedProxCheck)) { if (!mAllowPulseTriggers) { diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java index 95012a2643a5..1a06418065a2 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java @@ -18,6 +18,7 @@ package com.android.systemui.doze; import static com.android.systemui.doze.DozeMachine.State.DOZE; import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED; +import static com.android.systemui.Flags.dozeuiSchedulingAlarmsBackgroundExecution; import android.app.AlarmManager; import android.content.Context; @@ -70,6 +71,7 @@ public class DozeUi implements DozeMachine.Part { @Inject public DozeUi(Context context, AlarmManager alarmManager, WakeLock wakeLock, DozeHost host, @Main Handler handler, + @Background Handler bgHandler, DozeParameters params, @Background DelayableExecutor bgExecutor, DozeLog dozeLog) { @@ -80,7 +82,13 @@ public class DozeUi implements DozeMachine.Part { mBgExecutor = bgExecutor; mCanAnimateTransition = !params.getDisplayNeedsBlanking(); mDozeParameters = params; - mTimeTicker = new AlarmTimeout(alarmManager, this::onTimeTick, "doze_time_tick", handler); + if (dozeuiSchedulingAlarmsBackgroundExecution()) { + mTimeTicker = new AlarmTimeout(alarmManager, this::onTimeTick, "doze_time_tick", + bgHandler); + } else { + mTimeTicker = new AlarmTimeout(alarmManager, this::onTimeTick, "doze_time_tick", + handler); + } mDozeLog = dozeLog; } diff --git a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt index 30b958393b60..ea8d7d778851 100644 --- a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt +++ b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt @@ -19,9 +19,7 @@ package com.android.systemui.haptics.qs import android.os.VibrationEffect import android.view.View import androidx.annotation.VisibleForTesting -import com.android.systemui.animation.Expandable import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor -import com.android.systemui.plugins.qs.QSTile import com.android.systemui.statusbar.VibratorHelper import javax.inject.Inject import kotlinx.coroutines.flow.Flow @@ -53,10 +51,6 @@ constructor( var state = State.IDLE private set - /** The QSTile and Expandable used to perform a long-click and click actions */ - var qsTile: QSTile? = null - var expandable: Expandable? = null - /** Flow for view control and action */ private val _postedActionType = MutableStateFlow<ActionType?>(null) val actionType: Flow<ActionType?> = @@ -111,7 +105,6 @@ constructor( when (state) { State.IDLE -> { setState(State.TIMEOUT_WAIT) - _postedActionType.value = ActionType.WAIT_TAP_TIMEOUT } State.RUNNING_BACKWARDS -> _postedActionType.value = ActionType.CANCEL_ANIMATOR else -> {} @@ -119,9 +112,16 @@ constructor( } fun handleActionUp() { - if (state == State.RUNNING_FORWARD) { - _postedActionType.value = ActionType.REVERSE_ANIMATOR - setState(State.RUNNING_BACKWARDS) + when (state) { + State.TIMEOUT_WAIT -> { + _postedActionType.value = ActionType.CLICK + setState(State.IDLE) + } + State.RUNNING_FORWARD -> { + _postedActionType.value = ActionType.REVERSE_ANIMATOR + setState(State.RUNNING_BACKWARDS) + } + else -> {} } } @@ -129,7 +129,6 @@ constructor( when (state) { State.TIMEOUT_WAIT -> { setState(State.IDLE) - clearActionType() } State.RUNNING_FORWARD -> { _postedActionType.value = ActionType.REVERSE_ANIMATOR @@ -146,23 +145,18 @@ constructor( /** This function is called both when an animator completes or gets cancelled */ fun handleAnimationComplete() { - when (state) { - State.RUNNING_FORWARD -> { - setState(State.IDLE) - vibrate(snapEffect) - _postedActionType.value = ActionType.LONG_PRESS - } - State.RUNNING_BACKWARDS -> { - setState(State.IDLE) - clearActionType() - } - else -> {} + if (state == State.RUNNING_FORWARD) { + vibrate(snapEffect) + _postedActionType.value = ActionType.LONG_PRESS + } + if (state != State.TIMEOUT_WAIT) { + // This will happen if the animator did not finish by being cancelled + setState(State.IDLE) } } fun handleAnimationCancel() { setState(State.TIMEOUT_WAIT) - _postedActionType.value = ActionType.WAIT_TAP_TIMEOUT } fun handleTimeoutComplete() { @@ -196,22 +190,9 @@ constructor( effectDuration ) setState(State.IDLE) - clearActionType() return true } - fun onTileClick(): Boolean { - if (state == State.TIMEOUT_WAIT) { - setState(State.IDLE) - clearActionType() - qsTile?.let { - it.click(expandable) - return true - } - } - return false - } - enum class State { IDLE, /* The effect is idle waiting for touch input */ TIMEOUT_WAIT, /* The effect is waiting for a [PRESSED_TIMEOUT] period */ @@ -221,7 +202,7 @@ constructor( /* A type of action to perform on the view depending on the effect's state and logic */ enum class ActionType { - WAIT_TAP_TIMEOUT, + CLICK, LONG_PRESS, RESET_AND_LONG_PRESS, START_ANIMATOR, diff --git a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt index 92a55ef0e74f..4875f481cce6 100644 --- a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt @@ -17,6 +17,8 @@ package com.android.systemui.haptics.qs import android.animation.ValueAnimator +import android.annotation.SuppressLint +import android.view.MotionEvent import android.view.ViewConfiguration import android.view.animation.AccelerateDecelerateInterpolator import androidx.core.animation.doOnCancel @@ -28,7 +30,6 @@ import com.android.app.tracing.coroutines.launch import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.qs.tileimpl.QSTileViewImpl import kotlinx.coroutines.DisposableHandle -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.filterNotNull object QSLongPressEffectViewBinder { @@ -40,6 +41,9 @@ object QSLongPressEffectViewBinder { ): DisposableHandle? { if (qsLongPressEffect == null) return null + // Set the touch listener as the long-press effect + setTouchListener(tile, qsLongPressEffect) + return tile.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) { // Action to perform @@ -48,18 +52,18 @@ object QSLongPressEffectViewBinder { qsLongPressEffect.actionType.filterNotNull().collect { action -> when (action) { - QSLongPressEffect.ActionType.WAIT_TAP_TIMEOUT -> { - delay(ViewConfiguration.getTapTimeout().toLong()) - qsLongPressEffect.handleTimeoutComplete() + QSLongPressEffect.ActionType.CLICK -> { + tile.performClick() + qsLongPressEffect.clearActionType() } QSLongPressEffect.ActionType.LONG_PRESS -> { tile.prepareForLaunch() - qsLongPressEffect.qsTile?.longClick(qsLongPressEffect.expandable) + tile.performLongClick() qsLongPressEffect.clearActionType() } QSLongPressEffect.ActionType.RESET_AND_LONG_PRESS -> { tile.resetLongPressEffectProperties() - qsLongPressEffect.qsTile?.longClick(qsLongPressEffect.expandable) + tile.performLongClick() qsLongPressEffect.clearActionType() } QSLongPressEffect.ActionType.START_ANIMATOR -> { @@ -102,4 +106,22 @@ object QSLongPressEffectViewBinder { } } } + + @SuppressLint("ClickableViewAccessibility") + private fun setTouchListener(tile: QSTileViewImpl, longPressEffect: QSLongPressEffect?) { + tile.setOnTouchListener { _, event -> + when (event.actionMasked) { + MotionEvent.ACTION_DOWN -> { + tile.postDelayed( + { longPressEffect?.handleTimeoutComplete() }, + ViewConfiguration.getTapTimeout().toLong(), + ) + longPressEffect?.handleActionDown() + } + MotionEvent.ACTION_UP -> longPressEffect?.handleActionUp() + MotionEvent.ACTION_CANCEL -> longPressEffect?.handleActionCancel() + } + true + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardModule.kt b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardModule.kt index fc9406bd27d8..c6fb4f9d6956 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardModule.kt @@ -19,13 +19,12 @@ package com.android.systemui.keyboard import com.android.systemui.keyboard.data.repository.KeyboardRepository import com.android.systemui.keyboard.data.repository.KeyboardRepositoryImpl -import com.android.systemui.keyboard.shortcut.ShortcutHelperModule import com.android.systemui.keyboard.stickykeys.data.repository.StickyKeysRepository import com.android.systemui.keyboard.stickykeys.data.repository.StickyKeysRepositoryImpl import dagger.Binds import dagger.Module -@Module(includes = [ShortcutHelperModule::class]) +@Module abstract class KeyboardModule { @Binds diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt index 52ccc219353e..271e79b8d060 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt @@ -16,13 +16,16 @@ package com.android.systemui.keyboard.shortcut.ui.composable -import androidx.annotation.StringRes import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.FlowRowScope import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -32,21 +35,19 @@ import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.OpenInNew -import androidx.compose.material.icons.filled.Accessibility -import androidx.compose.material.icons.filled.Apps import androidx.compose.material.icons.filled.ExpandMore -import androidx.compose.material.icons.filled.Keyboard import androidx.compose.material.icons.filled.Search -import androidx.compose.material.icons.filled.Tv -import androidx.compose.material.icons.filled.VerticalSplit import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.NavigationDrawerItemColors @@ -56,6 +57,7 @@ import androidx.compose.material3.SearchBarDefaults import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -69,10 +71,13 @@ import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.platform.rememberNestedScrollInteropConnection import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.util.fastForEach @@ -81,8 +86,13 @@ import com.android.compose.windowsizeclass.LocalWindowSizeClass import com.android.systemui.res.R @Composable -fun ShortcutHelper(modifier: Modifier = Modifier, onKeyboardSettingsClicked: () -> Unit) { - if (shouldUseSinglePane()) { +fun ShortcutHelper( + onKeyboardSettingsClicked: () -> Unit, + modifier: Modifier = Modifier, + categories: List<ShortcutHelperCategory> = ShortcutHelperTemporaryData.categories, + useSinglePane: @Composable () -> Boolean = { shouldUseSinglePane() }, +) { + if (useSinglePane()) { ShortcutHelperSinglePane(modifier, categories, onKeyboardSettingsClicked) } else { ShortcutHelperTwoPane(modifier, categories, onKeyboardSettingsClicked) @@ -91,7 +101,8 @@ fun ShortcutHelper(modifier: Modifier = Modifier, onKeyboardSettingsClicked: () @Composable private fun shouldUseSinglePane() = - LocalWindowSizeClass.current.widthSizeClass == WindowWidthSizeClass.Compact + LocalWindowSizeClass.current.widthSizeClass == WindowWidthSizeClass.Compact || + LocalWindowSizeClass.current.heightSizeClass == WindowHeightSizeClass.Compact @Composable private fun ShortcutHelperSinglePane( @@ -209,11 +220,31 @@ private fun RotatingExpandCollapseIcon(isExpanded: Boolean) { @Composable private fun ShortcutCategoryDetailsSinglePane(category: ShortcutHelperCategory) { - Box(modifier = Modifier.fillMaxWidth().heightIn(min = 300.dp)) { - Text( - modifier = Modifier.align(Alignment.Center), - text = stringResource(category.labelResId), - ) + Column(Modifier.padding(horizontal = 16.dp)) { + category.subCategories.fastForEach { subCategory -> + ShortcutSubCategorySinglePane(subCategory) + } + } +} + +@Composable +private fun ShortcutSubCategorySinglePane(subCategory: SubCategory) { + // This @Composable is expected to be in a Column. + SubCategoryTitle(subCategory.label) + subCategory.shortcuts.fastForEachIndexed { index, shortcut -> + if (index > 0) { + HorizontalDivider() + } + ShortcutSinglePane(shortcut) + } +} + +@Composable +private fun ShortcutSinglePane(shortcut: Shortcut) { + Column(Modifier.padding(vertical = 24.dp)) { + ShortcutDescriptionText(shortcut = shortcut) + Spacer(modifier = Modifier.height(12.dp)) + ShortcutKeyCombinations(shortcut = shortcut) } } @@ -223,6 +254,7 @@ private fun ShortcutHelperTwoPane( categories: List<ShortcutHelperCategory>, onKeyboardSettingsClicked: () -> Unit, ) { + var selectedCategory by remember { mutableStateOf(categories.first()) } Column(modifier = modifier.fillMaxSize().padding(start = 24.dp, end = 24.dp, top = 26.dp)) { TitleBar() Spacer(modifier = Modifier.height(12.dp)) @@ -230,39 +262,189 @@ private fun ShortcutHelperTwoPane( StartSidePanel( modifier = Modifier.fillMaxWidth(fraction = 0.32f), categories = categories, + selectedCategory = selectedCategory, + onCategoryClicked = { selectedCategory = it }, onKeyboardSettingsClicked = onKeyboardSettingsClicked, ) Spacer(modifier = Modifier.width(24.dp)) - EndSidePanel(Modifier.fillMaxSize()) + EndSidePanel(Modifier.fillMaxSize(), selectedCategory) + } + } +} + +@Composable +private fun EndSidePanel(modifier: Modifier, category: ShortcutHelperCategory) { + LazyColumn(modifier.nestedScroll(rememberNestedScrollInteropConnection())) { + items(items = category.subCategories, key = { item -> item.label }) { + SubCategoryContainerDualPane(it) + Spacer(modifier = Modifier.height(8.dp)) } } } @Composable +private fun SubCategoryContainerDualPane(subCategory: SubCategory) { + Surface( + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(28.dp), + color = MaterialTheme.colorScheme.surfaceBright + ) { + Column(Modifier.padding(horizontal = 32.dp, vertical = 24.dp)) { + SubCategoryTitle(subCategory.label) + Spacer(Modifier.height(24.dp)) + subCategory.shortcuts.fastForEachIndexed { index, shortcut -> + if (index > 0) { + HorizontalDivider() + } + ShortcutViewDualPane(shortcut) + } + } + } +} + +@Composable +private fun SubCategoryTitle(title: String) { + Text( + title, + style = MaterialTheme.typography.titleSmall, + color = MaterialTheme.colorScheme.primary, + ) +} + +@Composable +private fun ShortcutViewDualPane(shortcut: Shortcut) { + Row(Modifier.padding(vertical = 16.dp)) { + ShortcutDescriptionText( + modifier = Modifier.weight(0.25f).align(Alignment.CenterVertically), + shortcut = shortcut, + ) + ShortcutKeyCombinations( + modifier = Modifier.weight(0.75f), + shortcut = shortcut, + ) + } +} + +@OptIn(ExperimentalLayoutApi::class) +@Composable +private fun ShortcutKeyCombinations( + modifier: Modifier = Modifier, + shortcut: Shortcut, +) { + FlowRow(modifier = modifier, verticalArrangement = Arrangement.spacedBy(8.dp)) { + shortcut.commands.forEachIndexed { index, command -> + if (index > 0) { + ShortcutOrSeparator(spacing = 16.dp) + } + ShortcutCommand(command) + } + } +} + +@Composable +private fun ShortcutCommand(command: ShortcutCommand) { + // This @Composable is expected to be in a Row or FlowRow. + command.keys.forEachIndexed { keyIndex, key -> + if (keyIndex > 0) { + Spacer(Modifier.width(4.dp)) + } + ShortcutKeyContainer { + if (key is ShortcutKey.Text) { + ShortcutTextKey(key) + } else if (key is ShortcutKey.Icon) { + ShortcutIconKey(key) + } + } + } +} + +@Composable +private fun ShortcutKeyContainer(shortcutKeyContent: @Composable BoxScope.() -> Unit) { + Box( + modifier = + Modifier.height(36.dp) + .background( + color = MaterialTheme.colorScheme.surfaceContainer, + shape = RoundedCornerShape(12.dp) + ), + ) { + shortcutKeyContent() + } +} + +@Composable +private fun BoxScope.ShortcutTextKey(key: ShortcutKey.Text) { + Text( + text = key.value, + modifier = Modifier.align(Alignment.Center).padding(horizontal = 12.dp), + style = MaterialTheme.typography.titleSmall, + ) +} + +@Composable +private fun BoxScope.ShortcutIconKey(key: ShortcutKey.Icon) { + Icon( + imageVector = key.value, + contentDescription = null, + modifier = Modifier.align(Alignment.Center).padding(6.dp) + ) +} + +@OptIn(ExperimentalLayoutApi::class) +@Composable +private fun FlowRowScope.ShortcutOrSeparator(spacing: Dp) { + Spacer(Modifier.width(spacing)) + Text( + text = stringResource(R.string.shortcut_helper_key_combinations_or_separator), + modifier = Modifier.align(Alignment.CenterVertically), + style = MaterialTheme.typography.titleSmall, + ) + Spacer(Modifier.width(spacing)) +} + +@Composable +private fun ShortcutDescriptionText( + shortcut: Shortcut, + modifier: Modifier = Modifier, +) { + Text( + modifier = modifier, + text = shortcut.label, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurface, + ) +} + +@Composable private fun StartSidePanel( modifier: Modifier, categories: List<ShortcutHelperCategory>, onKeyboardSettingsClicked: () -> Unit, + selectedCategory: ShortcutHelperCategory, + onCategoryClicked: (ShortcutHelperCategory) -> Unit, ) { Column(modifier) { ShortcutsSearchBar() Spacer(modifier = Modifier.heightIn(16.dp)) - CategoriesPanelTwoPane(categories) + CategoriesPanelTwoPane(categories, selectedCategory, onCategoryClicked) Spacer(modifier = Modifier.weight(1f)) KeyboardSettings(onKeyboardSettingsClicked) } } @Composable -private fun CategoriesPanelTwoPane(categories: List<ShortcutHelperCategory>) { - var selected by remember { mutableStateOf(categories.first()) } +private fun CategoriesPanelTwoPane( + categories: List<ShortcutHelperCategory>, + selectedCategory: ShortcutHelperCategory, + onCategoryClicked: (ShortcutHelperCategory) -> Unit +) { Column { categories.fastForEach { CategoryItemTwoPane( label = stringResource(it.labelResId), icon = it.icon, - selected = selected == it, - onClick = { selected = it } + selected = selectedCategory == it, + onClick = { onCategoryClicked(it) } ) } } @@ -305,15 +487,6 @@ private fun CategoryItemTwoPane( } @Composable -fun EndSidePanel(modifier: Modifier) { - Surface( - modifier = modifier, - shape = RoundedCornerShape(28.dp), - color = MaterialTheme.colorScheme.surfaceBright - ) {} -} - -@Composable @OptIn(ExperimentalMaterial3Api::class) private fun TitleBar() { CenterAlignedTopAppBar( @@ -333,6 +506,7 @@ private fun TitleBar() { private fun ShortcutsSearchBar() { var query by remember { mutableStateOf("") } SearchBar( + modifier = Modifier.fillMaxWidth(), colors = SearchBarDefaults.colors(containerColor = MaterialTheme.colorScheme.surfaceBright), query = query, active = false, @@ -372,25 +546,6 @@ private fun KeyboardSettings(onClick: () -> Unit) { } } -/** Temporary data class just to populate the UI. */ -private data class ShortcutHelperCategory( - @StringRes val labelResId: Int, - val icon: ImageVector, -) - -// Temporarily populating the categories directly in the UI. -private val categories = - listOf( - ShortcutHelperCategory(R.string.shortcut_helper_category_system, Icons.Default.Tv), - ShortcutHelperCategory( - R.string.shortcut_helper_category_multitasking, - Icons.Default.VerticalSplit - ), - ShortcutHelperCategory(R.string.shortcut_helper_category_input, Icons.Default.Keyboard), - ShortcutHelperCategory(R.string.shortcut_helper_category_app_shortcuts, Icons.Default.Apps), - ShortcutHelperCategory(R.string.shortcut_helper_category_a11y, Icons.Default.Accessibility), - ) - object ShortcutHelper { object Shapes { diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperTemporaryData.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperTemporaryData.kt new file mode 100644 index 000000000000..fa2388f6287d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperTemporaryData.kt @@ -0,0 +1,251 @@ +/* + * 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.keyboard.shortcut.ui.composable + +import androidx.annotation.StringRes +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Accessibility +import androidx.compose.material.icons.filled.Apps +import androidx.compose.material.icons.filled.ArrowBackIosNew +import androidx.compose.material.icons.filled.Keyboard +import androidx.compose.material.icons.filled.KeyboardCommandKey +import androidx.compose.material.icons.filled.RadioButtonUnchecked +import androidx.compose.material.icons.filled.Tv +import androidx.compose.material.icons.filled.VerticalSplit +import androidx.compose.ui.graphics.vector.ImageVector +import com.android.systemui.res.R + +/** Temporary data classes and data below just to populate the UI. */ +data class ShortcutHelperCategory( + @StringRes val labelResId: Int, + val icon: ImageVector, + val subCategories: List<SubCategory>, +) + +data class SubCategory( + val label: String, + val shortcuts: List<Shortcut>, +) + +data class Shortcut(val label: String, val commands: List<ShortcutCommand>) + +data class ShortcutCommand(val keys: List<ShortcutKey>) + +sealed interface ShortcutKey { + data class Text(val value: String) : ShortcutKey + + data class Icon(val value: ImageVector) : ShortcutKey +} + +// DSL Builder Functions +private fun shortcutHelperCategory( + labelResId: Int, + icon: ImageVector, + block: ShortcutHelperCategoryBuilder.() -> Unit +): ShortcutHelperCategory = ShortcutHelperCategoryBuilder(labelResId, icon).apply(block).build() + +private fun ShortcutHelperCategoryBuilder.subCategory( + label: String, + block: SubCategoryBuilder.() -> Unit +) { + subCategories.add(SubCategoryBuilder(label).apply(block).build()) +} + +private fun SubCategoryBuilder.shortcut(label: String, block: ShortcutBuilder.() -> Unit) { + shortcuts.add(ShortcutBuilder(label).apply(block).build()) +} + +private fun ShortcutBuilder.command(block: ShortcutCommandBuilder.() -> Unit) { + commands.add(ShortcutCommandBuilder().apply(block).build()) +} + +private fun ShortcutCommandBuilder.key(value: String) { + keys.add(ShortcutKey.Text(value)) +} + +private fun ShortcutCommandBuilder.key(value: ImageVector) { + keys.add(ShortcutKey.Icon(value)) +} + +private class ShortcutHelperCategoryBuilder( + private val labelResId: Int, + private val icon: ImageVector +) { + val subCategories = mutableListOf<SubCategory>() + + fun build() = ShortcutHelperCategory(labelResId, icon, subCategories) +} + +private class SubCategoryBuilder(private val label: String) { + val shortcuts = mutableListOf<Shortcut>() + + fun build() = SubCategory(label, shortcuts) +} + +private class ShortcutBuilder(private val label: String) { + val commands = mutableListOf<ShortcutCommand>() + + fun build() = Shortcut(label, commands) +} + +private class ShortcutCommandBuilder { + val keys = mutableListOf<ShortcutKey>() + + fun build() = ShortcutCommand(keys) +} + +object ShortcutHelperTemporaryData { + + // Some shortcuts and their strings below are made up just to populate the UI for now. + // For this reason they are not in translatable resources yet. + val categories = + listOf( + shortcutHelperCategory(R.string.shortcut_helper_category_system, Icons.Default.Tv) { + subCategory("System controls") { + shortcut("Go to home screen") { + command { key(Icons.Default.RadioButtonUnchecked) } + command { + key(Icons.Default.KeyboardCommandKey) + key("H") + } + command { + key(Icons.Default.KeyboardCommandKey) + key("Return") + } + } + shortcut("View recent apps") { + command { + key(Icons.Default.KeyboardCommandKey) + key("Tab") + } + } + shortcut("All apps search") { + command { key(Icons.Default.KeyboardCommandKey) } + } + } + subCategory("System apps") { + shortcut("Go back") { + command { key(Icons.Default.ArrowBackIosNew) } + command { + key(Icons.Default.KeyboardCommandKey) + key("Left arrow") + } + command { + key(Icons.Default.KeyboardCommandKey) + key("ESC") + } + command { + key(Icons.Default.KeyboardCommandKey) + key("Backspace") + } + } + shortcut("View notifications") { + command { + key(Icons.Default.KeyboardCommandKey) + key("N") + } + } + shortcut("Take a screenshot") { + command { key(Icons.Default.KeyboardCommandKey) } + command { key("CTRL") } + command { key("S") } + } + shortcut("Open Settings") { + command { + key(Icons.Default.KeyboardCommandKey) + key("I") + } + } + } + }, + shortcutHelperCategory( + R.string.shortcut_helper_category_multitasking, + Icons.Default.VerticalSplit + ) { + subCategory("Multitasking & windows") { + shortcut("Take a screenshot") { + command { key(Icons.Default.KeyboardCommandKey) } + command { key("CTRL") } + command { key("S") } + } + } + }, + shortcutHelperCategory( + R.string.shortcut_helper_category_input, + Icons.Default.Keyboard + ) { + subCategory("Input") { + shortcut("Open Settings") { + command { + key(Icons.Default.KeyboardCommandKey) + key("I") + } + } + shortcut("View notifications") { + command { + key(Icons.Default.KeyboardCommandKey) + key("N") + } + } + } + }, + shortcutHelperCategory( + R.string.shortcut_helper_category_app_shortcuts, + Icons.Default.Apps + ) { + subCategory("App shortcuts") { + shortcut("Open Settings") { + command { + key(Icons.Default.KeyboardCommandKey) + key("I") + } + } + shortcut("Go back") { + command { key(Icons.Default.ArrowBackIosNew) } + command { + key(Icons.Default.KeyboardCommandKey) + key("Left arrow") + } + command { + key(Icons.Default.KeyboardCommandKey) + key("ESC") + } + command { + key(Icons.Default.KeyboardCommandKey) + key("Backspace") + } + } + } + }, + shortcutHelperCategory( + R.string.shortcut_helper_category_a11y, + Icons.Default.Accessibility + ) { + subCategory("Accessibility shortcuts") { + shortcut("View recent apps") { + command { + key(Icons.Default.KeyboardCommandKey) + key("Tab") + } + } + shortcut("All apps search") { + command { key(Icons.Default.KeyboardCommandKey) } + } + } + } + ) +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt index d09b9f68ea60..5d541260b05f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt @@ -38,6 +38,7 @@ constructor( ) : KeyguardQuickAffordanceConfig { override val key: String = BuiltInKeyguardQuickAffordanceKeys.GLANCEABLE_HUB + override fun pickerName(): String = "Glanceable hub" override val pickerIconResourceId = R.drawable.ic_widgets @@ -52,6 +53,10 @@ constructor( } } + override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState { + return KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice + } + override fun onTriggered( expandable: Expandable? ): KeyguardQuickAffordanceConfig.OnTriggeredResult { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt index f3692bdd3a4a..f5e98f1fedfe 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt @@ -29,7 +29,6 @@ import com.android.systemui.keyguard.shared.model.BiometricUnlockMode.Companion. import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.util.kotlin.Utils.Companion.sample -import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.CoroutineDispatcher @@ -66,7 +65,6 @@ constructor( override fun start() { listenForDozingToAny() - listenForDozingToGoneViaBiometrics() listenForWakeFromDozing() listenForTransitionToCamera(scope, keyguardInteractor) } @@ -79,35 +77,6 @@ constructor( isKeyguardDismissible && !isKeyguardShowing } - private fun listenForDozingToGoneViaBiometrics() { - if (KeyguardWmStateRefactor.isEnabled) { - return - } - - // This is separate from `listenForDozingToAny` because any delay on wake and unlock will - // cause a noticeable issue with animations - scope.launch { - powerInteractor.isAwake - .filterRelevantKeyguardStateAnd { isAwake -> isAwake } - .sample( - keyguardInteractor.biometricUnlockState, - ::Pair, - ) - .collect { - ( - _, - biometricUnlockState, - ) -> - if (isWakeAndUnlock(biometricUnlockState.mode)) { - startTransitionTo( - KeyguardState.GONE, - ownerReason = "biometric wake and unlock", - ) - } - } - } - } - private fun listenForDozingToAny() { if (KeyguardWmStateRefactor.isEnabled) { return @@ -118,6 +87,7 @@ constructor( .debounce(50L) .filterRelevantKeyguardStateAnd { isAwake -> isAwake } .sample( + keyguardInteractor.biometricUnlockState, keyguardInteractor.isKeyguardOccluded, communalInteractor.isIdleOnCommunal, canTransitionToGoneOnWake, @@ -126,6 +96,7 @@ constructor( .collect { ( _, + biometricUnlockState, occluded, isIdleOnCommunal, canTransitionToGoneOnWake, @@ -133,6 +104,8 @@ constructor( startTransitionTo( if (!deviceEntryRepository.isLockscreenEnabled()) { KeyguardState.GONE + } else if (isWakeAndUnlock(biometricUnlockState.mode)) { + KeyguardState.GONE } else if (canTransitionToGoneOnWake) { KeyguardState.GONE } else if (primaryBouncerShowing) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt index a540d761c38f..f5b12a2ecfcf 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt @@ -169,6 +169,7 @@ constructor( KeyguardState.AOD -> TO_AOD_DURATION KeyguardState.DOZING -> TO_DOZING_DURATION KeyguardState.LOCKSCREEN -> TO_LOCKSCREEN_DURATION + KeyguardState.GLANCEABLE_HUB -> TO_GLANCEABLE_HUB_DURATION else -> DEFAULT_DURATION }.inWholeMilliseconds } @@ -181,5 +182,6 @@ constructor( val TO_AOD_DURATION = 1300.milliseconds val TO_DOZING_DURATION = 933.milliseconds val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION + val TO_GLANCEABLE_HUB_DURATION = DEFAULT_DURATION } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt index 6b11dc57e096..191056c5578a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt @@ -121,10 +121,7 @@ object KeyguardSmartspaceViewBinder { ) { val dateView = constraintLayout.requireViewById<View>(sharedR.id.date_smartspace_view) - val weatherView = - constraintLayout.requireViewById<View>(sharedR.id.weather_smartspace_view) addView(dateView) - addView(weatherView) } } } @@ -141,9 +138,6 @@ object KeyguardSmartspaceViewBinder { ) { val dateView = constraintLayout.requireViewById<View>(sharedR.id.date_smartspace_view) - val weatherView = - constraintLayout.requireViewById<View>(sharedR.id.weather_smartspace_view) - removeView(weatherView) removeView(dateView) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt index 1f4bc61fb003..ecdc21cf3bb5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt @@ -35,6 +35,7 @@ import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDreamingTransit import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToOccludedTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.GoneToAodTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.GoneToDozingTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.GoneToGlanceableHubTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.GoneToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.LockscreenToAodTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDozingTransitionViewModel @@ -246,4 +247,10 @@ abstract class DeviceEntryIconTransitionModule { abstract fun occludedToGlanceableHub( impl: OccludedToGlanceableHubTransitionViewModel ): DeviceEntryIconTransition + + @Binds + @IntoSet + abstract fun goneToGlanceableHub( + impl: GoneToGlanceableHubTransitionViewModel + ): DeviceEntryIconTransition } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt index 0435531bb87c..8a751f05e102 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.ui.view.layout.sections import android.content.Context import android.view.View +import android.view.ViewGroup import android.view.ViewTreeObserver.OnGlobalLayoutListener import androidx.constraintlayout.widget.Barrier import androidx.constraintlayout.widget.ConstraintLayout @@ -51,7 +52,7 @@ constructor( ) : KeyguardSection() { private var smartspaceView: View? = null private var weatherView: View? = null - private var dateView: View? = null + private var dateWeatherView: ViewGroup? = null private var smartspaceVisibilityListener: OnGlobalLayoutListener? = null private var pastVisibility: Int = -1 @@ -69,12 +70,15 @@ constructor( if (!keyguardSmartspaceViewModel.isSmartspaceEnabled) return smartspaceView = smartspaceController.buildAndConnectView(constraintLayout) weatherView = smartspaceController.buildAndConnectWeatherView(constraintLayout) - dateView = smartspaceController.buildAndConnectDateView(constraintLayout) + dateWeatherView = + smartspaceController.buildAndConnectDateView(constraintLayout) as ViewGroup pastVisibility = smartspaceView?.visibility ?: View.GONE constraintLayout.addView(smartspaceView) if (keyguardSmartspaceViewModel.isDateWeatherDecoupled) { - constraintLayout.addView(weatherView) - constraintLayout.addView(dateView) + constraintLayout.addView(dateWeatherView) + // Place weather right after the date, before the extras (alarm and dnd) + val index = if (dateWeatherView?.childCount == 0) 0 else 1 + dateWeatherView?.addView(weatherView, index) } keyguardUnlockAnimationController.lockscreenSmartspace = smartspaceView smartspaceVisibilityListener = OnGlobalLayoutListener { @@ -116,26 +120,6 @@ constructor( ConstraintSet.START, horizontalPaddingStart ) - constrainWidth(sharedR.id.weather_smartspace_view, ConstraintSet.WRAP_CONTENT) - connect( - sharedR.id.weather_smartspace_view, - ConstraintSet.TOP, - sharedR.id.date_smartspace_view, - ConstraintSet.TOP - ) - connect( - sharedR.id.weather_smartspace_view, - ConstraintSet.BOTTOM, - sharedR.id.date_smartspace_view, - ConstraintSet.BOTTOM - ) - connect( - sharedR.id.weather_smartspace_view, - ConstraintSet.START, - sharedR.id.date_smartspace_view, - ConstraintSet.END, - 4 - ) // migrate addSmartspaceView from KeyguardClockSwitchController constrainHeight(sharedR.id.bc_smartspace_view, ConstraintSet.WRAP_CONTENT) @@ -186,7 +170,6 @@ constructor( *intArrayOf( sharedR.id.bc_smartspace_view, sharedR.id.date_smartspace_view, - sharedR.id.weather_smartspace_view, ) ) } @@ -196,7 +179,7 @@ constructor( override fun removeViews(constraintLayout: ConstraintLayout) { if (!MigrateClocksToBlueprint.isEnabled) return if (!keyguardSmartspaceViewModel.isSmartspaceEnabled) return - listOf(smartspaceView, dateView, weatherView).forEach { + listOf(smartspaceView, dateWeatherView).forEach { it?.let { if (it.parent == constraintLayout) { constraintLayout.removeView(it) @@ -220,7 +203,7 @@ constructor( setVisibility(sharedR.id.weather_smartspace_view, weatherVisibility) setAlpha( sharedR.id.weather_smartspace_view, - if (weatherVisibility == ConstraintSet.VISIBLE) 1f else 0f + if (weatherVisibility == View.VISIBLE) 1f else 0f ) val dateVisibility = if (keyguardClockViewModel.hasCustomWeatherDataDisplay.value) ConstraintSet.GONE diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModel.kt index 480f948f67f5..77ebfcea9c96 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModel.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.ui.viewmodel +import android.util.MathUtils import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromDozingTransitionInteractor.Companion.TO_GONE_DURATION import com.android.systemui.keyguard.shared.model.Edge @@ -49,10 +50,12 @@ constructor( ) fun lockscreenAlpha(viewState: ViewStateAccessor): Flow<Float> { + var startAlpha = 1f return transitionAnimation.sharedFlow( duration = 200.milliseconds, - onStart = { 0f }, - onStep = { 0f }, + onStart = { startAlpha = viewState.alpha() }, + onStep = { MathUtils.lerp(startAlpha, 0f, it) }, + onFinish = { 0f }, ) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToGlanceableHubTransitionViewModel.kt new file mode 100644 index 000000000000..8eab406a1273 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToGlanceableHubTransitionViewModel.kt @@ -0,0 +1,50 @@ +/* + * 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.keyguard.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_GLANCEABLE_HUB_DURATION +import com.android.systemui.keyguard.shared.model.Edge +import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB +import com.android.systemui.keyguard.shared.model.KeyguardState.GONE +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition +import com.android.systemui.scene.shared.model.Scenes +import javax.inject.Inject +import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.flow.Flow + +@SysUISingleton +class GoneToGlanceableHubTransitionViewModel +@Inject +constructor( + animationFlow: KeyguardTransitionAnimationFlow, +) : DeviceEntryIconTransition { + + private val transitionAnimation = + animationFlow + .setup(duration = TO_GLANCEABLE_HUB_DURATION, edge = Edge.create(GONE, Scenes.Communal)) + .setupWithoutSceneContainer(edge = Edge.create(GONE, GLANCEABLE_HUB)) + + override val deviceEntryParentViewAlpha: Flow<Float> = + transitionAnimation.sharedFlow( + duration = 167.milliseconds, + onStep = { it }, + onCancel = { 0f }, + onFinish = { 1f }, + ) +} diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt index 8e985e11732f..37dffd1955d6 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt @@ -107,6 +107,7 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch @@ -371,6 +372,7 @@ class MediaDataProcessor( .onStart { emit(Unit) } .map { allowMediaRecommendations() } .distinctUntilChanged() + .flowOn(backgroundDispatcher) // only track the most recent emission .collectLatest { allowMediaRecommendations = it diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt index edead51dd8e0..8f1556166431 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt @@ -42,7 +42,6 @@ import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.Dumpable import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager @@ -107,6 +106,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch @@ -124,7 +124,6 @@ private val DEBUG = Log.isLoggable(TAG, Log.DEBUG) class MediaCarouselController @Inject constructor( - @Application applicationScope: CoroutineScope, private val context: Context, private val mediaControlPanelFactory: Provider<MediaControlPanel>, private val visualStabilityProvider: VisualStabilityProvider, @@ -389,12 +388,12 @@ constructor( repeatOnLifecycle(Lifecycle.State.STARTED) { listenForAnyStateToGoneKeyguardTransition(this) listenForAnyStateToLockscreenTransition(this) + listenForLockscreenSettingChanges(this) if (!mediaFlags.isSceneContainerEnabled()) return@repeatOnLifecycle listenForMediaItemsChanges(this) } } - listenForLockscreenSettingChanges(applicationScope) // Notifies all active players about animation scale changes. globalSettings.registerContentObserverSync( @@ -696,6 +695,7 @@ constructor( .onStart { emit(Unit) } .map { getMediaLockScreenSetting() } .distinctUntilChanged() + .flowOn(backgroundDispatcher) .collectLatest { allowMediaPlayerOnLockScreen = it updateHostVisibility() diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt index 596c18f04134..03adf1b68095 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt @@ -53,8 +53,13 @@ constructor( withContext(coroutineDispatcher) { val groupedTasks: List<GroupedRecentTaskInfo> = recents?.getTasks() ?: emptyList() // Note: the returned task list is from the most-recent to least-recent order. - // The last foreground task is at index 1, because at index 0 will be our app selector. - val foregroundGroup = groupedTasks.elementAtOrNull(1) + // When opening the app selector in full screen, index 0 will be just the app selector + // activity and a null second task, so the foreground task will be index 1, but when + // opening the app selector in split screen mode, the foreground task will be the second + // task in index 0. + val foregroundGroup = + if (groupedTasks.first().splitBounds != null) groupedTasks.first() + else groupedTasks.elementAtOrNull(1) val foregroundTaskId1 = foregroundGroup?.taskInfo1?.taskId val foregroundTaskId2 = foregroundGroup?.taskInfo2?.taskId val foregroundTaskIds = listOfNotNull(foregroundTaskId1, foregroundTaskId2) diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/DeadZone.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/DeadZone.java index 326830600635..8177fdec86e6 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/DeadZone.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/DeadZone.java @@ -61,6 +61,7 @@ public class DeadZone { } }; + private final boolean mUseDeadZone; private final NavigationBarController mNavBarController; private final NavigationBarView mNavigationBarView; @@ -86,9 +87,12 @@ public class DeadZone { @Inject public DeadZone(NavigationBarView view) { + mUseDeadZone = view.getResources().getBoolean(R.bool.config_useDeadZone); + mNavigationBarView = view; mNavBarController = Dependency.get(NavigationBarController.class); mDisplayId = view.getContext().getDisplayId(); + onConfigurationChanged(HORIZONTAL); } @@ -108,12 +112,20 @@ public class DeadZone { } public void setFlashOnTouchCapture(boolean dbg) { + if (!mUseDeadZone) { + return; + } + mShouldFlash = dbg; mFlashFrac = 0f; mNavigationBarView.postInvalidate(); } public void onConfigurationChanged(int rotation) { + if (!mUseDeadZone) { + return; + } + mDisplayRotation = rotation; final Resources res = mNavigationBarView.getResources(); @@ -134,6 +146,10 @@ public class DeadZone { // I made you a touch event... public boolean onTouchEvent(MotionEvent event) { + if (!mUseDeadZone) { + return false; + } + if (DEBUG) { Slog.v(TAG, this + " onTouch: " + MotionEvent.actionToString(event.getAction())); } @@ -187,17 +203,17 @@ public class DeadZone { if (mShouldFlash) mNavigationBarView.postInvalidate(); } - public void setFlash(float f) { + private void setFlash(float f) { mFlashFrac = f; mNavigationBarView.postInvalidate(); } - public float getFlash() { + private float getFlash() { return mFlashFrac; } public void onDraw(Canvas can) { - if (!mShouldFlash || mFlashFrac <= 0f) { + if (!mUseDeadZone || !mShouldFlash || mFlashFrac <= 0f) { return; } diff --git a/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeSceneViewModel.kt index f677ec1b31bb..d0c7fbcac189 100644 --- a/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeSceneViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeSceneViewModel.kt @@ -17,41 +17,25 @@ package com.android.systemui.notifications.ui.viewmodel import com.android.compose.animation.scene.Back -import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel +import com.android.systemui.scene.shared.model.SceneFamilies import javax.inject.Inject -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.asStateFlow /** Models UI state and handles user input for the Notifications Shade scene. */ @SysUISingleton -class NotificationsShadeSceneViewModel -@Inject -constructor( - @Application private val applicationScope: CoroutineScope, - overlayShadeViewModel: OverlayShadeViewModel, -) { +class NotificationsShadeSceneViewModel @Inject constructor() { val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> = - overlayShadeViewModel.backgroundScene - .map(::destinationScenes) - .stateIn( - scope = applicationScope, - started = SharingStarted.WhileSubscribed(), - initialValue = destinationScenes(overlayShadeViewModel.backgroundScene.value), + MutableStateFlow( + mapOf( + Swipe.Up to SceneFamilies.Home, + Back to SceneFamilies.Home, + ) ) - - private fun destinationScenes(backgroundScene: SceneKey): Map<UserAction, UserActionResult> { - return mapOf( - Swipe.Up to backgroundScene, - Back to backgroundScene, - ) - } + .asStateFlow() } diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java index 9e313797674d..0a880293ca76 100644 --- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java +++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java @@ -23,7 +23,6 @@ import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE; import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN; import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD; -import static android.appwidget.flags.Flags.drawDataParcel; import static android.appwidget.flags.Flags.generatedPreviews; import static android.content.Intent.ACTION_BOOT_COMPLETED; import static android.content.Intent.ACTION_PACKAGE_ADDED; @@ -72,7 +71,6 @@ import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; import android.graphics.drawable.Icon; import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; @@ -113,8 +111,6 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; import com.android.wm.shell.bubbles.Bubbles; -import java.io.IOException; -import java.io.InputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; @@ -1456,54 +1452,13 @@ public class PeopleSpaceWidgetManager implements Dumpable { if (DEBUG) { Log.d(TAG, "Updating People Space widget preview for user " + user.getIdentifier()); } - if (!drawDataParcel() || (!Build.IS_USERDEBUG && !Build.IS_ENG)) { - updateGeneratedPreviewForUserInternal(provider, user, - new RemoteViews(mContext.getPackageName(), - R.layout.people_space_placeholder_layout)); - } else { - mBgExecutor.execute(updateGeneratedPreviewFromDrawInstructionsForUser(provider, user)); - } - } - - private void updateGeneratedPreviewForUserInternal(@NonNull final ComponentName provider, - @NonNull final UserHandle user, @NonNull final RemoteViews rv) { boolean success = mAppWidgetManager.setWidgetPreview( provider, WIDGET_CATEGORY_HOME_SCREEN | WIDGET_CATEGORY_KEYGUARD, - rv); + new RemoteViews(mContext.getPackageName(), + R.layout.people_space_placeholder_layout)); if (DEBUG && !success) { Log.d(TAG, "Failed to update generated preview for user " + user.getIdentifier()); } mUpdatedPreviews.put(user.getIdentifier(), success); } - - private Runnable updateGeneratedPreviewFromDrawInstructionsForUser( - @NonNull final ComponentName provider, @NonNull final UserHandle user) { - return () -> { - if (DEBUG) { - Log.d(TAG, "Parsing People Space widget preview from binary for user " - + user.getIdentifier()); - } - if (!generatedPreviews() || mUpdatedPreviews.get(user.getIdentifier()) - || !mUserManager.isUserUnlocked(user)) { - // Conditions may have changed given this is called from background thread - return; - } - try (InputStream is = mContext.getResources().openRawResource(R.raw.widget) - ) { - final byte[] preview = new byte[(int) is.available()]; - final int result = is.read(preview); - if (DEBUG && result == -1) { - Log.d(TAG, "Failed parsing previews from binary for user " - + user.getIdentifier()); - } - updateGeneratedPreviewForUserInternal(provider, user, new RemoteViews( - new RemoteViews.DrawInstructions.Builder( - Collections.singletonList(preview)).build())); - } catch (IOException e) { - if (DEBUG) { - Log.e(TAG, "Failed to generate preview for people widget", e); - } - } - }; - } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 9c8c17bb1ca0..f3cc35ba31f8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -113,6 +113,9 @@ public class QSPanel extends LinearLayout implements Tunable { private boolean mSceneContainerEnabled; + @Nullable + private View mMediaViewPlaceHolderForScene; + public QSPanel(Context context, AttributeSet attrs) { super(context, attrs); mUsingMediaPlayer = useQsMediaPlayer(context); @@ -125,7 +128,6 @@ public class QSPanel extends LinearLayout implements Tunable { setOrientation(VERTICAL); mMovableContentStartIndex = getChildCount(); - } void initialize(QSLogger qsLogger, boolean usingMediaPlayer) { @@ -133,7 +135,7 @@ public class QSPanel extends LinearLayout implements Tunable { mUsingMediaPlayer = usingMediaPlayer; mTileLayout = getOrCreateTileLayout(); - if (mUsingMediaPlayer) { + if (mUsingMediaPlayer || SceneContainerFlag.isEnabled()) { mHorizontalLinearLayout = new RemeasuringLinearLayout(mContext); mHorizontalLinearLayout.setOrientation(LinearLayout.HORIZONTAL); mHorizontalLinearLayout.setVisibility( @@ -151,6 +153,13 @@ public class QSPanel extends LinearLayout implements Tunable { lp.setMarginEnd(marginSize); lp.gravity = Gravity.CENTER_VERTICAL; mHorizontalLinearLayout.addView(mHorizontalContentContainer, lp); + if (SceneContainerFlag.isEnabled()) { + int mediaHeight = mContext.getResources() + .getDimensionPixelSize(R.dimen.qs_media_session_height_expanded); + lp = new LayoutParams(0, mediaHeight, 1); + mMediaViewPlaceHolderForScene = new View(mContext); + mHorizontalLinearLayout.addView(mMediaViewPlaceHolderForScene, lp); + } lp = new LayoutParams(LayoutParams.MATCH_PARENT, 0, 1); addView(mHorizontalLinearLayout, lp); @@ -383,6 +392,13 @@ public class QSPanel extends LinearLayout implements Tunable { if (mTileLayout != null) { mTileLayout.updateResources(); } + + if (mMediaViewPlaceHolderForScene != null) { + ViewGroup.LayoutParams lp = mMediaViewPlaceHolderForScene.getLayoutParams(); + lp.height = mContext.getResources() + .getDimensionPixelSize(R.dimen.qs_media_session_height_expanded); + mMediaViewPlaceHolderForScene.setLayoutParams(lp); + } } protected void updatePadding() { @@ -417,7 +433,8 @@ public class QSPanel extends LinearLayout implements Tunable { } private void updateHorizontalLinearLayoutMargins() { - if (mUsingMediaPlayer && mHorizontalLinearLayout != null && !displayMediaMarginsOnMedia()) { + if ((mUsingMediaPlayer || SceneContainerFlag.isEnabled()) && mHorizontalLinearLayout != null + && !displayMediaMarginsOnMedia()) { LayoutParams lp = (LayoutParams) mHorizontalLinearLayout.getLayoutParams(); lp.bottomMargin = Math.max(mMediaTotalBottomMargin - getPaddingBottom(), 0); mHorizontalLinearLayout.setLayoutParams(lp); @@ -632,6 +649,7 @@ public class QSPanel extends LinearLayout implements Tunable { // using media, the parent should always be this. ViewGroup newParent = horizontal && mUsingMediaPlayer ? mHorizontalContentContainer : this; + if (SceneContainerFlag.isEnabled()) return; switchAllContentToParent(newParent, mTileLayout); reAttachMediaHost(mediaHostView, horizontal); if (needsDynamicRowsAndColumns()) { @@ -647,6 +665,19 @@ public class QSPanel extends LinearLayout implements Tunable { void setColumnRowLayout(boolean withMedia) { mTileLayout.setMinRows(withMedia ? 2 : 1); mTileLayout.setMaxColumns(withMedia ? 2 : 4); + placeTileLayoutForScene(withMedia); + } + + protected void placeTileLayoutForScene(boolean withMedia) { + // The tile layout should be reparented if horizontal and we are using media. If not + // using media, the parent should always be this. + ViewGroup newParent = withMedia ? mHorizontalContentContainer : this; + if (mTileLayout != null && ((View) mTileLayout).getParent() != newParent) { + switchAllContentToParent(newParent, mTileLayout); + } + if (mHorizontalLinearLayout != null) { + mHorizontalLinearLayout.setVisibility(withMedia ? View.VISIBLE : View.GONE); + } } private void updateMargins(ViewGroup mediaHostView) { @@ -699,6 +730,12 @@ public class QSPanel extends LinearLayout implements Tunable { mCanCollapse = canCollapse; } + @Nullable + @VisibleForTesting + View getMediaPlaceholder() { + return mMediaViewPlaceHolderForScene; + } + public interface QSTileLayout { /** */ default void saveInstanceState(Bundle outState) {} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java index 3b5cc61057e6..13cedc2d2f3b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java @@ -456,7 +456,7 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr boolean switchTileLayout(boolean force) { /* Whether or not the panel currently contains a media player. */ boolean horizontal = shouldUseHorizontalLayout(); - if (horizontal != mUsingHorizontalLayout || force) { + if ((!SceneContainerFlag.isEnabled() && horizontal != mUsingHorizontalLayout) || force) { mQSLogger.logSwitchTileLayout(horizontal, mUsingHorizontalLayout, force, mView.getDumpableTag()); mUsingHorizontalLayout = horizontal; @@ -470,7 +470,7 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr return false; } - void setLayoutForMediaInScene() { + private void setLayoutForMediaInScene() { boolean withMedia = shouldUseHorizontalInScene(); mView.setColumnRowLayout(withMedia); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java index d457e88fcf14..fb47b4053b60 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java @@ -332,7 +332,7 @@ public class TileServices extends IQSService.Stub { if (info.applicationInfo.isSystemApp()) { final StatusBarIcon statusIcon = icon != null ? new StatusBarIcon(userHandle, packageName, icon, 0, 0, - contentDescription) + contentDescription, StatusBarIcon.Type.SystemIcon) : null; final String slot = getStatusBarIconSlotName(componentName); mMainHandler.post(new Runnable() { diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt index d60076745a78..e1b21ef99f42 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt @@ -284,7 +284,7 @@ class PartitionedGridLayout @Inject constructor(private val viewModel: Partition Box( Modifier.fillMaxWidth() .background( - color = MaterialTheme.colorScheme.surfaceVariant, + color = MaterialTheme.colorScheme.background, alpha = { 1f }, shape = RoundedCornerShape(dimensionResource(R.dimen.qs_corner_radius)) ) diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt index f776bf08c9e4..e4fbb4bb7c61 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt @@ -17,6 +17,8 @@ package com.android.systemui.qs.panels.ui.compose import android.graphics.drawable.Animatable +import android.service.quicksettings.Tile.STATE_ACTIVE +import android.service.quicksettings.Tile.STATE_INACTIVE import android.text.TextUtils import androidx.appcompat.content.res.AppCompatResources import androidx.compose.animation.graphics.ExperimentalAnimationGraphicsApi @@ -49,6 +51,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Remove import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -75,14 +78,11 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.Expandable -import com.android.compose.theme.colorAttr import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.ui.compose.Icon import com.android.systemui.common.ui.compose.load -import com.android.systemui.qs.panels.ui.viewmodel.ActiveTileColorAttributes import com.android.systemui.qs.panels.ui.viewmodel.AvailableEditActions import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel -import com.android.systemui.qs.panels.ui.viewmodel.TileColorAttributes import com.android.systemui.qs.panels.ui.viewmodel.TileUiState import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel import com.android.systemui.qs.panels.ui.viewmodel.toUiState @@ -108,10 +108,12 @@ fun Tile( tile.state .mapLatest { it.toUiState() } .collectAsStateWithLifecycle(tile.currentState.toUiState()) + val colors = TileDefaults.getColorForState(state.state) + val context = LocalContext.current Expandable( - color = colorAttr(state.colors.background), + color = colors.background, shape = RoundedCornerShape(dimensionResource(R.dimen.qs_corner_radius)), ) { Row( @@ -121,7 +123,7 @@ fun Tile( onClick = { tile.onClick(it) }, onLongClick = { tile.onLongClick(it) } ) - .tileModifier(state.colors), + .tileModifier(colors), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = tileHorizontalArrangement(iconOnly), ) { @@ -139,7 +141,7 @@ fun Tile( label = state.label.toString(), secondaryLabel = state.secondaryLabel.toString(), icon = icon, - colors = state.colors, + colors = colors, iconOnly = iconOnly, showLabels = showLabels, ) @@ -292,7 +294,7 @@ fun EditTile( modifier: Modifier = Modifier, ) { val label = tileViewModel.label.load() ?: tileViewModel.tileSpec.spec - val colors = ActiveTileColorAttributes + val colors = TileDefaults.inactiveTileColors() Row( modifier = modifier.tileModifier(colors).semantics { this.contentDescription = label }, @@ -361,10 +363,10 @@ private fun TileIcon( } @Composable -private fun Modifier.tileModifier(colors: TileColorAttributes): Modifier { +private fun Modifier.tileModifier(colors: TileColors): Modifier { return fillMaxWidth() .clip(RoundedCornerShape(dimensionResource(R.dimen.qs_corner_radius))) - .background(colorAttr(colors.background)) + .background(colors.background) .padding(horizontal = dimensionResource(id = R.dimen.qs_label_container_margin)) } @@ -387,7 +389,7 @@ private fun TileContent( label: String, secondaryLabel: String?, icon: Icon, - colors: TileColorAttributes, + colors: TileColors, iconOnly: Boolean, showLabels: Boolean = false, animateIconToEnd: Boolean = false, @@ -397,13 +399,13 @@ private fun TileContent( verticalArrangement = Arrangement.Center, modifier = Modifier.fillMaxHeight() ) { - TileIcon(icon, colorAttr(colors.icon), animateIconToEnd) + TileIcon(icon, colors.icon, animateIconToEnd) if (iconOnly && showLabels) { Text( label, maxLines = 2, - color = colorAttr(colors.label), + color = colors.label, overflow = TextOverflow.Ellipsis, textAlign = TextAlign.Center, ) @@ -414,13 +416,13 @@ private fun TileContent( Column(verticalArrangement = Arrangement.Center, modifier = Modifier.fillMaxHeight()) { Text( label, - color = colorAttr(colors.label), + color = colors.label, modifier = Modifier.basicMarquee(), ) if (!TextUtils.isEmpty(secondaryLabel)) { Text( secondaryLabel ?: "", - color = colorAttr(colors.secondaryLabel), + color = colors.secondaryLabel, modifier = Modifier.basicMarquee(), ) } @@ -431,12 +433,55 @@ private fun TileContent( @Composable fun tileHeight(iconWithLabel: Boolean = false): Dp { return if (iconWithLabel) { - TileDimensions.IconTileWithLabelHeight + TileDefaults.IconTileWithLabelHeight } else { dimensionResource(id = R.dimen.qs_tile_height) } } -private object TileDimensions { +private data class TileColors( + val background: Color, + val label: Color, + val secondaryLabel: Color, + val icon: Color, +) + +private object TileDefaults { val IconTileWithLabelHeight = 100.dp + + @Composable + fun activeTileColors(): TileColors = + TileColors( + background = MaterialTheme.colorScheme.primary, + label = MaterialTheme.colorScheme.onPrimary, + secondaryLabel = MaterialTheme.colorScheme.onPrimary, + icon = MaterialTheme.colorScheme.onPrimary, + ) + + @Composable + fun inactiveTileColors(): TileColors = + TileColors( + background = MaterialTheme.colorScheme.surfaceVariant, + label = MaterialTheme.colorScheme.onSurfaceVariant, + secondaryLabel = MaterialTheme.colorScheme.onSurfaceVariant, + icon = MaterialTheme.colorScheme.onSurfaceVariant, + ) + + @Composable + fun unavailableTileColors(): TileColors = + TileColors( + background = MaterialTheme.colorScheme.surface, + label = MaterialTheme.colorScheme.onSurface, + secondaryLabel = MaterialTheme.colorScheme.onSurface, + icon = MaterialTheme.colorScheme.onSurface, + ) + + @Composable + fun getColorForState(state: Int): TileColors { + return when (state) { + STATE_ACTIVE -> activeTileColors() + STATE_INACTIVE -> inactiveTileColors() + else -> unavailableTileColors() + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileColorAttributes.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileColorAttributes.kt deleted file mode 100644 index 1290bf34d1f1..000000000000 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileColorAttributes.kt +++ /dev/null @@ -1,61 +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.qs.panels.ui.viewmodel - -import android.service.quicksettings.Tile -import androidx.annotation.AttrRes -import com.android.systemui.plugins.qs.QSTile -import com.android.systemui.res.R - -data class TileColorAttributes( - @AttrRes val background: Int = 0, - @AttrRes val label: Int = 0, - @AttrRes val secondaryLabel: Int = 0, - @AttrRes val icon: Int = 0, -) - -val ActiveTileColorAttributes = - TileColorAttributes( - background = R.attr.shadeActive, - label = R.attr.onShadeActive, - secondaryLabel = R.attr.onShadeActiveVariant, - icon = R.attr.onShadeActive, - ) - -val InactiveTileColorAttributes = - TileColorAttributes( - background = R.attr.shadeInactive, - label = R.attr.onShadeInactive, - secondaryLabel = R.attr.onShadeInactiveVariant, - icon = R.attr.onShadeInactiveVariant, - ) - -val UnavailableTileColorAttributes = - TileColorAttributes( - background = R.attr.shadeDisabled, - label = R.attr.outline, - secondaryLabel = R.attr.outline, - icon = R.attr.outline, - ) - -fun QSTile.State.colors(): TileColorAttributes = - when (state) { - Tile.STATE_UNAVAILABLE -> UnavailableTileColorAttributes - Tile.STATE_ACTIVE -> ActiveTileColorAttributes - Tile.STATE_INACTIVE -> InactiveTileColorAttributes - else -> TileColorAttributes() - } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt index 58d07c368456..578a292deb7c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt @@ -22,7 +22,7 @@ import java.util.function.Supplier data class TileUiState( val label: CharSequence, val secondaryLabel: CharSequence, - val colors: TileColorAttributes, + val state: Int, val icon: Supplier<QSTile.Icon>, ) @@ -30,7 +30,7 @@ fun QSTile.State.toUiState(): TileUiState { return TileUiState( label ?: "", secondaryLabel ?: "", - colors(), + state, icon?.let { Supplier { icon } } ?: iconSupplier, ) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt index 762dacdfdddb..1143c304f594 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt @@ -19,7 +19,6 @@ package com.android.systemui.qs.tileimpl import android.animation.ArgbEvaluator import android.animation.PropertyValuesHolder import android.animation.ValueAnimator -import android.annotation.SuppressLint import android.content.Context import android.content.res.ColorStateList import android.content.res.Configuration @@ -38,7 +37,6 @@ import android.util.Log import android.util.TypedValue import android.view.Gravity import android.view.LayoutInflater -import android.view.MotionEvent import android.view.View import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent @@ -397,22 +395,15 @@ open class QSTileViewImpl @JvmOverloads constructor( override fun init(tile: QSTile) { val expandable = Expandable.fromView(this) - if (quickSettingsVisualHapticsLongpress()) { - isHapticFeedbackEnabled = false - longPressEffect?.qsTile = tile - longPressEffect?.expandable = expandable - init( - { _: View? -> longPressEffect?.onTileClick() }, - null, // Haptics and long-clicks will be handled by the [QSLongPressEffect] - ) - } else { - init( + init( { _: View? -> tile.click(expandable) }, { _: View? -> tile.longClick(expandable) true - }, - ) + } + ) + if (quickSettingsVisualHapticsLongpress()) { + isHapticFeedbackEnabled = false // Haptics will be handled by the [QSLongPressEffect] } } @@ -550,20 +541,6 @@ open class QSTileViewImpl @JvmOverloads constructor( return sb.toString() } - @SuppressLint("ClickableViewAccessibility") - override fun onTouchEvent(event: MotionEvent?): Boolean { - // let the View run the onTouch logic for click and long-click detection - val result = super.onTouchEvent(event) - if (longPressEffect != null) { - when (event?.actionMasked) { - MotionEvent.ACTION_DOWN -> longPressEffect.handleActionDown() - MotionEvent.ACTION_UP -> longPressEffect.handleActionUp() - MotionEvent.ACTION_CANCEL -> longPressEffect.handleActionCancel() - } - } - return result - } - // HANDLE STATE CHANGES RELATED METHODS protected open fun handleStateChanged(state: QSTile.State) { @@ -698,6 +675,7 @@ open class QSTileViewImpl @JvmOverloads constructor( // Long-press effects might have been enabled before but the new state does not // handle a long-press. In this case, we go back to the behaviour of a regular tile // and clean-up the resources + setOnTouchListener(null) unbindLongPressEffect() showRippleEffect = isClickable initialLongPressProperties = null diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java index 183c1a4a7ce7..b96e83d43e32 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java @@ -19,34 +19,53 @@ package com.android.systemui.qs.tiles; import android.content.Intent; import android.os.Handler; import android.os.Looper; +import android.os.UserManager; import android.provider.Settings; +import android.service.quicksettings.Tile; import androidx.annotation.Nullable; import com.android.internal.logging.MetricsLogger; import com.android.systemui.Flags; +import com.android.systemui.accessibility.hearingaid.HearingDevicesChecker; import com.android.systemui.accessibility.hearingaid.HearingDevicesDialogManager; import com.android.systemui.animation.Expandable; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.FalsingManager; -import com.android.systemui.plugins.qs.QSTile.State; +import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.res.R; +import com.android.systemui.statusbar.policy.BluetoothController; import javax.inject.Inject; /** Quick settings tile: Hearing Devices **/ -public class HearingDevicesTile extends QSTileImpl<State> { - +public class HearingDevicesTile extends QSTileImpl<BooleanState> { + //TODO(b/338520598): Transform the current implementation into new QS architecture + // and use Kotlin except Tile class. public static final String TILE_SPEC = "hearing_devices"; private final HearingDevicesDialogManager mDialogManager; + private final HearingDevicesChecker mDevicesChecker; + private final BluetoothController mBluetoothController; + + private final BluetoothController.Callback mCallback = new BluetoothController.Callback() { + @Override + public void onBluetoothStateChange(boolean enabled) { + refreshState(); + } + + @Override + public void onBluetoothDevicesChanged() { + refreshState(); + } + }; @Inject public HearingDevicesTile( @@ -59,16 +78,20 @@ public class HearingDevicesTile extends QSTileImpl<State> { StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, - HearingDevicesDialogManager hearingDevicesDialogManager - ) { + HearingDevicesDialogManager hearingDevicesDialogManager, + HearingDevicesChecker hearingDevicesChecker, + BluetoothController bluetoothController) { super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mDialogManager = hearingDevicesDialogManager; + mDevicesChecker = hearingDevicesChecker; + mBluetoothController = bluetoothController; + mBluetoothController.observe(getLifecycle(), mCallback); } @Override - public State newTileState() { - return new State(); + public BooleanState newTileState() { + return new BooleanState(); } @Override @@ -77,9 +100,28 @@ public class HearingDevicesTile extends QSTileImpl<State> { } @Override - protected void handleUpdateState(State state, Object arg) { + protected void handleUpdateState(BooleanState state, Object arg) { + checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_BLUETOOTH); + state.label = mContext.getString(R.string.quick_settings_hearing_devices_label); state.icon = ResourceIcon.get(R.drawable.qs_hearing_devices_icon); + state.forceExpandIcon = true; + + boolean isBonded = mDevicesChecker.isAnyPairedHearingDevice(); + boolean isActive = mDevicesChecker.isAnyActiveHearingDevice(); + + if (isActive) { + state.state = Tile.STATE_ACTIVE; + state.secondaryLabel = mContext.getString( + R.string.quick_settings_hearing_devices_connected); + } else if (isBonded) { + state.state = Tile.STATE_INACTIVE; + state.secondaryLabel = mContext.getString( + R.string.quick_settings_hearing_devices_disconnected); + } else { + state.state = Tile.STATE_INACTIVE; + state.secondaryLabel = ""; + } } @Nullable diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt index e6801022ad0e..70f3b847ce07 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt @@ -52,7 +52,6 @@ import com.android.systemui.screenrecord.RecordingService import com.android.systemui.settings.UserContextProvider import com.android.systemui.statusbar.phone.KeyguardDismissUtil import com.android.systemui.statusbar.policy.KeyguardStateController -import com.android.traceur.TraceUtils.PresetTraceType import java.util.concurrent.Executor import javax.inject.Inject @@ -131,15 +130,11 @@ constructor( } } - private fun startIssueRecordingService(screenRecord: Boolean, traceType: PresetTraceType) = + private fun startIssueRecordingService() = PendingIntent.getForegroundService( userContextProvider.userContext, RecordingService.REQUEST_CODE, - IssueRecordingService.getStartIntent( - userContextProvider.userContext, - screenRecord, - traceType - ), + IssueRecordingService.getStartIntent(userContextProvider.userContext), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) .send(BroadcastOptions.makeBasic().apply { isInteractive = true }.toBundle()) @@ -157,7 +152,7 @@ constructor( val dialog: AlertDialog = delegateFactory .create { - startIssueRecordingService(it.screenRecord, it.traceType) + startIssueRecordingService() dialogTransitionAnimator.disableAllCurrentDialogsExitAnimations() panelInteractor.collapsePanels() } @@ -169,8 +164,7 @@ constructor( if (expandable != null && !keyguardStateController.isShowing) { expandable .dialogTransitionController(DialogCuj(CUJ_SHADE_DIALOG_OPEN, TILE_SPEC)) - ?.let { dialogTransitionAnimator.show(dialog, it) } - ?: dialog.show() + ?.let { dialogTransitionAnimator.show(dialog, it) } ?: dialog.show() } else { dialog.show() } diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt index c7326b08e315..bb36fd5ea979 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt @@ -33,6 +33,7 @@ import com.android.systemui.plugins.qs.QSContainerController import com.android.systemui.qs.QSContainerImpl import com.android.systemui.qs.QSImpl import com.android.systemui.qs.dagger.QSSceneComponent +import com.android.systemui.qs.tiles.viewmodel.StubQSTileViewModel.state import com.android.systemui.res.R import com.android.systemui.settings.brightness.MirrorController import com.android.systemui.shade.domain.interactor.ShadeInteractor @@ -267,6 +268,7 @@ constructor( override val qqsHeight: Int get() = qsImpl.value?.qqsHeight ?: 0 + override val qsHeight: Int get() = qsImpl.value?.qsHeight ?: 0 @@ -375,8 +377,10 @@ constructor( qs.view.setPadding(0, 0, 0, 0) qs.setContainerController(this@QSSceneAdapterImpl) qs.applyState(state.value) + applyLatestExpansionAndSquishiness() } } + override fun setState(state: QSSceneAdapter.State) { this.state.value = state } diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt index 6cf2e52ff3d9..79cdfec182ae 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.qs.ui.viewmodel import androidx.lifecycle.LifecycleOwner @@ -28,12 +26,12 @@ import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor import com.android.systemui.qs.FooterActionsController import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel import com.android.systemui.qs.ui.adapter.QSSceneAdapter import com.android.systemui.scene.domain.interactor.SceneBackInteractor +import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.settings.brightness.ui.viewModel.BrightnessMirrorViewModel import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel @@ -41,7 +39,6 @@ import com.android.systemui.statusbar.notification.stack.ui.viewmodel.Notificati import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine @@ -55,7 +52,6 @@ class QuickSettingsSceneViewModel @Inject constructor( @Application private val applicationScope: CoroutineScope, - deviceEntryInteractor: DeviceEntryInteractor, val brightnessMirrorViewModel: BrightnessMirrorViewModel, val shadeHeaderViewModel: ShadeHeaderViewModel, val qsSceneAdapter: QSSceneAdapter, @@ -77,25 +73,15 @@ constructor( val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> = combine( - deviceEntryInteractor.isUnlocked, - deviceEntryInteractor.canSwipeToEnter, qsSceneAdapter.isCustomizerShowing, backScene, - ) { isUnlocked, canSwipeToDismiss, isCustomizerShowing, backScene -> - destinationScenes( - isUnlocked, - canSwipeToDismiss, - isCustomizerShowing, - backScene, - ) - } + transform = ::destinationScenes, + ) .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), initialValue = destinationScenes( - isUnlocked = deviceEntryInteractor.isUnlocked.value, - canSwipeToDismiss = deviceEntryInteractor.canSwipeToEnter.value, isCustomizing = qsSceneAdapter.isCustomizerShowing.value, backScene = backScene.value, ), @@ -104,18 +90,9 @@ constructor( val isMediaVisible: StateFlow<Boolean> = mediaCarouselInteractor.hasAnyMediaOrRecommendation private fun destinationScenes( - isUnlocked: Boolean, - canSwipeToDismiss: Boolean?, isCustomizing: Boolean, backScene: SceneKey?, ): Map<UserAction, UserActionResult> { - val upBottomEdge = - when { - canSwipeToDismiss == true -> Scenes.Lockscreen - isUnlocked -> Scenes.Gone - else -> Scenes.Lockscreen - } - return buildMap { if (isCustomizing) { // TODO(b/332749288) Empty map so there are no back handlers and back can close @@ -127,11 +104,8 @@ constructor( put(Back, UserActionResult(backScene ?: Scenes.Shade)) put(Swipe(SwipeDirection.Up), UserActionResult(backScene ?: Scenes.Shade)) put( - Swipe( - fromSource = Edge.Bottom, - direction = SwipeDirection.Up, - ), - UserActionResult(upBottomEdge), + Swipe(fromSource = Edge.Bottom, direction = SwipeDirection.Up), + UserActionResult(SceneFamilies.Home), ) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModel.kt index c1a56465064f..bd748d5c2174 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModel.kt @@ -17,30 +17,26 @@ package com.android.systemui.qs.ui.viewmodel import com.android.compose.animation.scene.Back -import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult import com.android.systemui.brightness.ui.viewmodel.BrightnessSliderViewModel import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.qs.panels.ui.viewmodel.EditModeViewModel import com.android.systemui.qs.panels.ui.viewmodel.TileGridViewModel import com.android.systemui.qs.ui.adapter.QSSceneAdapter +import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel import javax.inject.Inject -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.asStateFlow /** Models UI state and handles user input for the Quick Settings Shade scene. */ @SysUISingleton class QuickSettingsShadeSceneViewModel @Inject constructor( - @Application private val applicationScope: CoroutineScope, val overlayShadeViewModel: OverlayShadeViewModel, val brightnessSliderViewModel: BrightnessSliderViewModel, val tileGridViewModel: TileGridViewModel, @@ -48,18 +44,11 @@ constructor( val qsSceneAdapter: QSSceneAdapter, ) { val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> = - overlayShadeViewModel.backgroundScene - .map(::destinationScenes) - .stateIn( - scope = applicationScope, - started = SharingStarted.WhileSubscribed(), - initialValue = destinationScenes(overlayShadeViewModel.backgroundScene.value), + MutableStateFlow( + mapOf( + Swipe.Up to SceneFamilies.Home, + Back to SceneFamilies.Home, + ) ) - - private fun destinationScenes(backgroundScene: SceneKey): Map<UserAction, UserActionResult> { - return mapOf( - Swipe.Up to backgroundScene, - Back to backgroundScene, - ) - } + .asStateFlow() } diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt index 5ede64a4fc26..4a4c73ba9c81 100644 --- a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt +++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt @@ -35,8 +35,6 @@ import com.android.systemui.screenrecord.RecordingService import com.android.systemui.screenrecord.RecordingServiceStrings import com.android.systemui.settings.UserContextProvider import com.android.systemui.statusbar.phone.KeyguardDismissUtil -import com.android.traceur.MessageConstants.INTENT_EXTRA_TRACE_TYPE -import com.android.traceur.TraceUtils.PresetTraceType import java.util.concurrent.Executor import javax.inject.Inject @@ -76,15 +74,10 @@ constructor( when (intent?.action) { ACTION_START -> { bgExecutor.execute { - traceurMessageSender.startTracing( - intent.getSerializableExtra( - INTENT_EXTRA_TRACE_TYPE, - PresetTraceType::class.java - ) - ) + traceurMessageSender.startTracing(issueRecordingState.traceType) } issueRecordingState.isRecording = true - if (!intent.getBooleanExtra(EXTRA_SCREEN_RECORD, false)) { + if (!issueRecordingState.recordScreen) { // If we don't want to record the screen, the ACTION_SHOW_START_NOTIF action // will circumvent the RecordingService's screen recording start code. return super.onStartCommand(Intent(ACTION_SHOW_START_NOTIF), flags, startId) @@ -107,7 +100,7 @@ constructor( ) val screenRecording = intent.getParcelableExtra(EXTRA_PATH, Uri::class.java) - if (issueRecordingState.takeBugReport) { + if (issueRecordingState.takeBugreport) { iActivityManager.requestBugReportWithExtraAttachment(screenRecording) } else { traceurMessageSender.shareTraces(applicationContext, screenRecording) @@ -130,7 +123,6 @@ constructor( companion object { private const val TAG = "IssueRecordingService" private const val CHANNEL_ID = "issue_record" - private const val EXTRA_SCREEN_RECORD = "extra_screenRecord" /** * Get an intent to stop the issue recording service. @@ -148,35 +140,36 @@ constructor( * * @param context Context from the requesting activity */ - fun getStartIntent( - context: Context, - screenRecord: Boolean, - traceType: PresetTraceType, - ): Intent = - Intent(context, IssueRecordingService::class.java) - .setAction(ACTION_START) - .putExtra(EXTRA_SCREEN_RECORD, screenRecord) - .putExtra(INTENT_EXTRA_TRACE_TYPE, traceType) + fun getStartIntent(context: Context): Intent = + Intent(context, IssueRecordingService::class.java).setAction(ACTION_START) } } private class IrsStrings(private val res: Resources) : RecordingServiceStrings(res) { override val title get() = res.getString(R.string.issuerecord_title) + override val notificationChannelDescription get() = res.getString(R.string.issuerecord_channel_description) + override val startErrorResId get() = R.string.issuerecord_start_error + override val startError get() = res.getString(R.string.issuerecord_start_error) + override val saveErrorResId get() = R.string.issuerecord_save_error + override val saveError get() = res.getString(R.string.issuerecord_save_error) + override val ongoingRecording get() = res.getString(R.string.issuerecord_ongoing_screen_only) + override val backgroundProcessingLabel get() = res.getString(R.string.issuerecord_background_processing_label) + override val saveTitle get() = res.getString(R.string.issuerecord_save_title) } diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingState.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingState.kt index 12ed06d75ce3..4ea334522ad4 100644 --- a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingState.kt +++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingState.kt @@ -16,16 +16,51 @@ package com.android.systemui.recordissue +import android.content.Context import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.qs.tiles.RecordIssueTile +import com.android.systemui.res.R +import com.android.systemui.settings.UserFileManager +import com.android.systemui.settings.UserTracker +import com.android.traceur.TraceUtils.PresetTraceType import java.util.concurrent.CopyOnWriteArrayList import javax.inject.Inject @SysUISingleton -class IssueRecordingState @Inject constructor() { +class IssueRecordingState +@Inject +constructor( + userTracker: UserTracker, + userFileManager: UserFileManager, +) { - private val listeners = CopyOnWriteArrayList<Runnable>() + private val prefs = + userFileManager.getSharedPreferences( + RecordIssueTile.TILE_SPEC, + Context.MODE_PRIVATE, + userTracker.userId + ) + + var takeBugreport + get() = prefs.getBoolean(KEY_TAKE_BUG_REPORT, false) + set(value) = prefs.edit().putBoolean(KEY_TAKE_BUG_REPORT, value).apply() + + var recordScreen + get() = prefs.getBoolean(KEY_RECORD_SCREEN, false) + set(value) = prefs.edit().putBoolean(KEY_RECORD_SCREEN, value).apply() + + var hasUserApprovedScreenRecording + get() = prefs.getBoolean(HAS_APPROVED_SCREEN_RECORDING, false) + private set(value) = prefs.edit().putBoolean(HAS_APPROVED_SCREEN_RECORDING, value).apply() + + var issueTypeRes + get() = prefs.getInt(KEY_ISSUE_TYPE_RES, ISSUE_TYPE_NOT_SET) + set(value) = prefs.edit().putInt(KEY_ISSUE_TYPE_RES, value).apply() + + val traceType: PresetTraceType + get() = ALL_ISSUE_TYPES[issueTypeRes] ?: PresetTraceType.UNSET - var takeBugReport: Boolean = false + private val listeners = CopyOnWriteArrayList<Runnable>() var isRecording = false set(value) { @@ -33,6 +68,10 @@ class IssueRecordingState @Inject constructor() { listeners.forEach(Runnable::run) } + fun markUserApprovalForScreenRecording() { + hasUserApprovedScreenRecording = true + } + fun addListener(listener: Runnable) { listeners.add(listener) } @@ -40,4 +79,20 @@ class IssueRecordingState @Inject constructor() { fun removeListener(listener: Runnable) { listeners.remove(listener) } + + companion object { + private const val KEY_TAKE_BUG_REPORT = "key_takeBugReport" + private const val HAS_APPROVED_SCREEN_RECORDING = "HasApprovedScreenRecord" + private const val KEY_RECORD_SCREEN = "key_recordScreen" + const val KEY_ISSUE_TYPE_RES = "key_issueTypeRes" + const val ISSUE_TYPE_NOT_SET = -1 + + val ALL_ISSUE_TYPES: Map<Int, PresetTraceType> = + hashMapOf( + Pair(R.string.performance, PresetTraceType.PERFORMANCE), + Pair(R.string.user_interface, PresetTraceType.UI), + Pair(R.string.battery, PresetTraceType.BATTERY), + Pair(R.string.thermal, PresetTraceType.THERMAL) + ) + } } diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt index 84a063a36740..bbf4e51b35e9 100644 --- a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt +++ b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt @@ -17,7 +17,7 @@ package com.android.systemui.recordissue import android.annotation.SuppressLint -import android.app.AlertDialog +import android.app.AlertDialog.BUTTON_POSITIVE import android.content.Context import android.content.Intent import android.content.res.ColorStateList @@ -41,18 +41,16 @@ import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger import com.android.systemui.mediaprojection.SessionCreationSource import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDisabledDialogDelegate -import com.android.systemui.qs.tiles.RecordIssueTile +import com.android.systemui.recordissue.IssueRecordingState.Companion.ALL_ISSUE_TYPES +import com.android.systemui.recordissue.IssueRecordingState.Companion.ISSUE_TYPE_NOT_SET +import com.android.systemui.recordissue.IssueRecordingState.Companion.KEY_ISSUE_TYPE_RES import com.android.systemui.res.R -import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.phone.SystemUIDialog -import com.android.traceur.MessageConstants.INTENT_EXTRA_TRACE_TYPE -import com.android.traceur.TraceUtils.PresetTraceType import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import java.util.concurrent.Executor -import java.util.function.Consumer class RecordIssueDialogDelegate @AssistedInject @@ -64,31 +62,20 @@ constructor( @Main private val mainExecutor: Executor, private val devicePolicyResolver: dagger.Lazy<ScreenCaptureDevicePolicyResolver>, private val mediaProjectionMetricsLogger: MediaProjectionMetricsLogger, - private val userFileManager: UserFileManager, private val screenCaptureDisabledDialogDelegate: ScreenCaptureDisabledDialogDelegate, - private val issueRecordingState: IssueRecordingState, + private val state: IssueRecordingState, private val traceurMessageSender: TraceurMessageSender, - @Assisted private val onStarted: Consumer<IssueRecordingConfig>, + @Assisted private val onStarted: Runnable, ) : SystemUIDialog.Delegate { - private val issueTypeOptions: Map<Int, PresetTraceType> = - hashMapOf( - Pair(R.string.performance, PresetTraceType.PERFORMANCE), - Pair(R.string.user_interface, PresetTraceType.UI), - Pair(R.string.battery, PresetTraceType.BATTERY), - Pair(R.string.thermal, PresetTraceType.THERMAL) - ) - private var selectedIssueType: PresetTraceType? = null - /** To inject dependencies and allow for easier testing */ @AssistedFactory interface Factory { /** Create a dialog object */ - fun create(onStarted: Consumer<IssueRecordingConfig>): RecordIssueDialogDelegate + fun create(onStarted: Runnable): RecordIssueDialogDelegate } @SuppressLint("UseSwitchCompatOrMaterialCode") private lateinit var screenRecordSwitch: Switch - @SuppressLint("UseSwitchCompatOrMaterialCode") private lateinit var bugReportSwitch: Switch private lateinit var issueTypeButton: Button @MainThread @@ -97,21 +84,8 @@ constructor( setView(LayoutInflater.from(context).inflate(R.layout.record_issue_dialog, null)) setTitle(context.getString(R.string.qs_record_issue_label)) setIcon(R.drawable.qs_record_issue_icon_off) - setNegativeButton(R.string.cancel) { _, _ -> dismiss() } - setPositiveButton( - R.string.qs_record_issue_start, - { _, _ -> - issueRecordingState.takeBugReport = bugReportSwitch.isChecked - onStarted.accept( - IssueRecordingConfig( - screenRecordSwitch.isChecked, - selectedIssueType ?: PresetTraceType.UNSET - ) - ) - dismiss() - }, - false - ) + setNegativeButton(R.string.cancel) { _, _ -> } + setPositiveButton(R.string.qs_record_issue_start) { _, _ -> onStarted.run() } } bgExecutor.execute { traceurMessageSender.bindToTraceur(dialog.context) } } @@ -121,22 +95,39 @@ constructor( @MainThread override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) { dialog.apply { - window?.addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS) - window?.setGravity(Gravity.CENTER) + window?.apply { + addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS) + setGravity(Gravity.CENTER) + } - screenRecordSwitch = requireViewById(R.id.screenrecord_switch) - screenRecordSwitch.setOnCheckedChangeListener { _, isEnabled -> - if (isEnabled) { - bgExecutor.execute { onScreenRecordSwitchClicked() } + screenRecordSwitch = + requireViewById<Switch>(R.id.screenrecord_switch).apply { + isChecked = state.recordScreen + setOnCheckedChangeListener { _, isChecked -> + state.recordScreen = isChecked + if (isChecked) { + bgExecutor.execute { onScreenRecordSwitchClicked() } + } + } } + + requireViewById<Switch>(R.id.bugreport_switch).apply { + isChecked = state.takeBugreport + setOnCheckedChangeListener { _, isChecked -> state.takeBugreport = isChecked } } - bugReportSwitch = requireViewById(R.id.bugreport_switch) - val startButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE) - issueTypeButton = requireViewById(R.id.issue_type_button) - issueTypeButton.setOnClickListener { - onIssueTypeClicked(context) { startButton.isEnabled = true } - } - startButton.isEnabled = false + + issueTypeButton = + requireViewById<Button>(R.id.issue_type_button).apply { + val startButton = dialog.getButton(BUTTON_POSITIVE) + if (state.issueTypeRes != ISSUE_TYPE_NOT_SET) { + setText(state.issueTypeRes) + } else { + startButton.isEnabled = false + } + setOnClickListener { + onIssueTypeClicked(context) { startButton.isEnabled = true } + } + } } } @@ -160,19 +151,14 @@ constructor( SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER ) - if (flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)) { - val prefs = - userFileManager.getSharedPreferences( - RecordIssueTile.TILE_SPEC, - Context.MODE_PRIVATE, - userTracker.userId - ) - if (!prefs.getBoolean(HAS_APPROVED_SCREEN_RECORDING, false)) { - mainExecutor.execute { - ScreenCapturePermissionDialogDelegate(factory, prefs).createDialog().apply { - setOnCancelListener { screenRecordSwitch.isChecked = false } - show() - } + if ( + flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING) && + !state.hasUserApprovedScreenRecording + ) { + mainExecutor.execute { + ScreenCapturePermissionDialogDelegate(factory, state).createDialog().apply { + setOnCancelListener { screenRecordSwitch.isChecked = false } + show() } } } @@ -182,23 +168,21 @@ constructor( private fun onIssueTypeClicked(context: Context, onIssueTypeSelected: Runnable) { val popupMenu = PopupMenu(context, issueTypeButton) - issueTypeOptions.keys.forEach { + ALL_ISSUE_TYPES.keys.forEach { popupMenu.menu.add(it).apply { setIcon(R.drawable.arrow_pointing_down) - if (issueTypeOptions[it] != selectedIssueType) { + if (it != state.issueTypeRes) { iconTintList = ColorStateList.valueOf(Color.TRANSPARENT) } - intent = Intent().putExtra(INTENT_EXTRA_TRACE_TYPE, issueTypeOptions[it]) + intent = Intent().putExtra(KEY_ISSUE_TYPE_RES, it) } } popupMenu.apply { setOnMenuItemClickListener { issueTypeButton.text = it.title - selectedIssueType = - it.intent?.getSerializableExtra( - INTENT_EXTRA_TRACE_TYPE, - PresetTraceType::class.java - ) + state.issueTypeRes = + it.intent?.getIntExtra(KEY_ISSUE_TYPE_RES, ISSUE_TYPE_NOT_SET) + ?: ISSUE_TYPE_NOT_SET onIssueTypeSelected.run() true } diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/ScreenCapturePermissionDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/recordissue/ScreenCapturePermissionDialogDelegate.kt index de6d3f698285..b029d077b6d1 100644 --- a/packages/SystemUI/src/com/android/systemui/recordissue/ScreenCapturePermissionDialogDelegate.kt +++ b/packages/SystemUI/src/com/android/systemui/recordissue/ScreenCapturePermissionDialogDelegate.kt @@ -16,18 +16,15 @@ package com.android.systemui.recordissue -import android.content.SharedPreferences import android.os.Bundle import android.view.Gravity import android.view.WindowManager import com.android.systemui.res.R import com.android.systemui.statusbar.phone.SystemUIDialog -const val HAS_APPROVED_SCREEN_RECORDING = "HasApprovedScreenRecord" - class ScreenCapturePermissionDialogDelegate( private val dialogFactory: SystemUIDialog.Factory, - private val sharedPreferences: SharedPreferences, + private val state: IssueRecordingState, ) : SystemUIDialog.Delegate { override fun beforeCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) { @@ -37,7 +34,7 @@ class ScreenCapturePermissionDialogDelegate( setMessage(R.string.screenrecord_permission_dialog_warning_entire_screen) setNegativeButton(R.string.slice_permission_deny) { _, _ -> cancel() } setPositiveButton(R.string.slice_permission_allow) { _, _ -> - sharedPreferences.edit().putBoolean(HAS_APPROVED_SCREEN_RECORDING, true).apply() + state.markUserApprovalForScreenRecording() dismiss() } window?.addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS) diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/TraceurMessageSender.kt b/packages/SystemUI/src/com/android/systemui/recordissue/TraceurMessageSender.kt index 189336cf69bc..51744aa47c1a 100644 --- a/packages/SystemUI/src/com/android/systemui/recordissue/TraceurMessageSender.kt +++ b/packages/SystemUI/src/com/android/systemui/recordissue/TraceurMessageSender.kt @@ -93,7 +93,7 @@ class TraceurMessageSender @Inject constructor(@Background private val backgroun } @WorkerThread - fun startTracing(traceType: PresetTraceType?) { + fun startTracing(traceType: PresetTraceType) { val data = Bundle().apply { putSerializable(MessageConstants.INTENT_EXTRA_TRACE_TYPE, traceType) } notifyTraceur(MessageConstants.START_WHAT, data) diff --git a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt index 7a9d09ad815a..da239360a644 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt @@ -18,6 +18,7 @@ package com.android.systemui.scene import com.android.systemui.CoreStartable import com.android.systemui.notifications.ui.composable.NotificationsShadeSessionModule +import com.android.systemui.scene.domain.SceneDomainModule import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor import com.android.systemui.scene.domain.startable.SceneContainerStartable import com.android.systemui.scene.domain.startable.ScrimStartable @@ -40,6 +41,7 @@ import dagger.multibindings.IntoMap NotificationsShadeSessionModule::class, QuickSettingsSceneModule::class, ShadeSceneModule::class, + SceneDomainModule::class, ], ) interface KeyguardlessSceneContainerFrameworkModule { diff --git a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt index 7e6dfb8762cd..a0cf82a28406 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt @@ -19,6 +19,7 @@ package com.android.systemui.scene import com.android.systemui.CoreStartable import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlagsModule import com.android.systemui.notifications.ui.composable.NotificationsShadeSessionModule +import com.android.systemui.scene.domain.SceneDomainModule import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor import com.android.systemui.scene.domain.startable.SceneContainerStartable import com.android.systemui.scene.domain.startable.ScrimStartable @@ -46,6 +47,7 @@ import dagger.multibindings.IntoMap QuickSettingsShadeSceneModule::class, NotificationsShadeSceneModule::class, NotificationsShadeSessionModule::class, + SceneDomainModule::class, ], ) interface SceneContainerFrameworkModule { diff --git a/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt index b918277bd3a4..a326ec1b53b3 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt @@ -16,6 +16,7 @@ package com.android.systemui.scene +import com.android.systemui.scene.domain.SceneDomainModule import com.android.systemui.scene.shared.model.SceneContainerConfig import com.android.systemui.scene.shared.model.Scenes import dagger.Module @@ -29,6 +30,7 @@ import dagger.Provides EmptySceneModule::class, GoneSceneModule::class, LockscreenSceneModule::class, + SceneDomainModule::class, ], ) object ShadelessSceneContainerFrameworkModule { diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/SceneDomainModule.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/SceneDomainModule.kt new file mode 100644 index 000000000000..9b2a6dd9dcc2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/SceneDomainModule.kt @@ -0,0 +1,30 @@ +/* + * 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.scene.domain + +import com.android.systemui.scene.domain.resolver.HomeSceneFamilyResolverModule +import com.android.systemui.scene.domain.resolver.SceneResolverModule +import dagger.Module + +@Module( + includes = + [ + HomeSceneFamilyResolverModule::class, + SceneResolverModule::class, + ] +) +object SceneDomainModule diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt index b1700e377725..2f66d6bb7be1 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt @@ -23,9 +23,12 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor import com.android.systemui.scene.data.repository.SceneContainerRepository +import com.android.systemui.scene.domain.resolver.SceneResolver import com.android.systemui.scene.shared.logger.SceneLogger +import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.util.kotlin.pairwiseBy +import dagger.Lazy import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -52,6 +55,7 @@ constructor( @Application private val applicationScope: CoroutineScope, private val repository: SceneContainerRepository, private val logger: SceneLogger, + private val sceneFamilyResolvers: Lazy<Map<SceneKey, @JvmSuppressWildcards SceneResolver>>, private val deviceUnlockedInteractor: DeviceUnlockedInteractor, ) { @@ -180,10 +184,11 @@ constructor( sceneState: Any? = null, ) { val currentSceneKey = currentScene.value + val resolvedScene = sceneFamilyResolvers.get()[toScene]?.resolvedScene?.value ?: toScene if ( !validateSceneChange( from = currentSceneKey, - to = toScene, + to = resolvedScene, loggingReason = loggingReason, ) ) { @@ -192,13 +197,13 @@ constructor( logger.logSceneChangeRequested( from = currentSceneKey, - to = toScene, + to = resolvedScene, reason = loggingReason, isInstant = false, ) - onSceneAboutToChangeListener.forEach { it.onSceneAboutToChange(toScene, sceneState) } - repository.changeScene(toScene, transitionKey) + onSceneAboutToChangeListener.forEach { it.onSceneAboutToChange(resolvedScene, sceneState) } + repository.changeScene(resolvedScene, transitionKey) } /** @@ -212,10 +217,11 @@ constructor( loggingReason: String, ) { val currentSceneKey = currentScene.value + val resolvedScene = sceneFamilyResolvers.get()[toScene]?.resolvedScene?.value ?: toScene if ( !validateSceneChange( from = currentSceneKey, - to = toScene, + to = resolvedScene, loggingReason = loggingReason, ) ) { @@ -224,12 +230,12 @@ constructor( logger.logSceneChangeRequested( from = currentSceneKey, - to = toScene, + to = resolvedScene, reason = loggingReason, isInstant = true, ) - repository.snapToScene(toScene) + repository.snapToScene(resolvedScene) } /** @@ -288,6 +294,13 @@ constructor( repository.setTransitionState(transitionState) } + /** + * Returns the [concrete scene][Scenes] for [sceneKey] if it is a [scene family][SceneFamilies], + * otherwise returns a singleton [Flow] containing [sceneKey]. + */ + fun resolveSceneFamily(sceneKey: SceneKey): Flow<SceneKey> = + sceneFamilyResolvers.get()[sceneKey]?.resolvedScene ?: flowOf(sceneKey) + private fun isVisibleInternal( raw: Boolean = repository.isVisible.value, isRemoteUserInteractionOngoing: Boolean = repository.isRemoteUserInteractionOngoing.value, diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt new file mode 100644 index 000000000000..f19929cc51a3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.scene.domain.resolver + +import com.android.compose.animation.scene.SceneKey +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor +import com.android.systemui.scene.shared.model.SceneFamilies +import com.android.systemui.scene.shared.model.Scenes +import dagger.Binds +import dagger.Module +import dagger.multibindings.IntoSet +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn + +/** + * Resolver for [SceneFamilies.Home]. The "home" scene family resolves to the scene that is + * currently underneath any "overlay" scene, such as shades or bouncer. + */ +@SysUISingleton +class HomeSceneFamilyResolver +@Inject +constructor( + @Application private val applicationScope: CoroutineScope, + deviceEntryInteractor: DeviceEntryInteractor, +) : SceneResolver { + override val targetFamily: SceneKey = SceneFamilies.Home + + override val resolvedScene: StateFlow<SceneKey> = + combine( + deviceEntryInteractor.canSwipeToEnter, + deviceEntryInteractor.isUnlocked, + transform = ::homeScene, + ) + .stateIn( + scope = applicationScope, + started = SharingStarted.WhileSubscribed(), + initialValue = + homeScene( + deviceEntryInteractor.canSwipeToEnter.value, + deviceEntryInteractor.isUnlocked.value, + ) + ) + + private fun homeScene(canSwipeToEnter: Boolean?, isUnlocked: Boolean): SceneKey = + when { + canSwipeToEnter == true -> Scenes.Lockscreen + isUnlocked -> Scenes.Gone + else -> Scenes.Lockscreen + } +} + +@Module +interface HomeSceneFamilyResolverModule { + @Binds @IntoSet fun provideSceneResolver(interactor: HomeSceneFamilyResolver): SceneResolver +} diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/SceneResolver.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/SceneResolver.kt new file mode 100644 index 000000000000..837252995e7d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/SceneResolver.kt @@ -0,0 +1,45 @@ +/* + * 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.scene.domain.resolver + +import com.android.compose.animation.scene.SceneKey +import dagger.Module +import dagger.Provides +import dagger.multibindings.Multibinds +import kotlinx.coroutines.flow.StateFlow + +/** Resolves [concrete scenes][Scenes] from a [scene family][SceneFamilies]. */ +interface SceneResolver { + /** The scene family that this resolves. */ + val targetFamily: SceneKey + + /** The concrete scene that [targetFamily] is currently resolved to. */ + val resolvedScene: StateFlow<SceneKey> +} + +@Module +interface SceneResolverModule { + + @Multibinds fun resolverSet(): Set<@JvmSuppressWildcards SceneResolver> + + companion object { + @Provides + fun provideResolverMap( + resolverSet: Set<@JvmSuppressWildcards SceneResolver> + ): Map<SceneKey, SceneResolver> = resolverSet.associateBy { it.targetFamily } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt index 09c80b09a388..ab24e0bbb690 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt @@ -34,6 +34,8 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow 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 /** Models UI state for the scene container. */ @@ -61,7 +63,9 @@ constructor( val isVisible: StateFlow<Boolean> = sceneInteractor.isVisible private val destinationScenesBySceneKey = - scenes.associate { scene -> scene.key to scene.destinationScenes } + scenes.associate { scene -> + scene.key to scene.destinationScenes.flatMapLatestConflated { replaceSceneFamilies(it) } + } fun currentDestinationScenes( scope: CoroutineScope, @@ -140,7 +144,24 @@ constructor( val fromLockscreenScene = currentScene.value == Scenes.Lockscreen !fromLockscreenScene || !isFalseTouch - } - ?: true + } ?: true + } + + private fun replaceSceneFamilies( + destinationScenes: Map<UserAction, UserActionResult>, + ): Flow<Map<UserAction, UserActionResult>> { + return destinationScenes + .mapValues { (_, actionResult) -> + sceneInteractor.resolveSceneFamily(actionResult.toScene).map { scene -> + actionResult.copy(toScene = scene) + } + } + .combineValueFlows() } } + +private fun <K, V> Map<K, Flow<V>>.combineValueFlows(): Flow<Map<K, V>> = + combine( + asIterable().map { (k, fv) -> fv.map { k to it } }, + transform = Array<Pair<K, V>>::toMap, + ) diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt index 80aa0efb0a19..4f27b9e4dbf0 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt @@ -79,7 +79,10 @@ class PolicyRequestProcessor( } /** Produce a new [ScreenshotData] using [CaptureParameters] */ - suspend fun modify(original: ScreenshotData, updates: CaptureParameters): ScreenshotData { + private suspend fun modify( + original: ScreenshotData, + updates: CaptureParameters, + ): ScreenshotData { // Update and apply bitmap capture depending on the parameters. val updated = when (val type = updates.type) { @@ -117,7 +120,7 @@ class PolicyRequestProcessor( return replaceWithScreenshot( original = original, componentName = topMainRootTask?.topActivity ?: defaultComponent, - owner = topMainRootTask?.userId?.let { UserHandle.of(it) } ?: defaultOwner, + owner = defaultOwner, displayId = original.displayId ) } diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt index bf0843b8fa4e..2def6c7cfdc2 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt @@ -157,9 +157,15 @@ constructor( private var anyBouncerShowing = false /** - * True if the shade is fully expanded, meaning the hub should not receive any touch input. + * True if the shade is fully expanded and the user is not interacting with it anymore, meaning + * the hub should not receive any touch input. * - * Tracks [ShadeInteractor.isAnyFullyExpanded]. + * We need to not pause the touch handling lifecycle as soon as the shade opens because if the + * user swipes down, then back up without lifting their finger, the lifecycle will be paused + * then resumed, and resuming force-stops all active touch sessions. This means the shade will + * not receive the end of the gesture and will be stuck open. + * + * Based on [ShadeInteractor.isAnyFullyExpanded] and [ShadeInteractor.isUserInteracting]. */ private var shadeShowing = false diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index 6efa6334b968..c01b7b6f4883 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -138,6 +138,11 @@ public class NotificationShadeWindowViewController implements Dumpable { private final PanelExpansionInteractor mPanelExpansionInteractor; private final ShadeExpansionStateManager mShadeExpansionStateManager; + /** + * If {@code true}, an external touch sent in {@link #handleExternalTouch(MotionEvent)} has been + * intercepted and all future touch events for the gesture should be processed by this view. + */ + private boolean mExternalTouchIntercepted = false; private boolean mIsTrackingBarGesture = false; private boolean mIsOcclusionTransitionRunning = false; private DisableSubpixelTextTransitionListener mDisableSubpixelTextTransitionListener; @@ -255,11 +260,28 @@ public class NotificationShadeWindowViewController implements Dumpable { } /** - * Handle a touch event while dreaming by forwarding the event to the content view. + * Handle a touch event while dreaming or on the hub by forwarding the event to the content + * view. + * <p> + * Since important logic for handling touches lives in the dispatch/intercept phases, we + * simulate going through all of these stages before sending onTouchEvent if intercepted. + * * @param event The event to forward. */ - public void handleDreamTouch(MotionEvent event) { - mView.dispatchTouchEvent(event); + public void handleExternalTouch(MotionEvent event) { + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + mExternalTouchIntercepted = false; + } + + if (!mView.dispatchTouchEvent(event)) { + return; + } + if (!mExternalTouchIntercepted) { + mExternalTouchIntercepted = mView.onInterceptTouchEvent(event); + } + if (mExternalTouchIntercepted) { + mView.onTouchEvent(event); + } } /** Inflates the {@link R.layout#status_bar_expanded} layout and sets it up. */ diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt index 884ccef3a080..ac1f97172c0e 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt @@ -17,16 +17,14 @@ package com.android.systemui.shade import android.view.MotionEvent -import com.android.compose.animation.scene.SceneKey import com.android.systemui.assist.AssistManager import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor -import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor import com.android.systemui.log.LogBuffer import com.android.systemui.log.dagger.ShadeTouchLog import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.TransitionKeys.SlightlyFasterShadeCollapse import com.android.systemui.shade.ShadeController.ShadeVisibilityListener @@ -61,8 +59,6 @@ constructor( @Background private val scope: CoroutineScope, private val shadeInteractor: ShadeInteractor, private val sceneInteractor: SceneInteractor, - private val deviceEntryInteractor: DeviceEntryInteractor, - private val deviceUnlockedInteractor: DeviceUnlockedInteractor, private val notificationStackScrollLayout: NotificationStackScrollLayout, @ShadeTouchLog private val touchLog: LogBuffer, private val vibratorHelper: VibratorHelper, @@ -100,7 +96,7 @@ constructor( override fun instantCollapseShade() { sceneInteractor.snapToScene( - getCollapseDestinationScene(), + SceneFamilies.Home, "hide shade", ) } @@ -140,24 +136,12 @@ constructor( private fun animateCollapseShadeInternal() { sceneInteractor.changeScene( - getCollapseDestinationScene(), // TODO(b/336581871): add sceneState? + SceneFamilies.Home, // TODO(b/336581871): add sceneState? "ShadeController.animateCollapseShade", SlightlyFasterShadeCollapse, ) } - private fun getCollapseDestinationScene(): SceneKey { - // Always check whether device is unlocked before transitioning to gone scene. - return if ( - deviceUnlockedInteractor.deviceUnlockStatus.value.isUnlocked && - deviceEntryInteractor.isDeviceEntered.value - ) { - Scenes.Gone - } else { - Scenes.Lockscreen - } - } - override fun cancelExpansionAndCollapseShade() { // TODO do we need to actually cancel the touch session? animateCollapseShade() diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt index 55bd8c6c0834..3a483f460db7 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt @@ -18,6 +18,7 @@ package com.android.systemui.shade.domain.interactor import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.shared.model.ShadeMode import javax.inject.Inject @@ -36,11 +37,7 @@ constructor( if (shadeInteractor.isQsExpanded.value) { val key = if (fullyCollapse || shadeInteractor.shadeMode.value is ShadeMode.Dual) { - if (deviceEntryInteractor.isDeviceEntered.value) { - Scenes.Gone - } else { - Scenes.Lockscreen - } + SceneFamilies.Home } else { Scenes.Shade } diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt index b8dd62897587..0314091e792e 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt @@ -19,49 +19,41 @@ package com.android.systemui.shade.ui.viewmodel import com.android.compose.animation.scene.SceneKey import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes import javax.inject.Inject import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn /** * Models UI state and handles user input for the overlay shade UI, which shows a shade as an * overlay on top of another scene UI. */ -@OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton class OverlayShadeViewModel @Inject constructor( - @Application private val applicationScope: CoroutineScope, + @Application applicationScope: CoroutineScope, private val sceneInteractor: SceneInteractor, - deviceEntryInteractor: DeviceEntryInteractor, ) { /** The scene to show in the background when the overlay shade is open. */ val backgroundScene: StateFlow<SceneKey> = - deviceEntryInteractor.isDeviceEntered - .map(::backgroundScene) + sceneInteractor + .resolveSceneFamily(SceneFamilies.Home) .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), - initialValue = backgroundScene(deviceEntryInteractor.isDeviceEntered.value) + initialValue = Scenes.Lockscreen, ) /** Notifies that the user has clicked the semi-transparent background scrim. */ fun onScrimClicked() { sceneInteractor.changeScene( - toScene = backgroundScene.value, + toScene = SceneFamilies.Home, loggingReason = "Shade scrim clicked", ) } - - private fun backgroundScene(isDeviceEntered: Boolean): SceneKey { - return if (isDeviceEntered) Scenes.Gone else Scenes.Lockscreen - } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt index e4a2424e1ead..b0100b9642c2 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt @@ -26,12 +26,12 @@ import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor import com.android.systemui.qs.FooterActionsController import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel import com.android.systemui.qs.ui.adapter.QSSceneAdapter import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade import com.android.systemui.settings.brightness.ui.viewModel.BrightnessMirrorViewModel @@ -39,6 +39,7 @@ import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel import com.android.systemui.unfold.domain.interactor.UnfoldTransitionInteractor +import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject import kotlinx.coroutines.CoroutineScope @@ -47,6 +48,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn @@ -56,7 +58,6 @@ class ShadeSceneViewModel @Inject constructor( @Application private val applicationScope: CoroutineScope, - deviceEntryInteractor: DeviceEntryInteractor, val qsSceneAdapter: QSSceneAdapter, val shadeHeaderViewModel: ShadeHeaderViewModel, val notifications: NotificationsPlaceholderViewModel, @@ -70,16 +71,12 @@ constructor( ) { val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> = combine( - deviceEntryInteractor.isUnlocked, - deviceEntryInteractor.canSwipeToEnter, shadeInteractor.shadeMode, - qsSceneAdapter.isCustomizerShowing - ) { isUnlocked, canSwipeToDismiss, shadeMode, isCustomizerShowing -> + qsSceneAdapter.isCustomizerShowing, + ) { shadeMode, isCustomizerShowing -> destinationScenes( - isUnlocked = isUnlocked, - canSwipeToDismiss = canSwipeToDismiss, shadeMode = shadeMode, - isCustomizing = isCustomizerShowing + isCustomizing = isCustomizerShowing, ) } .stateIn( @@ -87,8 +84,6 @@ constructor( started = SharingStarted.WhileSubscribed(), initialValue = destinationScenes( - isUnlocked = deviceEntryInteractor.isUnlocked.value, - canSwipeToDismiss = deviceEntryInteractor.canSwipeToEnter.value, shadeMode = shadeInteractor.shadeMode.value, isCustomizing = qsSceneAdapter.isCustomizerShowing.value, ), @@ -100,6 +95,9 @@ constructor( /** Whether or not the shade container should be clickable. */ val isClickable: StateFlow<Boolean> = upDestinationSceneKey + .flatMapLatestConflated { key -> + key?.let { sceneInteractor.resolveSceneFamily(key) } ?: flowOf(null) + } .map { it == Scenes.Lockscreen } .stateIn( scope = applicationScope, @@ -138,27 +136,22 @@ constructor( } private fun destinationScenes( - isUnlocked: Boolean, - canSwipeToDismiss: Boolean?, shadeMode: ShadeMode, isCustomizing: Boolean, ): Map<UserAction, UserActionResult> { - val up = - when { - canSwipeToDismiss == true -> Scenes.Lockscreen - isUnlocked -> Scenes.Gone - else -> Scenes.Lockscreen - } - - val upTransitionKey = ToSplitShade.takeIf { shadeMode is ShadeMode.Split } - - val down = Scenes.QuickSettings.takeIf { shadeMode is ShadeMode.Single } - return buildMap { if (!isCustomizing) { - this[Swipe(SwipeDirection.Up)] = UserActionResult(up, upTransitionKey) + set( + Swipe(SwipeDirection.Up), + UserActionResult( + SceneFamilies.Home, + ToSplitShade.takeIf { shadeMode is ShadeMode.Split } + ) + ) } // TODO(b/330200163) Add an else to be able to collapse the shade while customizing - down?.let { this[Swipe(SwipeDirection.Down)] = UserActionResult(down) } + if (shadeMode is ShadeMode.Single) { + set(Swipe(SwipeDirection.Down), UserActionResult(Scenes.QuickSettings)) + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java index c742f6413022..5c4a63cdb993 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java @@ -455,7 +455,7 @@ public final class KeyboardShortcuts { if (mReceivedAppShortcutGroups == null || mReceivedImeShortcutGroups == null) { return; } - List<KeyboardShortcutGroup> shortcutGroups = mReceivedAppShortcutGroups; + List<KeyboardShortcutGroup> shortcutGroups = new ArrayList<>(mReceivedAppShortcutGroups); shortcutGroups.addAll(mReceivedImeShortcutGroups); mReceivedAppShortcutGroups = null; mReceivedImeShortcutGroups = null; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 47939ae07539..337ffa412e31 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -20,6 +20,7 @@ import static android.adaptiveauth.Flags.enableAdaptiveAuth; import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED; import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_MANAGEMENT_DISCLOSURE; import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_NAMED_MANAGEMENT_DISCLOSURE; +import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_START; import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK; import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_TIMEOUT; import static android.hardware.biometrics.BiometricSourceType.FACE; @@ -1296,6 +1297,12 @@ public class KeyguardIndicationController { @Override public void onBiometricAcquired(BiometricSourceType biometricSourceType, int acquireInfo) { if (biometricSourceType == FACE) { + if (acquireInfo == FACE_ACQUIRED_START) { + // Let's hide any previous messages when authentication starts, otherwise + // multiple auth attempts would overlap. + hideBiometricMessage(); + mBiometricErrorMessageToShowOnScreenOn = null; + } mFaceAcquiredMessageDeferral.processFrame(acquireInfo); } } @@ -1485,13 +1492,6 @@ public class KeyguardIndicationController { @Override public void onBiometricRunningStateChanged(boolean running, BiometricSourceType biometricSourceType) { - if (running && biometricSourceType == FACE) { - // Let's hide any previous messages when authentication starts, otherwise - // multiple auth attempts would overlap. - hideBiometricMessage(); - mBiometricErrorMessageToShowOnScreenOn = null; - } - if (!running && biometricSourceType == FACE) { showTrustAgentErrorMessage(mTrustAgentErrorMessage); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java index 6d34a0fa9c24..04a413acdf0b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java @@ -303,7 +303,12 @@ public class NotificationMediaManager implements Dumpable { // TODO(b/169655907): get the semi-filtered notifications for current user Collection<NotificationEntry> allNotifications = mNotifPipeline.getAllNotifs(); if (notificationMediaManagerBackgroundExecution()) { - mBackgroundExecutor.execute(() -> findPlayingMediaNotification(allNotifications)); + // Create new sbn list to be accessed in background thread. + List<StatusBarNotification> statusBarNotifications = new ArrayList<>(); + for (NotificationEntry entry: allNotifications) { + statusBarNotifications.add(entry.getSbn()); + } + mBackgroundExecutor.execute(() -> findPlayingMediaNotification(statusBarNotifications)); } else { findPlayingMediaNotification(allNotifications); } @@ -341,6 +346,51 @@ public class NotificationMediaManager implements Dumpable { } } + StatusBarNotification statusBarNotification = null; + if (mediaNotification != null) { + statusBarNotification = mediaNotification.getSbn(); + } + setUpControllerAndKey(controller, statusBarNotification); + } + + /** + * Find a notification and media controller associated with the playing media session, and + * update this manager's internal state. + * This method must be called in background. + * TODO(b/273443374) check this method + */ + void findPlayingMediaNotification(@NonNull List<StatusBarNotification> allNotifications) { + // Promote the media notification with a controller in 'playing' state, if any. + StatusBarNotification statusBarNotification = null; + MediaController controller = null; + for (StatusBarNotification sbn : allNotifications) { + Notification notif = sbn.getNotification(); + if (notif.isMediaNotification()) { + final MediaSession.Token token = + sbn.getNotification().extras.getParcelable( + Notification.EXTRA_MEDIA_SESSION, MediaSession.Token.class); + if (token != null) { + MediaController aController = new MediaController(mContext, token); + if (PlaybackState.STATE_PLAYING + == getMediaControllerPlaybackState(aController)) { + if (DEBUG_MEDIA) { + Log.v(TAG, "DEBUG_MEDIA: found mediastyle controller matching " + + sbn.getKey()); + } + statusBarNotification = sbn; + controller = aController; + break; + } + } + } + } + + setUpControllerAndKey(controller, statusBarNotification); + } + + private void setUpControllerAndKey( + MediaController controller, + StatusBarNotification mediaNotification) { if (controller != null && !sameSessions(mMediaController, controller)) { // We have a new media session clearCurrentMediaNotificationSession(); @@ -354,8 +404,8 @@ public class NotificationMediaManager implements Dumpable { } if (mediaNotification != null - && !mediaNotification.getSbn().getKey().equals(mMediaNotificationKey)) { - mMediaNotificationKey = mediaNotification.getSbn().getKey(); + && !mediaNotification.getKey().equals(mMediaNotificationKey)) { + mMediaNotificationKey = mediaNotification.getKey(); if (DEBUG_MEDIA) { Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key=" + mMediaNotificationKey); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index f8193a4a1b93..d0702fcc0c5e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -27,6 +27,7 @@ import android.app.ActivityManager; import android.app.Notification; import android.content.Context; import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; @@ -35,6 +36,7 @@ import android.graphics.Color; import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; import android.graphics.Rect; +import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.os.Trace; @@ -94,6 +96,8 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi public static final int STATE_DOT = 1; public static final int STATE_HIDDEN = 2; + public static final float APP_ICON_SCALE = .75f; + @Retention(RetentionPolicy.SOURCE) @IntDef({STATE_ICON, STATE_DOT, STATE_HIDDEN}) public @interface VisibleState { } @@ -499,7 +503,12 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi userId = UserHandle.USER_SYSTEM; } - Drawable icon = statusBarIcon.icon.loadDrawableAsUser(context, userId); + // Try to load the monochrome app icon if applicable + Drawable icon = maybeGetMonochromeAppIcon(context, statusBarIcon); + // Otherwise, just use the icon normally + if (icon == null) { + icon = statusBarIcon.icon.loadDrawableAsUser(context, userId); + } TypedValue typedValue = new TypedValue(); sysuiContext.getResources().getValue(R.dimen.status_bar_icon_scale_factor, @@ -526,6 +535,26 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi return new ScalingDrawableWrapper(icon, scaleFactor); } + @Nullable + private Drawable maybeGetMonochromeAppIcon(Context context, + StatusBarIcon statusBarIcon) { + if (android.app.Flags.notificationsUseMonochromeAppIcon() + && statusBarIcon.type == StatusBarIcon.Type.MaybeMonochromeAppIcon) { + // Check if we have a monochrome app icon + PackageManager pm = context.getPackageManager(); + Drawable appIcon = context.getApplicationInfo().loadIcon(pm); + if (appIcon instanceof AdaptiveIconDrawable) { + Drawable monochrome = ((AdaptiveIconDrawable) appIcon).getMonochrome(); + if (monochrome != null) { + setCropToPadding(true); + setScaleType(ScaleType.CENTER); + return new ScalingDrawableWrapper(monochrome, APP_ICON_SCALE); + } + } + } + return null; + } + public StatusBarIcon getStatusBarIcon() { return mIcon; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt index 2f293e072c84..f62b24aa96a3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt @@ -18,33 +18,29 @@ package com.android.systemui.statusbar.notification import android.content.Context import android.provider.DeviceConfig - import com.android.internal.annotations.VisibleForTesting import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE import com.android.systemui.statusbar.notification.stack.BUCKET_HEADS_UP import com.android.systemui.statusbar.notification.stack.BUCKET_MEDIA_CONTROLS import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE -import com.android.systemui.statusbar.notification.stack.BUCKET_PRIORITY_PEOPLE import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT +import com.android.systemui.statusbar.notification.stack.PriorityBucket import com.android.systemui.util.DeviceConfigProxy import com.android.systemui.util.Utils - import javax.inject.Inject private var sUsePeopleFiltering: Boolean? = null -/** - * Feature controller for the NOTIFICATIONS_USE_PEOPLE_FILTERING config. - */ +/** Feature controller for the NOTIFICATIONS_USE_PEOPLE_FILTERING config. */ @SysUISingleton -class NotificationSectionsFeatureManager @Inject constructor( - val proxy: DeviceConfigProxy, - val context: Context -) { +class NotificationSectionsFeatureManager +@Inject +constructor(val proxy: DeviceConfigProxy, val context: Context) { fun isFilteringEnabled(): Boolean { return usePeopleFiltering(proxy) @@ -55,30 +51,37 @@ class NotificationSectionsFeatureManager @Inject constructor( } fun getNotificationBuckets(): IntArray { - if (PriorityPeopleSection.isEnabled) { + if (PriorityPeopleSection.isEnabled || NotificationMinimalismPrototype.V2.isEnabled) { // We don't need this list to be adaptive, it can be the superset of all features. - return intArrayOf( - BUCKET_MEDIA_CONTROLS, + return PriorityBucket.getAllInOrder() + } + return when { + isFilteringEnabled() && isMediaControlsEnabled() -> + intArrayOf( BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, - BUCKET_PRIORITY_PEOPLE, + BUCKET_MEDIA_CONTROLS, BUCKET_PEOPLE, BUCKET_ALERTING, - BUCKET_SILENT, + BUCKET_SILENT ) - } - return when { - isFilteringEnabled() && isMediaControlsEnabled() -> - intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_MEDIA_CONTROLS, - BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT) !isFilteringEnabled() && isMediaControlsEnabled() -> - intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_MEDIA_CONTROLS, - BUCKET_ALERTING, BUCKET_SILENT) + intArrayOf( + BUCKET_HEADS_UP, + BUCKET_FOREGROUND_SERVICE, + BUCKET_MEDIA_CONTROLS, + BUCKET_ALERTING, + BUCKET_SILENT + ) isFilteringEnabled() && !isMediaControlsEnabled() -> - intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_PEOPLE, - BUCKET_ALERTING, BUCKET_SILENT) - else -> - intArrayOf(BUCKET_ALERTING, BUCKET_SILENT) + intArrayOf( + BUCKET_HEADS_UP, + BUCKET_FOREGROUND_SERVICE, + BUCKET_PEOPLE, + BUCKET_ALERTING, + BUCKET_SILENT + ) + else -> intArrayOf(BUCKET_ALERTING, BUCKET_SILENT) } } @@ -94,8 +97,12 @@ class NotificationSectionsFeatureManager @Inject constructor( private fun usePeopleFiltering(proxy: DeviceConfigProxy): Boolean { if (sUsePeopleFiltering == null) { - sUsePeopleFiltering = proxy.getBoolean( - DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_USE_PEOPLE_FILTERING, true) + sUsePeopleFiltering = + proxy.getBoolean( + DeviceConfig.NAMESPACE_SYSTEMUI, + NOTIFICATIONS_USE_PEOPLE_FILTERING, + true + ) } return sUsePeopleFiltering!! diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index b397906fc06f..1adfef061235 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -68,6 +68,9 @@ import com.android.systemui.statusbar.notification.icon.IconPack; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController; import com.android.systemui.statusbar.notification.row.NotificationGuts; +import com.android.systemui.statusbar.notification.row.shared.HeadsUpStatusBarModel; +import com.android.systemui.statusbar.notification.row.shared.NotificationContentModel; +import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor; import com.android.systemui.statusbar.notification.stack.PriorityBucket; import com.android.systemui.util.ListenerSet; @@ -951,6 +954,7 @@ public final class NotificationEntry extends ListEntry { * heads up. */ public void setHeadsUpStatusBarText(CharSequence headsUpStatusBarText) { + NotificationRowContentBinderRefactor.assertInLegacyMode(); this.mHeadsUpStatusBarText.setValue(headsUpStatusBarText); } @@ -964,6 +968,7 @@ public final class NotificationEntry extends ListEntry { * heads up, and its content is sensitive right now. */ public void setHeadsUpStatusBarTextPublic(CharSequence headsUpStatusBarTextPublic) { + NotificationRowContentBinderRefactor.assertInLegacyMode(); this.mHeadsUpStatusBarTextPublic.setValue(headsUpStatusBarTextPublic); } @@ -1036,6 +1041,14 @@ public final class NotificationEntry extends ListEntry { == Notification.VISIBILITY_PRIVATE; } + /** Set the content generated by the notification inflater. */ + public void setContentModel(NotificationContentModel contentModel) { + if (NotificationRowContentBinderRefactor.isUnexpectedlyInLegacyMode()) return; + HeadsUpStatusBarModel headsUpStatusBarModel = contentModel.getHeadsUpStatusBarModel(); + this.mHeadsUpStatusBarText.setValue(headsUpStatusBarModel.getPrivateText()); + this.mHeadsUpStatusBarTextPublic.setValue(headsUpStatusBarModel.getPublicText()); + } + /** Information about a suggestion that is being edited. */ public static class EditedSuggestionInfo { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java index 63997f8f2457..47a04291dd49 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java @@ -60,22 +60,27 @@ public class ColorizedFgsCoordinator implements Coordinator { public boolean isInSection(ListEntry entry) { NotificationEntry notificationEntry = entry.getRepresentativeEntry(); if (notificationEntry != null) { - return isColorizedForegroundService(notificationEntry) || isCall(notificationEntry); + return isRichOngoing(notificationEntry); } return false; } + }; - private boolean isColorizedForegroundService(NotificationEntry entry) { - Notification notification = entry.getSbn().getNotification(); - return notification.isForegroundService() - && notification.isColorized() - && entry.getImportance() > IMPORTANCE_MIN; - } + /** Determines if the given notification is a colorized or call notification */ + public static boolean isRichOngoing(NotificationEntry entry) { + return isColorizedForegroundService(entry) || isCall(entry); + } - private boolean isCall(NotificationEntry entry) { - Notification notification = entry.getSbn().getNotification(); - return entry.getImportance() > IMPORTANCE_MIN - && notification.isStyle(Notification.CallStyle.class); - } - }; + private static boolean isColorizedForegroundService(NotificationEntry entry) { + Notification notification = entry.getSbn().getNotification(); + return notification.isForegroundService() + && notification.isColorized() + && entry.getImportance() > IMPORTANCE_MIN; + } + + private static boolean isCall(NotificationEntry entry) { + Notification notification = entry.getSbn().getNotification(); + return entry.getImportance() > IMPORTANCE_MIN + && notification.isStyle(Notification.CallStyle.class); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt index 071192b02ee0..5a1146d2472f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.collection.coordinator +import android.app.NotificationManager import android.os.UserHandle import android.provider.Settings import androidx.annotation.VisibleForTesting @@ -44,7 +45,8 @@ import com.android.systemui.statusbar.notification.collection.provider.SectionHe import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype -import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE +import com.android.systemui.statusbar.notification.stack.BUCKET_TOP_ONGOING +import com.android.systemui.statusbar.notification.stack.BUCKET_TOP_UNSEEN import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.headsUpEvents import com.android.systemui.util.asIndenting @@ -113,7 +115,7 @@ constructor( private fun attachUnseenFilter(pipeline: NotifPipeline) { if (NotificationMinimalismPrototype.V2.isEnabled) { pipeline.addPromoter(unseenNotifPromoter) - pipeline.addOnBeforeTransformGroupsListener(::pickOutTopUnseenNotif) + pipeline.addOnBeforeTransformGroupsListener(::pickOutTopUnseenNotifs) } pipeline.addFinalizeFilter(unseenNotifFilter) pipeline.addCollectionListener(collectionListener) @@ -347,15 +349,16 @@ constructor( } } - private fun pickOutTopUnseenNotif(list: List<ListEntry>) { + private fun pickOutTopUnseenNotifs(list: List<ListEntry>) { if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return // Only ever elevate a top unseen notification on keyguard, not even locked shade if (statusBarStateController.state != StatusBarState.KEYGUARD) { + seenNotificationsInteractor.setTopOngoingNotification(null) seenNotificationsInteractor.setTopUnseenNotification(null) return } // On keyguard pick the top-ranked unseen or ongoing notification to elevate - seenNotificationsInteractor.setTopUnseenNotification( + val nonSummaryEntries: Sequence<NotificationEntry> = list .asSequence() .flatMap { @@ -365,7 +368,15 @@ constructor( else -> error("unhandled type of $it") } } - .filter { shouldIgnoreUnseenCheck(it) || it in unseenNotifications } + .filter { it.importance >= NotificationManager.IMPORTANCE_DEFAULT } + seenNotificationsInteractor.setTopOngoingNotification( + nonSummaryEntries + .filter { ColorizedFgsCoordinator.isRichOngoing(it) } + .minByOrNull { it.ranking.rank } + ) + seenNotificationsInteractor.setTopUnseenNotification( + nonSummaryEntries + .filter { !ColorizedFgsCoordinator.isRichOngoing(it) && it in unseenNotifications } .minByOrNull { it.ranking.rank } ) } @@ -375,29 +386,39 @@ constructor( object : NotifPromoter("$TAG-unseen") { override fun shouldPromoteToTopLevel(child: NotificationEntry): Boolean = if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) false + else if (!NotificationMinimalismPrototype.V2.ungroupTopUnseen) false else - seenNotificationsInteractor.isTopUnseenNotification(child) && - NotificationMinimalismPrototype.V2.ungroupTopUnseen + seenNotificationsInteractor.isTopOngoingNotification(child) || + seenNotificationsInteractor.isTopUnseenNotification(child) } - val unseenNotifSectioner = - object : NotifSectioner("Unseen", BUCKET_FOREGROUND_SERVICE) { + val topOngoingSectioner = + object : NotifSectioner("TopOngoing", BUCKET_TOP_ONGOING) { override fun isInSection(entry: ListEntry): Boolean { if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return false - if ( - seenNotificationsInteractor.isTopUnseenNotification(entry.representativeEntry) - ) { - return true + return entry.anyEntry { notificationEntry -> + seenNotificationsInteractor.isTopOngoingNotification(notificationEntry) } - if (entry !is GroupEntry) { - return false - } - return entry.children.any { - seenNotificationsInteractor.isTopUnseenNotification(it) + } + } + + val topUnseenSectioner = + object : NotifSectioner("TopUnseen", BUCKET_TOP_UNSEEN) { + override fun isInSection(entry: ListEntry): Boolean { + if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return false + return entry.anyEntry { notificationEntry -> + seenNotificationsInteractor.isTopUnseenNotification(notificationEntry) } } } + private fun ListEntry.anyEntry(predicate: (NotificationEntry?) -> Boolean) = + when { + predicate(representativeEntry) -> true + this !is GroupEntry -> false + else -> children.any(predicate) + } + @VisibleForTesting internal val unseenNotifFilter = object : NotifFilter("$TAG-unseen") { 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 4506385a2fb9..e41352254bac 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 @@ -116,11 +116,14 @@ constructor( } // Manually add Ordered Sections + if (NotificationMinimalismPrototype.V2.isEnabled) { + mOrderedSections.add(keyguardCoordinator.topOngoingSectioner) // Top Ongoing + } mOrderedSections.add(headsUpCoordinator.sectioner) // HeadsUp - mOrderedSections.add(colorizedFgsCoordinator.sectioner) // ForegroundService if (NotificationMinimalismPrototype.V2.isEnabled) { - mOrderedSections.add(keyguardCoordinator.unseenNotifSectioner) // Unseen (FGS) + mOrderedSections.add(keyguardCoordinator.topUnseenSectioner) // Top Unseen } + mOrderedSections.add(colorizedFgsCoordinator.sectioner) // ForegroundService if (PriorityPeopleSection.isEnabled) { mOrderedSections.add(conversationCoordinator.priorityPeopleSectioner) // Priority People } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt index e2c9e02672d2..45d1034f2cfb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt @@ -42,6 +42,9 @@ class ActiveNotificationListRepository @Inject constructor() { /** Stats about the list of notifications attached to the shade */ val notifStats = MutableStateFlow(NotifStats.empty) + /** The key of the top ongoing notification */ + val topOngoingNotificationKey = MutableStateFlow<String?>(null) + /** The key of the top unseen notification */ val topUnseenNotificationKey = MutableStateFlow<String?>(null) } @@ -75,6 +78,7 @@ data class ActiveNotificationsStore( /** Unique key identifying an [ActiveNotificationEntryModel] in the store. */ sealed class Key { data class Individual(val key: String) : Key() + data class Group(val key: String) : Key() } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt index 42828d99c7e4..85c66bd6f25a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt @@ -39,6 +39,18 @@ constructor( notificationListRepository.hasFilteredOutSeenNotifications.value = value } + /** Set the entry that is identified as the top ongoing notification. */ + fun setTopOngoingNotification(entry: NotificationEntry?) { + if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return + notificationListRepository.topOngoingNotificationKey.value = entry?.key + } + + /** Determine if the given notification is the top ongoing notification. */ + fun isTopOngoingNotification(entry: NotificationEntry?): Boolean = + if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) false + else + entry != null && notificationListRepository.topOngoingNotificationKey.value == entry.key + /** Set the entry that is identified as the top unseen notification. */ fun setTopUnseenNotification(entry: NotificationEntry?) { if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt index 3df9374da914..331d3cc4c21b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt @@ -20,8 +20,6 @@ import android.app.Notification import android.app.Notification.MessagingStyle import android.app.Person import android.content.pm.LauncherApps -import android.graphics.drawable.AdaptiveIconDrawable -import android.graphics.drawable.Drawable import android.graphics.drawable.Icon import android.os.Build import android.os.Bundle @@ -226,28 +224,22 @@ constructor( } val n = entry.sbn.notification - var usingMonochromeAppIcon = false - val icon: Icon? - if (showPeopleAvatar) { - icon = createPeopleAvatar(entry) - } else if (android.app.Flags.notificationsUseMonochromeAppIcon()) { - if (n.shouldUseAppIcon()) { - icon = - getMonochromeAppIcon(entry)?.also { usingMonochromeAppIcon = true } - ?: n.smallIcon + val (icon: Icon?, type: StatusBarIcon.Type) = + if (showPeopleAvatar) { + createPeopleAvatar(entry) to StatusBarIcon.Type.PeopleAvatar + } else if ( + android.app.Flags.notificationsUseMonochromeAppIcon() && n.shouldUseAppIcon() + ) { + n.smallIcon to StatusBarIcon.Type.MaybeMonochromeAppIcon } else { - icon = n.smallIcon + n.smallIcon to StatusBarIcon.Type.NotifSmallIcon } - } else { - icon = n.smallIcon - } - if (icon == null) { throw InflationException("No icon in notification from ${entry.sbn.packageName}") } - val sbi = icon.toStatusBarIcon(entry) - cacheIconDescriptor(entry, sbi, showPeopleAvatar, usingMonochromeAppIcon) + val sbi = icon.toStatusBarIcon(entry, type) + cacheIconDescriptor(entry, sbi) return sbi } @@ -269,29 +261,24 @@ constructor( } } - private fun cacheIconDescriptor( - entry: NotificationEntry, - descriptor: StatusBarIcon, - showPeopleAvatar: Boolean, - usingMonochromeAppIcon: Boolean - ) { - if (android.app.Flags.notificationsUseAppIcon() || - android.app.Flags.notificationsUseMonochromeAppIcon() + private fun cacheIconDescriptor(entry: NotificationEntry, descriptor: StatusBarIcon) { + if ( + android.app.Flags.notificationsUseAppIcon() || + android.app.Flags.notificationsUseMonochromeAppIcon() ) { // If either of the new icon flags is enabled, we cache the icon all the time. - if (showPeopleAvatar) { - entry.icons.peopleAvatarDescriptor = descriptor - } else if (usingMonochromeAppIcon) { + when (descriptor.type) { + StatusBarIcon.Type.PeopleAvatar -> entry.icons.peopleAvatarDescriptor = descriptor // When notificationsUseMonochromeAppIcon is enabled, we use the appIconDescriptor. - entry.icons.appIconDescriptor = descriptor - } else { + StatusBarIcon.Type.MaybeMonochromeAppIcon -> + entry.icons.appIconDescriptor = descriptor // When notificationsUseAppIcon is enabled, the app icon overrides the small icon. // But either way, it's a good idea to cache the descriptor. - entry.icons.smallIconDescriptor = descriptor + else -> entry.icons.smallIconDescriptor = descriptor } } else if (isImportantConversation(entry)) { // Old approach: cache only if important conversation. - if (showPeopleAvatar) { + if (descriptor.type == StatusBarIcon.Type.PeopleAvatar) { entry.icons.peopleAvatarDescriptor = descriptor } else { entry.icons.smallIconDescriptor = descriptor @@ -312,7 +299,10 @@ constructor( } } - private fun Icon.toStatusBarIcon(entry: NotificationEntry): StatusBarIcon { + private fun Icon.toStatusBarIcon( + entry: NotificationEntry, + type: StatusBarIcon.Type + ): StatusBarIcon { val n = entry.sbn.notification return StatusBarIcon( entry.sbn.user, @@ -320,33 +310,11 @@ constructor( /* icon = */ this, n.iconLevel, n.number, - iconBuilder.getIconContentDescription(n) + iconBuilder.getIconContentDescription(n), + type ) } - // TODO(b/335211019): Should we merge this with the method in GroupHelper? - private fun getMonochromeAppIcon(entry: NotificationEntry): Icon? { - // TODO(b/335211019): This should be done in the background. - var monochromeIcon: Icon? = null - try { - val appIcon: Drawable = iconBuilder.getAppIcon(entry.sbn.notification) - if (appIcon is AdaptiveIconDrawable) { - if (appIcon.monochrome != null) { - monochromeIcon = - Icon.createWithResourceAdaptiveDrawable( - /* resPackage = */ entry.sbn.packageName, - /* resId = */ appIcon.sourceDrawableResId, - /* useMonochrome = */ true, - /* inset = */ -3.0f * AdaptiveIconDrawable.getExtraInsetFraction() - ) - } - } - } catch (e: Exception) { - Log.e(TAG, "Failed to getAppIcon() in getMonochromeAppIcon()", e) - } - return monochromeIcon - } - private suspend fun getLauncherShortcutIconForPeopleAvatar(entry: NotificationEntry) = withContext(bgCoroutineContext) { var icon: Icon? = null @@ -365,7 +333,8 @@ constructor( // Once we have the icon, updating it should happen on the main thread. if (icon != null) { withContext(mainCoroutineContext) { - val iconDescriptor = icon.toStatusBarIcon(entry) + val iconDescriptor = + icon.toStatusBarIcon(entry, StatusBarIcon.Type.PeopleAvatar) // Cache the value entry.icons.peopleAvatarDescriptor = iconDescriptor diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java index 6ba26d99419e..af5117e0b561 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java @@ -56,6 +56,7 @@ import com.android.systemui.statusbar.notification.InflationException; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation; import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation; +import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor; import com.android.systemui.statusbar.notification.row.ui.viewbinder.SingleLineConversationViewBinder; import com.android.systemui.statusbar.notification.row.ui.viewbinder.SingleLineViewBinder; import com.android.systemui.statusbar.notification.row.ui.viewmodel.SingleLineViewModel; @@ -105,6 +106,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider, HeadsUpStyleProvider headsUpStyleProvider, NotificationRowContentBinderLogger logger) { + NotificationRowContentBinderRefactor.assertInLegacyMode(); mRemoteViewCache = remoteViewCache; mRemoteInputManager = remoteInputManager; mConversationProcessor = conversationProcessor; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java index c1302a0d3e57..fe0ee5235808 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java @@ -147,11 +147,6 @@ public interface NotificationRowContentBinder { * Use increased height when binding heads up views. */ public boolean usesIncreasedHeadsUpHeight; - - /** - * Is group summary notification - */ - public boolean mIsGroupSummary; } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt new file mode 100644 index 000000000000..e70414084598 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt @@ -0,0 +1,1569 @@ +/* + * Copyright (C) 2017 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.row + +import android.annotation.SuppressLint +import android.app.Notification +import android.content.Context +import android.content.ContextWrapper +import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager +import android.content.res.Resources +import android.os.AsyncTask +import android.os.Build +import android.os.CancellationSignal +import android.os.Trace +import android.os.UserHandle +import android.service.notification.StatusBarNotification +import android.util.Log +import android.view.NotificationHeaderView +import android.view.View +import android.view.ViewGroup +import android.widget.RemoteViews +import android.widget.RemoteViews.InteractionHandler +import android.widget.RemoteViews.OnViewAppliedListener +import com.android.app.tracing.TraceUtils +import com.android.internal.annotations.VisibleForTesting +import com.android.internal.widget.ImageMessageConsumer +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.NotifInflation +import com.android.systemui.res.R +import com.android.systemui.statusbar.InflationTask +import com.android.systemui.statusbar.NotificationRemoteInputManager +import com.android.systemui.statusbar.notification.ConversationNotificationProcessor +import com.android.systemui.statusbar.notification.InflationException +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.BindParams +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_SINGLE_LINE +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_GROUP_SUMMARY_HEADER +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationCallback +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag +import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation +import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation +import com.android.systemui.statusbar.notification.row.shared.HeadsUpStatusBarModel +import com.android.systemui.statusbar.notification.row.shared.NewRemoteViews +import com.android.systemui.statusbar.notification.row.shared.NotificationContentModel +import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor +import com.android.systemui.statusbar.notification.row.ui.viewbinder.SingleLineConversationViewBinder +import com.android.systemui.statusbar.notification.row.ui.viewbinder.SingleLineViewBinder +import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper +import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer +import com.android.systemui.statusbar.policy.InflatedSmartReplyState +import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder +import com.android.systemui.statusbar.policy.SmartReplyStateInflater +import com.android.systemui.util.Assert +import java.util.concurrent.Executor +import java.util.function.Consumer +import javax.inject.Inject + +/** + * [NotificationRowContentBinderImpl] binds content to a [ExpandableNotificationRow] by + * asynchronously building the content's [RemoteViews] and applying it to the row. + */ +@SysUISingleton +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +class NotificationRowContentBinderImpl +@Inject +constructor( + private val remoteViewCache: NotifRemoteViewCache, + private val remoteInputManager: NotificationRemoteInputManager, + private val conversationProcessor: ConversationNotificationProcessor, + @NotifInflation private val inflationExecutor: Executor, + private val smartReplyStateInflater: SmartReplyStateInflater, + private val notifLayoutInflaterFactoryProvider: NotifLayoutInflaterFactory.Provider, + private val headsUpStyleProvider: HeadsUpStyleProvider, + private val logger: NotificationRowContentBinderLogger +) : NotificationRowContentBinder { + + init { + /* check if */ NotificationRowContentBinderRefactor.isUnexpectedlyInLegacyMode() + } + + private var inflateSynchronously = false + + override fun bindContent( + entry: NotificationEntry, + row: ExpandableNotificationRow, + @InflationFlag contentToBind: Int, + bindParams: BindParams, + forceInflate: Boolean, + callback: InflationCallback? + ) { + if (row.isRemoved) { + // We don't want to reinflate anything for removed notifications. Otherwise views might + // be readded to the stack, leading to leaks. This may happen with low-priority groups + // where the removal of already removed children can lead to a reinflation. + logger.logNotBindingRowWasRemoved(entry) + return + } + logger.logBinding(entry, contentToBind) + val sbn: StatusBarNotification = entry.sbn + + // To check if the notification has inline image and preload inline image if necessary. + row.imageResolver.preloadImages(sbn.notification) + if (forceInflate) { + remoteViewCache.clearCache(entry) + } + + // Cancel any pending frees on any view we're trying to bind since we should be bound after. + cancelContentViewFrees(row, contentToBind) + val task = + AsyncInflationTask( + inflationExecutor, + inflateSynchronously, + /* reInflateFlags = */ contentToBind, + remoteViewCache, + entry, + conversationProcessor, + row, + bindParams.isMinimized, + bindParams.usesIncreasedHeight, + bindParams.usesIncreasedHeadsUpHeight, + callback, + remoteInputManager.remoteViewsOnClickHandler, + /* isMediaFlagEnabled = */ smartReplyStateInflater, + notifLayoutInflaterFactoryProvider, + headsUpStyleProvider, + logger + ) + if (inflateSynchronously) { + task.onPostExecute(task.doInBackground()) + } else { + task.executeOnExecutor(inflationExecutor) + } + } + + @VisibleForTesting + fun inflateNotificationViews( + entry: NotificationEntry, + row: ExpandableNotificationRow, + bindParams: BindParams, + inflateSynchronously: Boolean, + @InflationFlag reInflateFlags: Int, + builder: Notification.Builder, + packageContext: Context, + smartRepliesInflater: SmartReplyStateInflater + ): InflationProgress { + val systemUIContext = row.context + val result = + beginInflationAsync( + reInflateFlags = reInflateFlags, + entry = entry, + builder = builder, + isMinimized = bindParams.isMinimized, + usesIncreasedHeight = bindParams.usesIncreasedHeight, + usesIncreasedHeadsUpHeight = bindParams.usesIncreasedHeadsUpHeight, + systemUIContext = systemUIContext, + packageContext = packageContext, + row = row, + notifLayoutInflaterFactoryProvider = notifLayoutInflaterFactoryProvider, + headsUpStyleProvider = headsUpStyleProvider, + conversationProcessor = conversationProcessor, + logger = logger, + ) + inflateSmartReplyViews( + result, + reInflateFlags, + entry, + systemUIContext, + packageContext, + row.existingSmartReplyState, + smartRepliesInflater, + logger, + ) + if (AsyncHybridViewInflation.isEnabled) { + result.inflatedSingleLineView = + result.contentModel.singleLineViewModel?.let { viewModel -> + SingleLineViewInflater.inflateSingleLineViewHolder( + viewModel.isConversation(), + reInflateFlags, + entry, + systemUIContext, + logger, + ) + } + } + apply( + inflationExecutor, + inflateSynchronously, + bindParams.isMinimized, + result, + reInflateFlags, + remoteViewCache, + entry, + row, + remoteInputManager.remoteViewsOnClickHandler, + /* callback= */ null, + logger + ) + return result + } + + override fun cancelBind(entry: NotificationEntry, row: ExpandableNotificationRow): Boolean { + val abortedTask: Boolean = entry.abortTask() + if (abortedTask) { + logger.logCancelBindAbortedTask(entry) + } + return abortedTask + } + + @SuppressLint("WrongConstant") + override fun unbindContent( + entry: NotificationEntry, + row: ExpandableNotificationRow, + @InflationFlag contentToUnbind: Int + ) { + logger.logUnbinding(entry, contentToUnbind) + var curFlag = 1 + var contentLeftToUnbind = contentToUnbind + while (contentLeftToUnbind != 0) { + if (contentLeftToUnbind and curFlag != 0) { + freeNotificationView(entry, row, curFlag) + } + contentLeftToUnbind = contentLeftToUnbind and curFlag.inv() + curFlag = curFlag shl 1 + } + } + + /** + * Frees the content view associated with the inflation flag as soon as the view is not showing. + * + * @param inflateFlag the flag corresponding to the content view which should be freed + */ + private fun freeNotificationView( + entry: NotificationEntry, + row: ExpandableNotificationRow, + @InflationFlag inflateFlag: Int + ) { + when (inflateFlag) { + FLAG_CONTENT_VIEW_CONTRACTED -> + row.privateLayout.performWhenContentInactive( + NotificationContentView.VISIBLE_TYPE_CONTRACTED + ) { + row.privateLayout.setContractedChild(null) + remoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_CONTRACTED) + } + FLAG_CONTENT_VIEW_EXPANDED -> + row.privateLayout.performWhenContentInactive( + NotificationContentView.VISIBLE_TYPE_EXPANDED + ) { + row.privateLayout.setExpandedChild(null) + remoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_EXPANDED) + } + FLAG_CONTENT_VIEW_HEADS_UP -> + row.privateLayout.performWhenContentInactive( + NotificationContentView.VISIBLE_TYPE_HEADSUP + ) { + row.privateLayout.setHeadsUpChild(null) + remoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_HEADS_UP) + row.privateLayout.setHeadsUpInflatedSmartReplies(null) + } + FLAG_CONTENT_VIEW_PUBLIC -> + row.publicLayout.performWhenContentInactive( + NotificationContentView.VISIBLE_TYPE_CONTRACTED + ) { + row.publicLayout.setContractedChild(null) + remoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_PUBLIC) + } + FLAG_CONTENT_VIEW_SINGLE_LINE -> { + if (AsyncHybridViewInflation.isEnabled) { + row.privateLayout.performWhenContentInactive( + NotificationContentView.VISIBLE_TYPE_SINGLELINE + ) { + row.privateLayout.setSingleLineView(null) + } + } + } + else -> {} + } + } + + /** + * Cancel any pending content view frees from [.freeNotificationView] for the provided content + * views. + * + * @param row top level notification row containing the content views + * @param contentViews content views to cancel pending frees on + */ + private fun cancelContentViewFrees( + row: ExpandableNotificationRow, + @InflationFlag contentViews: Int + ) { + if (contentViews and FLAG_CONTENT_VIEW_CONTRACTED != 0) { + row.privateLayout.removeContentInactiveRunnable( + NotificationContentView.VISIBLE_TYPE_CONTRACTED + ) + } + if (contentViews and FLAG_CONTENT_VIEW_EXPANDED != 0) { + row.privateLayout.removeContentInactiveRunnable( + NotificationContentView.VISIBLE_TYPE_EXPANDED + ) + } + if (contentViews and FLAG_CONTENT_VIEW_HEADS_UP != 0) { + row.privateLayout.removeContentInactiveRunnable( + NotificationContentView.VISIBLE_TYPE_HEADSUP + ) + } + if (contentViews and FLAG_CONTENT_VIEW_PUBLIC != 0) { + row.publicLayout.removeContentInactiveRunnable( + NotificationContentView.VISIBLE_TYPE_CONTRACTED + ) + } + if ( + AsyncHybridViewInflation.isEnabled && + contentViews and FLAG_CONTENT_VIEW_SINGLE_LINE != 0 + ) { + row.privateLayout.removeContentInactiveRunnable( + NotificationContentView.VISIBLE_TYPE_SINGLELINE + ) + } + } + + /** + * Sets whether to perform inflation on the same thread as the caller. This method should only + * be used in tests, not in production. + */ + @VisibleForTesting + override fun setInflateSynchronously(inflateSynchronously: Boolean) { + this.inflateSynchronously = inflateSynchronously + } + + class AsyncInflationTask( + private val inflationExecutor: Executor, + private val inflateSynchronously: Boolean, + @get:InflationFlag @get:VisibleForTesting @InflationFlag val reInflateFlags: Int, + private val remoteViewCache: NotifRemoteViewCache, + private val entry: NotificationEntry, + private val conversationProcessor: ConversationNotificationProcessor, + private val row: ExpandableNotificationRow, + private val isMinimized: Boolean, + private val usesIncreasedHeight: Boolean, + private val usesIncreasedHeadsUpHeight: Boolean, + private val callback: InflationCallback?, + private val remoteViewClickHandler: InteractionHandler?, + private val smartRepliesInflater: SmartReplyStateInflater, + private val notifLayoutInflaterFactoryProvider: NotifLayoutInflaterFactory.Provider, + private val headsUpStyleProvider: HeadsUpStyleProvider, + private val logger: NotificationRowContentBinderLogger + ) : AsyncTask<Void, Void, Result<InflationProgress>>(), InflationCallback, InflationTask { + private val context: Context + get() = row.context + + private var cancellationSignal: CancellationSignal? = null + + init { + entry.setInflationTask(this) + } + + private fun updateApplicationInfo(sbn: StatusBarNotification) { + val packageName: String = sbn.packageName + val userId: Int = UserHandle.getUserId(sbn.uid) + val appInfo: ApplicationInfo + try { + // This method has an internal cache, so we don't need to add our own caching here. + appInfo = + context.packageManager.getApplicationInfoAsUser( + packageName, + PackageManager.MATCH_UNINSTALLED_PACKAGES, + userId + ) + } catch (e: PackageManager.NameNotFoundException) { + return + } + Notification.addFieldsFromContext(appInfo, sbn.notification) + } + + override fun onPreExecute() { + Trace.beginAsyncSection(ASYNC_TASK_TRACE_METHOD, System.identityHashCode(this)) + } + + public override fun doInBackground(vararg params: Void): Result<InflationProgress> { + return TraceUtils.trace( + "NotificationContentInflater.AsyncInflationTask#doInBackground" + ) { + try { + return@trace Result.success(doInBackgroundInternal()) + } catch (e: Exception) { + logger.logAsyncTaskException(entry, "inflating", e) + return@trace Result.failure(e) + } + } + } + + private fun doInBackgroundInternal(): InflationProgress { + val sbn: StatusBarNotification = entry.sbn + // Ensure the ApplicationInfo is updated before a builder is recovered. + updateApplicationInfo(sbn) + val recoveredBuilder = Notification.Builder.recoverBuilder(context, sbn.notification) + var packageContext: Context = sbn.getPackageContext(context) + if (recoveredBuilder.usesTemplate()) { + // For all of our templates, we want it to be RTL + packageContext = RtlEnabledContext(packageContext) + } + val inflationProgress = + beginInflationAsync( + reInflateFlags = reInflateFlags, + entry = entry, + builder = recoveredBuilder, + isMinimized = isMinimized, + usesIncreasedHeight = usesIncreasedHeight, + usesIncreasedHeadsUpHeight = usesIncreasedHeadsUpHeight, + systemUIContext = context, + packageContext = packageContext, + row = row, + notifLayoutInflaterFactoryProvider = notifLayoutInflaterFactoryProvider, + headsUpStyleProvider = headsUpStyleProvider, + conversationProcessor = conversationProcessor, + logger = logger + ) + logger.logAsyncTaskProgress( + entry, + "getting existing smart reply state (on wrong thread!)" + ) + val previousSmartReplyState: InflatedSmartReplyState? = row.existingSmartReplyState + logger.logAsyncTaskProgress(entry, "inflating smart reply views") + inflateSmartReplyViews( + /* result = */ inflationProgress, + reInflateFlags, + entry, + context, + packageContext, + previousSmartReplyState, + smartRepliesInflater, + logger, + ) + if (AsyncHybridViewInflation.isEnabled) { + logger.logAsyncTaskProgress(entry, "inflating single line view") + inflationProgress.inflatedSingleLineView = + inflationProgress.contentModel.singleLineViewModel?.let { + SingleLineViewInflater.inflateSingleLineViewHolder( + it.isConversation(), + reInflateFlags, + entry, + context, + logger + ) + } + } + logger.logAsyncTaskProgress(entry, "getting row image resolver (on wrong thread!)") + val imageResolver = row.imageResolver + // wait for image resolver to finish preloading + logger.logAsyncTaskProgress(entry, "waiting for preloaded images") + imageResolver.waitForPreloadedImages(IMG_PRELOAD_TIMEOUT_MS) + return inflationProgress + } + + public override fun onPostExecute(result: Result<InflationProgress>) { + Trace.endAsyncSection(ASYNC_TASK_TRACE_METHOD, System.identityHashCode(this)) + result + .onSuccess { progress -> + // Logged in detail in apply. + cancellationSignal = + apply( + inflationExecutor, + inflateSynchronously, + isMinimized, + progress, + reInflateFlags, + remoteViewCache, + entry, + row, + remoteViewClickHandler, + this /* callback */, + logger + ) + } + .onFailure { error -> handleError(error as Exception) } + } + + override fun onCancelled(result: Result<InflationProgress>) { + Trace.endAsyncSection(ASYNC_TASK_TRACE_METHOD, System.identityHashCode(this)) + } + + private fun handleError(e: Exception) { + entry.onInflationTaskFinished() + val sbn: StatusBarNotification = entry.sbn + val ident: String = (sbn.packageName + "/0x" + Integer.toHexString(sbn.id)) + Log.e(TAG, "couldn't inflate view for notification $ident", e) + callback?.handleInflationException( + row.entry, + InflationException("Couldn't inflate contentViews$e") + ) + + // Cancel any image loading tasks, not useful any more + row.imageResolver.cancelRunningTasks() + } + + override fun abort() { + logger.logAsyncTaskProgress(entry, "cancelling inflate") + cancel(/* mayInterruptIfRunning= */ true) + if (cancellationSignal != null) { + logger.logAsyncTaskProgress(entry, "cancelling apply") + cancellationSignal!!.cancel() + } + logger.logAsyncTaskProgress(entry, "aborted") + } + + override fun handleInflationException(entry: NotificationEntry, e: Exception) { + handleError(e) + } + + override fun onAsyncInflationFinished(entry: NotificationEntry) { + this.entry.onInflationTaskFinished() + row.onNotificationUpdated() + callback?.onAsyncInflationFinished(this.entry) + + // Notify the resolver that the inflation task has finished, + // try to purge unnecessary cached entries. + row.imageResolver.purgeCache() + + // Cancel any image loading tasks that have not completed at this point + row.imageResolver.cancelRunningTasks() + } + + class RtlEnabledContext(packageContext: Context) : ContextWrapper(packageContext) { + override fun getApplicationInfo(): ApplicationInfo { + val applicationInfo = ApplicationInfo(super.getApplicationInfo()) + applicationInfo.flags = applicationInfo.flags or ApplicationInfo.FLAG_SUPPORTS_RTL + return applicationInfo + } + } + + companion object { + private const val IMG_PRELOAD_TIMEOUT_MS = 1000L + } + } + + @VisibleForTesting + class InflationProgress( + @VisibleForTesting val packageContext: Context, + val remoteViews: NewRemoteViews, + val contentModel: NotificationContentModel, + ) { + + var inflatedContentView: View? = null + var inflatedHeadsUpView: View? = null + var inflatedExpandedView: View? = null + var inflatedPublicView: View? = null + var inflatedGroupHeaderView: NotificationHeaderView? = null + var inflatedMinimizedGroupHeaderView: NotificationHeaderView? = null + var inflatedSmartReplyState: InflatedSmartReplyState? = null + var expandedInflatedSmartReplies: InflatedSmartReplyViewHolder? = null + var headsUpInflatedSmartReplies: InflatedSmartReplyViewHolder? = null + + // Inflated SingleLineView that lacks the UI State + var inflatedSingleLineView: HybridNotificationView? = null + } + + @VisibleForTesting + abstract class ApplyCallback { + abstract fun setResultView(v: View) + + abstract val remoteView: RemoteViews + } + + companion object { + const val TAG = "NotifContentInflater" + + private fun inflateSmartReplyViews( + result: InflationProgress, + @InflationFlag reInflateFlags: Int, + entry: NotificationEntry, + context: Context, + packageContext: Context, + previousSmartReplyState: InflatedSmartReplyState?, + inflater: SmartReplyStateInflater, + logger: NotificationRowContentBinderLogger + ) { + val inflateContracted = + (reInflateFlags and FLAG_CONTENT_VIEW_CONTRACTED != 0 && + result.remoteViews.contracted != null) + val inflateExpanded = + (reInflateFlags and FLAG_CONTENT_VIEW_EXPANDED != 0 && + result.remoteViews.expanded != null) + val inflateHeadsUp = + (reInflateFlags and FLAG_CONTENT_VIEW_HEADS_UP != 0 && + result.remoteViews.headsUp != null) + if (inflateContracted || inflateExpanded || inflateHeadsUp) { + logger.logAsyncTaskProgress(entry, "inflating contracted smart reply state") + result.inflatedSmartReplyState = inflater.inflateSmartReplyState(entry) + } + if (inflateExpanded) { + logger.logAsyncTaskProgress(entry, "inflating expanded smart reply state") + result.expandedInflatedSmartReplies = + inflater.inflateSmartReplyViewHolder( + context, + packageContext, + entry, + previousSmartReplyState, + result.inflatedSmartReplyState!! + ) + } + if (inflateHeadsUp) { + logger.logAsyncTaskProgress(entry, "inflating heads up smart reply state") + result.headsUpInflatedSmartReplies = + inflater.inflateSmartReplyViewHolder( + context, + packageContext, + entry, + previousSmartReplyState, + result.inflatedSmartReplyState!! + ) + } + } + + private fun beginInflationAsync( + @InflationFlag reInflateFlags: Int, + entry: NotificationEntry, + builder: Notification.Builder, + isMinimized: Boolean, + usesIncreasedHeight: Boolean, + usesIncreasedHeadsUpHeight: Boolean, + systemUIContext: Context, + packageContext: Context, + row: ExpandableNotificationRow, + notifLayoutInflaterFactoryProvider: NotifLayoutInflaterFactory.Provider, + headsUpStyleProvider: HeadsUpStyleProvider, + conversationProcessor: ConversationNotificationProcessor, + logger: NotificationRowContentBinderLogger + ): InflationProgress { + // process conversations and extract the messaging style + val messagingStyle = + if (entry.ranking.isConversation) { + conversationProcessor.processNotification(entry, builder, logger) + } else null + + val remoteViews = + createRemoteViews( + reInflateFlags = reInflateFlags, + builder = builder, + isMinimized = isMinimized, + usesIncreasedHeight = usesIncreasedHeight, + usesIncreasedHeadsUpHeight = usesIncreasedHeadsUpHeight, + row = row, + notifLayoutInflaterFactoryProvider = notifLayoutInflaterFactoryProvider, + headsUpStyleProvider = headsUpStyleProvider, + logger = logger, + ) + + val singleLineViewModel = + if ( + AsyncHybridViewInflation.isEnabled && + reInflateFlags and FLAG_CONTENT_VIEW_SINGLE_LINE != 0 + ) { + logger.logAsyncTaskProgress(entry, "inflating single line view model") + SingleLineViewInflater.inflateSingleLineViewModel( + notification = entry.sbn.notification, + messagingStyle = messagingStyle, + builder = builder, + systemUiContext = systemUIContext, + ) + } else null + + val headsUpStatusBarModel = + HeadsUpStatusBarModel( + privateText = builder.getHeadsUpStatusBarText(/* publicMode= */ false), + publicText = builder.getHeadsUpStatusBarText(/* publicMode= */ true), + ) + + val contentModel = + NotificationContentModel( + headsUpStatusBarModel = headsUpStatusBarModel, + singleLineViewModel = singleLineViewModel, + ) + + return InflationProgress( + packageContext = packageContext, + remoteViews = remoteViews, + contentModel = contentModel, + ) + } + + private fun createRemoteViews( + @InflationFlag reInflateFlags: Int, + builder: Notification.Builder, + isMinimized: Boolean, + usesIncreasedHeight: Boolean, + usesIncreasedHeadsUpHeight: Boolean, + row: ExpandableNotificationRow, + notifLayoutInflaterFactoryProvider: NotifLayoutInflaterFactory.Provider, + headsUpStyleProvider: HeadsUpStyleProvider, + logger: NotificationRowContentBinderLogger + ): NewRemoteViews { + return TraceUtils.trace("NotificationContentInflater.createRemoteViews") { + val entryForLogging: NotificationEntry = row.entry + val contracted = + if (reInflateFlags and FLAG_CONTENT_VIEW_CONTRACTED != 0) { + logger.logAsyncTaskProgress( + entryForLogging, + "creating contracted remote view" + ) + createContentView(builder, isMinimized, usesIncreasedHeight) + } else null + val expanded = + if (reInflateFlags and FLAG_CONTENT_VIEW_EXPANDED != 0) { + logger.logAsyncTaskProgress( + entryForLogging, + "creating expanded remote view" + ) + createExpandedView(builder, isMinimized) + } else null + val headsUp = + if (reInflateFlags and FLAG_CONTENT_VIEW_HEADS_UP != 0) { + logger.logAsyncTaskProgress( + entryForLogging, + "creating heads up remote view" + ) + val isHeadsUpCompact = headsUpStyleProvider.shouldApplyCompactStyle() + if (isHeadsUpCompact) { + builder.createCompactHeadsUpContentView() + } else { + builder.createHeadsUpContentView(usesIncreasedHeadsUpHeight) + } + } else null + val public = + if (reInflateFlags and FLAG_CONTENT_VIEW_PUBLIC != 0) { + logger.logAsyncTaskProgress(entryForLogging, "creating public remote view") + builder.makePublicContentView(isMinimized) + } else null + val normalGroupHeader = + if ( + AsyncGroupHeaderViewInflation.isEnabled && + reInflateFlags and FLAG_GROUP_SUMMARY_HEADER != 0 + ) { + logger.logAsyncTaskProgress( + entryForLogging, + "creating group summary remote view" + ) + builder.makeNotificationGroupHeader() + } else null + val minimizedGroupHeader = + if ( + AsyncGroupHeaderViewInflation.isEnabled && + reInflateFlags and FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER != 0 + ) { + logger.logAsyncTaskProgress( + entryForLogging, + "creating low-priority group summary remote view" + ) + builder.makeLowPriorityContentView(true /* useRegularSubtext */) + } else null + NewRemoteViews( + contracted = contracted, + headsUp = headsUp, + expanded = expanded, + public = public, + normalGroupHeader = normalGroupHeader, + minimizedGroupHeader = minimizedGroupHeader + ) + .withLayoutInflaterFactory(row, notifLayoutInflaterFactoryProvider) + } + } + + private fun NewRemoteViews.withLayoutInflaterFactory( + row: ExpandableNotificationRow, + provider: NotifLayoutInflaterFactory.Provider + ): NewRemoteViews { + contracted?.let { + it.layoutInflaterFactory = provider.provide(row, FLAG_CONTENT_VIEW_CONTRACTED) + } + expanded?.let { + it.layoutInflaterFactory = provider.provide(row, FLAG_CONTENT_VIEW_EXPANDED) + } + headsUp?.let { + it.layoutInflaterFactory = provider.provide(row, FLAG_CONTENT_VIEW_HEADS_UP) + } + public?.let { + it.layoutInflaterFactory = provider.provide(row, FLAG_CONTENT_VIEW_PUBLIC) + } + return this + } + + private fun apply( + inflationExecutor: Executor, + inflateSynchronously: Boolean, + isMinimized: Boolean, + result: InflationProgress, + @InflationFlag reInflateFlags: Int, + remoteViewCache: NotifRemoteViewCache, + entry: NotificationEntry, + row: ExpandableNotificationRow, + remoteViewClickHandler: InteractionHandler?, + callback: InflationCallback?, + logger: NotificationRowContentBinderLogger + ): CancellationSignal { + Trace.beginAsyncSection(APPLY_TRACE_METHOD, System.identityHashCode(row)) + val privateLayout = row.privateLayout + val publicLayout = row.publicLayout + val runningInflations = HashMap<Int, CancellationSignal>() + var flag = FLAG_CONTENT_VIEW_CONTRACTED + if (reInflateFlags and flag != 0) { + val isNewView = + !canReapplyRemoteView( + newView = result.remoteViews.contracted, + oldView = remoteViewCache.getCachedView(entry, FLAG_CONTENT_VIEW_CONTRACTED) + ) + val applyCallback: ApplyCallback = + object : ApplyCallback() { + override fun setResultView(v: View) { + logger.logAsyncTaskProgress(entry, "contracted view applied") + result.inflatedContentView = v + } + + override val remoteView: RemoteViews + get() = result.remoteViews.contracted!! + } + logger.logAsyncTaskProgress(entry, "applying contracted view") + applyRemoteView( + inflationExecutor = inflationExecutor, + inflateSynchronously = inflateSynchronously, + isMinimized = isMinimized, + result = result, + reInflateFlags = reInflateFlags, + inflationId = flag, + remoteViewCache = remoteViewCache, + entry = entry, + row = row, + isNewView = isNewView, + remoteViewClickHandler = remoteViewClickHandler, + callback = callback, + parentLayout = privateLayout, + existingView = privateLayout.contractedChild, + existingWrapper = + privateLayout.getVisibleWrapper( + NotificationContentView.VISIBLE_TYPE_CONTRACTED + ), + runningInflations = runningInflations, + applyCallback = applyCallback, + logger = logger + ) + } + flag = FLAG_CONTENT_VIEW_EXPANDED + if (reInflateFlags and flag != 0) { + if (result.remoteViews.expanded != null) { + val isNewView = + !canReapplyRemoteView( + newView = result.remoteViews.expanded, + oldView = + remoteViewCache.getCachedView(entry, FLAG_CONTENT_VIEW_EXPANDED) + ) + val applyCallback: ApplyCallback = + object : ApplyCallback() { + override fun setResultView(v: View) { + logger.logAsyncTaskProgress(entry, "expanded view applied") + result.inflatedExpandedView = v + } + + override val remoteView: RemoteViews + get() = result.remoteViews.expanded + } + logger.logAsyncTaskProgress(entry, "applying expanded view") + applyRemoteView( + inflationExecutor = inflationExecutor, + inflateSynchronously = inflateSynchronously, + isMinimized = isMinimized, + result = result, + reInflateFlags = reInflateFlags, + inflationId = flag, + remoteViewCache = remoteViewCache, + entry = entry, + row = row, + isNewView = isNewView, + remoteViewClickHandler = remoteViewClickHandler, + callback = callback, + parentLayout = privateLayout, + existingView = privateLayout.expandedChild, + existingWrapper = + privateLayout.getVisibleWrapper( + NotificationContentView.VISIBLE_TYPE_EXPANDED + ), + runningInflations = runningInflations, + applyCallback = applyCallback, + logger = logger + ) + } + } + flag = FLAG_CONTENT_VIEW_HEADS_UP + if (reInflateFlags and flag != 0) { + if (result.remoteViews.headsUp != null) { + val isNewView = + !canReapplyRemoteView( + newView = result.remoteViews.headsUp, + oldView = + remoteViewCache.getCachedView(entry, FLAG_CONTENT_VIEW_HEADS_UP) + ) + val applyCallback: ApplyCallback = + object : ApplyCallback() { + override fun setResultView(v: View) { + logger.logAsyncTaskProgress(entry, "heads up view applied") + result.inflatedHeadsUpView = v + } + + override val remoteView: RemoteViews + get() = result.remoteViews.headsUp + } + logger.logAsyncTaskProgress(entry, "applying heads up view") + applyRemoteView( + inflationExecutor = inflationExecutor, + inflateSynchronously = inflateSynchronously, + isMinimized = isMinimized, + result = result, + reInflateFlags = reInflateFlags, + inflationId = flag, + remoteViewCache = remoteViewCache, + entry = entry, + row = row, + isNewView = isNewView, + remoteViewClickHandler = remoteViewClickHandler, + callback = callback, + parentLayout = privateLayout, + existingView = privateLayout.headsUpChild, + existingWrapper = + privateLayout.getVisibleWrapper( + NotificationContentView.VISIBLE_TYPE_HEADSUP + ), + runningInflations = runningInflations, + applyCallback = applyCallback, + logger = logger + ) + } + } + flag = FLAG_CONTENT_VIEW_PUBLIC + if (reInflateFlags and flag != 0) { + val isNewView = + !canReapplyRemoteView( + newView = result.remoteViews.public, + oldView = remoteViewCache.getCachedView(entry, FLAG_CONTENT_VIEW_PUBLIC) + ) + val applyCallback: ApplyCallback = + object : ApplyCallback() { + override fun setResultView(v: View) { + logger.logAsyncTaskProgress(entry, "public view applied") + result.inflatedPublicView = v + } + + override val remoteView: RemoteViews + get() = result.remoteViews.public!! + } + logger.logAsyncTaskProgress(entry, "applying public view") + applyRemoteView( + inflationExecutor = inflationExecutor, + inflateSynchronously = inflateSynchronously, + isMinimized = isMinimized, + result = result, + reInflateFlags = reInflateFlags, + inflationId = flag, + remoteViewCache = remoteViewCache, + entry = entry, + row = row, + isNewView = isNewView, + remoteViewClickHandler = remoteViewClickHandler, + callback = callback, + parentLayout = publicLayout, + existingView = publicLayout.contractedChild, + existingWrapper = + publicLayout.getVisibleWrapper( + NotificationContentView.VISIBLE_TYPE_CONTRACTED + ), + runningInflations = runningInflations, + applyCallback = applyCallback, + logger = logger + ) + } + if (AsyncGroupHeaderViewInflation.isEnabled) { + val childrenContainer: NotificationChildrenContainer = + row.getChildrenContainerNonNull() + if (reInflateFlags and FLAG_GROUP_SUMMARY_HEADER != 0) { + val isNewView = + !canReapplyRemoteView( + newView = result.remoteViews.normalGroupHeader, + oldView = + remoteViewCache.getCachedView(entry, FLAG_GROUP_SUMMARY_HEADER) + ) + val applyCallback: ApplyCallback = + object : ApplyCallback() { + override fun setResultView(v: View) { + logger.logAsyncTaskProgress(entry, "group header view applied") + result.inflatedGroupHeaderView = v as NotificationHeaderView? + } + + override val remoteView: RemoteViews + get() = result.remoteViews.normalGroupHeader!! + } + logger.logAsyncTaskProgress(entry, "applying group header view") + applyRemoteView( + inflationExecutor = inflationExecutor, + inflateSynchronously = inflateSynchronously, + isMinimized = isMinimized, + result = result, + reInflateFlags = reInflateFlags, + inflationId = FLAG_GROUP_SUMMARY_HEADER, + remoteViewCache = remoteViewCache, + entry = entry, + row = row, + isNewView = isNewView, + remoteViewClickHandler = remoteViewClickHandler, + callback = callback, + parentLayout = childrenContainer, + existingView = childrenContainer.groupHeader, + existingWrapper = childrenContainer.notificationHeaderWrapper, + runningInflations = runningInflations, + applyCallback = applyCallback, + logger = logger + ) + } + if (reInflateFlags and FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER != 0) { + val isNewView = + !canReapplyRemoteView( + newView = result.remoteViews.minimizedGroupHeader, + oldView = + remoteViewCache.getCachedView( + entry, + FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER + ) + ) + val applyCallback: ApplyCallback = + object : ApplyCallback() { + override fun setResultView(v: View) { + logger.logAsyncTaskProgress( + entry, + "low-priority group header view applied" + ) + result.inflatedMinimizedGroupHeaderView = + v as NotificationHeaderView? + } + + override val remoteView: RemoteViews + get() = result.remoteViews.minimizedGroupHeader!! + } + logger.logAsyncTaskProgress(entry, "applying low priority group header view") + applyRemoteView( + inflationExecutor = inflationExecutor, + inflateSynchronously = inflateSynchronously, + isMinimized = isMinimized, + result = result, + reInflateFlags = reInflateFlags, + inflationId = FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER, + remoteViewCache = remoteViewCache, + entry = entry, + row = row, + isNewView = isNewView, + remoteViewClickHandler = remoteViewClickHandler, + callback = callback, + parentLayout = childrenContainer, + existingView = childrenContainer.minimizedNotificationHeader, + existingWrapper = childrenContainer.minimizedGroupHeaderWrapper, + runningInflations = runningInflations, + applyCallback = applyCallback, + logger = logger + ) + } + } + + // Let's try to finish, maybe nobody is even inflating anything + finishIfDone( + result, + isMinimized, + reInflateFlags, + remoteViewCache, + runningInflations, + callback, + entry, + row, + logger + ) + val cancellationSignal = CancellationSignal() + cancellationSignal.setOnCancelListener { + logger.logAsyncTaskProgress(entry, "apply cancelled") + Trace.endAsyncSection(APPLY_TRACE_METHOD, System.identityHashCode(row)) + runningInflations.values.forEach( + Consumer { obj: CancellationSignal -> obj.cancel() } + ) + } + return cancellationSignal + } + + @VisibleForTesting + fun applyRemoteView( + inflationExecutor: Executor?, + inflateSynchronously: Boolean, + isMinimized: Boolean, + result: InflationProgress, + @InflationFlag reInflateFlags: Int, + @InflationFlag inflationId: Int, + remoteViewCache: NotifRemoteViewCache, + entry: NotificationEntry, + row: ExpandableNotificationRow, + isNewView: Boolean, + remoteViewClickHandler: InteractionHandler?, + callback: InflationCallback?, + parentLayout: ViewGroup?, + existingView: View?, + existingWrapper: NotificationViewWrapper?, + runningInflations: HashMap<Int, CancellationSignal>, + applyCallback: ApplyCallback, + logger: NotificationRowContentBinderLogger + ) { + val newContentView: RemoteViews = applyCallback.remoteView + if (inflateSynchronously) { + try { + if (isNewView) { + val v: View = + newContentView.apply( + result.packageContext, + parentLayout, + remoteViewClickHandler + ) + validateView(v, entry, row.resources) + applyCallback.setResultView(v) + } else { + requireNotNull(existingView) + requireNotNull(existingWrapper) + newContentView.reapply( + result.packageContext, + existingView, + remoteViewClickHandler + ) + validateView(existingView, entry, row.resources) + existingWrapper.onReinflated() + } + } catch (e: Exception) { + handleInflationError( + runningInflations, + e, + row.entry, + callback, + logger, + "applying view synchronously" + ) + // Add a running inflation to make sure we don't trigger callbacks. + // Safe to do because only happens in tests. + runningInflations[inflationId] = CancellationSignal() + } + return + } + val listener: OnViewAppliedListener = + object : OnViewAppliedListener { + override fun onViewInflated(v: View) { + if (v is ImageMessageConsumer) { + (v as ImageMessageConsumer).setImageResolver(row.imageResolver) + } + } + + override fun onViewApplied(v: View) { + val invalidReason = isValidView(v, entry, row.resources) + if (invalidReason != null) { + handleInflationError( + runningInflations, + InflationException(invalidReason), + row.entry, + callback, + logger, + "applied invalid view" + ) + runningInflations.remove(inflationId) + return + } + if (isNewView) { + applyCallback.setResultView(v) + } else { + existingWrapper?.onReinflated() + } + runningInflations.remove(inflationId) + finishIfDone( + result, + isMinimized, + reInflateFlags, + remoteViewCache, + runningInflations, + callback, + entry, + row, + logger + ) + } + + override fun onError(e: Exception) { + // Uh oh the async inflation failed. Due to some bugs (see b/38190555), this + // could + // actually also be a system issue, so let's try on the UI thread again to + // be safe. + try { + val newView = + if (isNewView) { + newContentView.apply( + result.packageContext, + parentLayout, + remoteViewClickHandler + ) + } else { + newContentView.reapply( + result.packageContext, + existingView, + remoteViewClickHandler + ) + existingView!! + } + Log.wtf( + TAG, + "Async Inflation failed but normal inflation finished normally.", + e + ) + onViewApplied(newView) + } catch (anotherException: Exception) { + runningInflations.remove(inflationId) + handleInflationError( + runningInflations, + e, + row.entry, + callback, + logger, + "applying view" + ) + } + } + } + val cancellationSignal: CancellationSignal = + if (isNewView) { + newContentView.applyAsync( + result.packageContext, + parentLayout, + inflationExecutor, + listener, + remoteViewClickHandler + ) + } else { + newContentView.reapplyAsync( + result.packageContext, + existingView, + inflationExecutor, + listener, + remoteViewClickHandler + ) + } + runningInflations[inflationId] = cancellationSignal + } + + /** + * Checks if the given View is a valid notification View. + * + * @return null == valid, non-null == invalid, String represents reason for rejection. + */ + @VisibleForTesting + fun isValidView(view: View, entry: NotificationEntry, resources: Resources): String? { + return if (!satisfiesMinHeightRequirement(view, entry, resources)) { + "inflated notification does not meet minimum height requirement" + } else null + } + + private fun satisfiesMinHeightRequirement( + view: View, + entry: NotificationEntry, + resources: Resources + ): Boolean { + return if (!requiresHeightCheck(entry)) { + true + } else + TraceUtils.trace("NotificationContentInflater#satisfiesMinHeightRequirement") { + val heightSpec = + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) + val referenceWidth = + resources.getDimensionPixelSize( + R.dimen.notification_validation_reference_width + ) + val widthSpec = + View.MeasureSpec.makeMeasureSpec(referenceWidth, View.MeasureSpec.EXACTLY) + view.measure(widthSpec, heightSpec) + val minHeight = + resources.getDimensionPixelSize( + R.dimen.notification_validation_minimum_allowed_height + ) + view.measuredHeight >= minHeight + } + } + + /** + * Notifications with undecorated custom views need to satisfy a minimum height to avoid + * visual issues. + */ + private fun requiresHeightCheck(entry: NotificationEntry): Boolean { + // Undecorated custom views are disallowed from S onwards + if (entry.targetSdk >= Build.VERSION_CODES.S) { + return false + } + // No need to check if the app isn't using any custom views + val notification: Notification = entry.sbn.notification + @Suppress("DEPRECATION") + return !(notification.contentView == null && + notification.bigContentView == null && + notification.headsUpContentView == null) + } + + @Throws(InflationException::class) + private fun validateView(view: View, entry: NotificationEntry, resources: Resources) { + val invalidReason = isValidView(view, entry, resources) + if (invalidReason != null) { + throw InflationException(invalidReason) + } + } + + private fun handleInflationError( + runningInflations: HashMap<Int, CancellationSignal>, + e: Exception, + notification: NotificationEntry, + callback: InflationCallback?, + logger: NotificationRowContentBinderLogger, + logContext: String + ) { + Assert.isMainThread() + logger.logAsyncTaskException(notification, logContext, e) + runningInflations.values.forEach(Consumer { obj: CancellationSignal -> obj.cancel() }) + callback?.handleInflationException(notification, e) + } + + /** + * Finish the inflation of the views + * + * @return true if the inflation was finished + */ + private fun finishIfDone( + result: InflationProgress, + isMinimized: Boolean, + @InflationFlag reInflateFlags: Int, + remoteViewCache: NotifRemoteViewCache, + runningInflations: HashMap<Int, CancellationSignal>, + endListener: InflationCallback?, + entry: NotificationEntry, + row: ExpandableNotificationRow, + logger: NotificationRowContentBinderLogger + ): Boolean { + Assert.isMainThread() + if (runningInflations.isNotEmpty()) { + return false + } + val privateLayout = row.privateLayout + val publicLayout = row.publicLayout + logger.logAsyncTaskProgress(entry, "finishing") + if (reInflateFlags and FLAG_CONTENT_VIEW_CONTRACTED != 0) { + if (result.inflatedContentView != null) { + // New view case + privateLayout.setContractedChild(result.inflatedContentView) + remoteViewCache.putCachedView( + entry, + FLAG_CONTENT_VIEW_CONTRACTED, + result.remoteViews.contracted + ) + } else if (remoteViewCache.hasCachedView(entry, FLAG_CONTENT_VIEW_CONTRACTED)) { + // Reinflation case. Only update if it's still cached (i.e. view has not been + // freed while inflating). + remoteViewCache.putCachedView( + entry, + FLAG_CONTENT_VIEW_CONTRACTED, + result.remoteViews.contracted + ) + } + } + if (reInflateFlags and FLAG_CONTENT_VIEW_EXPANDED != 0) { + if (result.inflatedExpandedView != null) { + privateLayout.setExpandedChild(result.inflatedExpandedView) + remoteViewCache.putCachedView( + entry, + FLAG_CONTENT_VIEW_EXPANDED, + result.remoteViews.expanded + ) + } else if (result.remoteViews.expanded == null) { + privateLayout.setExpandedChild(null) + remoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_EXPANDED) + } else if (remoteViewCache.hasCachedView(entry, FLAG_CONTENT_VIEW_EXPANDED)) { + remoteViewCache.putCachedView( + entry, + FLAG_CONTENT_VIEW_EXPANDED, + result.remoteViews.expanded + ) + } + if (result.remoteViews.expanded != null) { + privateLayout.setExpandedInflatedSmartReplies( + result.expandedInflatedSmartReplies + ) + } else { + privateLayout.setExpandedInflatedSmartReplies(null) + } + row.setExpandable(result.remoteViews.expanded != null) + } + if (reInflateFlags and FLAG_CONTENT_VIEW_HEADS_UP != 0) { + if (result.inflatedHeadsUpView != null) { + privateLayout.setHeadsUpChild(result.inflatedHeadsUpView) + remoteViewCache.putCachedView( + entry, + FLAG_CONTENT_VIEW_HEADS_UP, + result.remoteViews.headsUp + ) + } else if (result.remoteViews.headsUp == null) { + privateLayout.setHeadsUpChild(null) + remoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_HEADS_UP) + } else if (remoteViewCache.hasCachedView(entry, FLAG_CONTENT_VIEW_HEADS_UP)) { + remoteViewCache.putCachedView( + entry, + FLAG_CONTENT_VIEW_HEADS_UP, + result.remoteViews.headsUp + ) + } + if (result.remoteViews.headsUp != null) { + privateLayout.setHeadsUpInflatedSmartReplies(result.headsUpInflatedSmartReplies) + } else { + privateLayout.setHeadsUpInflatedSmartReplies(null) + } + } + if ( + AsyncHybridViewInflation.isEnabled && + reInflateFlags and FLAG_CONTENT_VIEW_SINGLE_LINE != 0 + ) { + val singleLineView = result.inflatedSingleLineView + val viewModel = result.contentModel.singleLineViewModel + if (singleLineView != null && viewModel != null) { + if (viewModel.isConversation()) { + SingleLineConversationViewBinder.bind(viewModel, singleLineView) + } else { + SingleLineViewBinder.bind(viewModel, singleLineView) + } + privateLayout.setSingleLineView(result.inflatedSingleLineView) + } + } + result.inflatedSmartReplyState?.let { privateLayout.setInflatedSmartReplyState(it) } + if (reInflateFlags and FLAG_CONTENT_VIEW_PUBLIC != 0) { + if (result.inflatedPublicView != null) { + publicLayout.setContractedChild(result.inflatedPublicView) + remoteViewCache.putCachedView( + entry, + FLAG_CONTENT_VIEW_PUBLIC, + result.remoteViews.public + ) + } else if (remoteViewCache.hasCachedView(entry, FLAG_CONTENT_VIEW_PUBLIC)) { + remoteViewCache.putCachedView( + entry, + FLAG_CONTENT_VIEW_PUBLIC, + result.remoteViews.public + ) + } + } + if (AsyncGroupHeaderViewInflation.isEnabled) { + if (reInflateFlags and FLAG_GROUP_SUMMARY_HEADER != 0) { + if (result.inflatedGroupHeaderView != null) { + // We need to set if the row is minimized before setting the group header to + // make sure the setting of header view works correctly + row.setIsMinimized(isMinimized) + row.setGroupHeader(/* headerView= */ result.inflatedGroupHeaderView) + remoteViewCache.putCachedView( + entry, + FLAG_GROUP_SUMMARY_HEADER, + result.remoteViews.normalGroupHeader + ) + } else if (remoteViewCache.hasCachedView(entry, FLAG_GROUP_SUMMARY_HEADER)) { + // Re-inflation case. Only update if it's still cached (i.e. view has not + // been freed while inflating). + remoteViewCache.putCachedView( + entry, + FLAG_GROUP_SUMMARY_HEADER, + result.remoteViews.normalGroupHeader + ) + } + } + if (reInflateFlags and FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER != 0) { + if (result.inflatedMinimizedGroupHeaderView != null) { + // We need to set if the row is minimized before setting the group header to + // make sure the setting of header view works correctly + row.setIsMinimized(isMinimized) + row.setMinimizedGroupHeader( + /* headerView= */ result.inflatedMinimizedGroupHeaderView + ) + remoteViewCache.putCachedView( + entry, + FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER, + result.remoteViews.minimizedGroupHeader + ) + } else if ( + remoteViewCache.hasCachedView(entry, FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER) + ) { + // Re-inflation case. Only update if it's still cached (i.e. view has not + // been freed while inflating). + remoteViewCache.putCachedView( + entry, + FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER, + result.remoteViews.normalGroupHeader + ) + } + } + } + entry.setContentModel(result.contentModel) + Trace.endAsyncSection(APPLY_TRACE_METHOD, System.identityHashCode(row)) + endListener?.onAsyncInflationFinished(entry) + return true + } + + private fun createExpandedView( + builder: Notification.Builder, + isMinimized: Boolean + ): RemoteViews? { + @Suppress("DEPRECATION") + val bigContentView: RemoteViews? = builder.createBigContentView() + if (bigContentView != null) { + return bigContentView + } + if (isMinimized) { + @Suppress("DEPRECATION") val contentView: RemoteViews = builder.createContentView() + Notification.Builder.makeHeaderExpanded(contentView) + return contentView + } + return null + } + + private fun createContentView( + builder: Notification.Builder, + isMinimized: Boolean, + useLarge: Boolean + ): RemoteViews { + return if (isMinimized) { + builder.makeLowPriorityContentView(false /* useRegularSubtext */) + } else builder.createContentView(useLarge) + } + + /** + * @param newView The new view that will be applied + * @param oldView The old view that was applied to the existing view before + * @return `true` if the RemoteViews are the same and the view can be reused to reapply. + */ + @VisibleForTesting + fun canReapplyRemoteView(newView: RemoteViews?, oldView: RemoteViews?): Boolean { + return newView == null && oldView == null || + newView != null && + oldView != null && + oldView.getPackage() != null && + newView.getPackage() != null && + newView.getPackage() == oldView.getPackage() && + newView.layoutId == oldView.layoutId && + !oldView.hasFlags(RemoteViews.FLAG_REAPPLY_DISALLOWED) + } + + private const val ASYNC_TASK_TRACE_METHOD = + "NotificationRowContentBinderImpl.AsyncInflationTask" + private const val APPLY_TRACE_METHOD = "NotificationRowContentBinderImpl#apply" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java index 17c20268bc1c..84f2f6670839 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java @@ -17,9 +17,13 @@ package com.android.systemui.statusbar.notification.row; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor; import dagger.Binds; import dagger.Module; +import dagger.Provides; + +import javax.inject.Provider; /** * Dagger Module containing notification row and view inflation implementations. @@ -30,10 +34,18 @@ public abstract class NotificationRowModule { /** * Provides notification row content binder instance. */ - @Binds + @Provides @SysUISingleton - public abstract NotificationRowContentBinder provideNotificationRowContentBinder( - NotificationContentInflater contentBinderImpl); + public static NotificationRowContentBinder provideNotificationRowContentBinder( + Provider<NotificationContentInflater> legacyImpl, + Provider<NotificationRowContentBinderImpl> refactoredImpl + ) { + if (NotificationRowContentBinderRefactor.isEnabled()) { + return refactoredImpl.get(); + } else { + return legacyImpl.get(); + } + } /** * Provides notification remote view cache instance. diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingConfig.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/HeadsUpStatusBarModel.kt index 23dbc26d40d3..e43ce76d6482 100644 --- a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/HeadsUpStatusBarModel.kt @@ -14,8 +14,9 @@ * limitations under the License. */ -package com.android.systemui.recordissue +package com.android.systemui.statusbar.notification.row.shared -import com.android.traceur.TraceUtils.PresetTraceType - -data class IssueRecordingConfig(val screenRecord: Boolean, val traceType: PresetTraceType) +class HeadsUpStatusBarModel( + val privateText: CharSequence, + val publicText: CharSequence, +) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/NewRemoteViews.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/NewRemoteViews.kt new file mode 100644 index 000000000000..63bba86464b4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/NewRemoteViews.kt @@ -0,0 +1,28 @@ +/* + * 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.row.shared + +import android.widget.RemoteViews + +class NewRemoteViews( + val contracted: RemoteViews? = null, + val headsUp: RemoteViews? = null, + val expanded: RemoteViews? = null, + val public: RemoteViews? = null, + val normalGroupHeader: RemoteViews? = null, + val minimizedGroupHeader: RemoteViews? = null, +) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/NotificationContentModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/NotificationContentModel.kt new file mode 100644 index 000000000000..b2421bc72d00 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/NotificationContentModel.kt @@ -0,0 +1,24 @@ +/* + * 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.row.shared + +import com.android.systemui.statusbar.notification.row.ui.viewmodel.SingleLineViewModel + +data class NotificationContentModel( + val headsUpStatusBarModel: HeadsUpStatusBarModel, + val singleLineViewModel: SingleLineViewModel? = null, +) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt index fc28a99ef4ef..fabb696d9182 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt @@ -13,7 +13,9 @@ import android.annotation.IntDef [ BUCKET_UNKNOWN, BUCKET_MEDIA_CONTROLS, + BUCKET_TOP_ONGOING, BUCKET_HEADS_UP, + BUCKET_TOP_UNSEEN, BUCKET_FOREGROUND_SERVICE, BUCKET_PRIORITY_PEOPLE, BUCKET_PEOPLE, @@ -21,11 +23,28 @@ import android.annotation.IntDef BUCKET_SILENT ] ) -annotation class PriorityBucket +annotation class PriorityBucket { + companion object { + fun getAllInOrder(): IntArray = + intArrayOf( + BUCKET_MEDIA_CONTROLS, + BUCKET_TOP_ONGOING, + BUCKET_HEADS_UP, + BUCKET_TOP_UNSEEN, + BUCKET_FOREGROUND_SERVICE, + BUCKET_PRIORITY_PEOPLE, + BUCKET_PEOPLE, + BUCKET_ALERTING, + BUCKET_SILENT, + ) + } +} const val BUCKET_UNKNOWN = 0 const val BUCKET_MEDIA_CONTROLS = 1 +const val BUCKET_TOP_ONGOING = 8 const val BUCKET_HEADS_UP = 2 +const val BUCKET_TOP_UNSEEN = 9 const val BUCKET_FOREGROUND_SERVICE = 3 const val BUCKET_PRIORITY_PEOPLE = 7 const val BUCKET_PEOPLE = 4 diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt index 4b0b1e0029f3..391bc43a784c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt @@ -73,7 +73,8 @@ constructor( private var maxNotificationsExcludesMedia = false /** Whether we allow keyguard to show less important notifications above the shelf. */ - private var limitLockScreenToImportant = false + private val limitLockScreenToOneImportant + get() = NotificationMinimalismPrototype.V2.isEnabled /** Minimum space between two notifications, see [calculateGapAndDividerHeight]. */ private var dividerHeight by notNull<Float>() @@ -89,7 +90,7 @@ constructor( } private fun allowedByPolicy(stackHeight: StackHeight): Boolean = - if (limitLockScreenToImportant && stackHeight.includesLessImportantNotification) { + if (stackHeight.shouldForceIntoShelf) { log { "\tallowedByPolicy = false" } false } else { @@ -333,8 +334,8 @@ constructor( // changes during the lockscreen <=> full shade transition. val shelfHeightWithSpaceBefore: Float, - /** Whether this stack height includes less at least one important notification. */ - val includesLessImportantNotification: Boolean + /** Whether the stack should actually be forced into the shelf before this height. */ + val shouldForceIntoShelf: Boolean ) private fun computeHeightPerNotificationLimit( @@ -347,7 +348,7 @@ constructor( var previous: ExpandableView? = null val onLockscreen = onLockscreen() - var includesLessImportantNotification = false + val counter = if (limitLockScreenToOneImportant) BucketTypeCounter() else null // Only shelf. This should never happen, since we allow 1 view minimum (EmptyViewState). yield( @@ -355,7 +356,7 @@ constructor( notifsHeight = 0f, notifsHeightSavingSpace = 0f, shelfHeightWithSpaceBefore = shelfHeight, - includesLessImportantNotification = includesLessImportantNotification, + shouldForceIntoShelf = false, ) ) @@ -381,17 +382,9 @@ constructor( spaceBeforeShelf + shelfHeight } - if (limitLockScreenToImportant && !includesLessImportantNotification) { - val bucket = (currentNotification as? ExpandableNotificationRow)?.entry?.bucket - includesLessImportantNotification = - when (bucket) { - null, - BUCKET_MEDIA_CONTROLS, - BUCKET_HEADS_UP, - BUCKET_FOREGROUND_SERVICE, - BUCKET_PRIORITY_PEOPLE -> false - else -> true - } + if (counter != null) { + val entry = (currentNotification as? ExpandableNotificationRow)?.entry + counter.incrementForBucket(entry?.bucket) } log { @@ -404,7 +397,7 @@ constructor( notifsHeight = notifications, notifsHeightSavingSpace = notifsWithCollapsedHun, shelfHeightWithSpaceBefore = shelfWithSpaceBefore, - includesLessImportantNotification = includesLessImportantNotification, + shouldForceIntoShelf = counter?.shouldForceIntoShelf() ?: false ) ) } @@ -415,8 +408,6 @@ constructor( infiniteIfNegative( if (NotificationMinimalismPrototype.V1.isEnabled) { NotificationMinimalismPrototype.V1.maxNotifs - } else if (NotificationMinimalismPrototype.V2.isEnabled) { - 1 } else { resources.getInteger(R.integer.keyguard_max_notification_count) } @@ -424,7 +415,6 @@ constructor( maxNotificationsExcludesMedia = NotificationMinimalismPrototype.V1.isEnabled || NotificationMinimalismPrototype.V2.isEnabled - limitLockScreenToImportant = NotificationMinimalismPrototype.V2.isEnabled dividerHeight = max(1f, resources.getDimensionPixelSize(R.dimen.notification_divider_height).toFloat()) @@ -552,4 +542,24 @@ constructor( /** Returns the last index where [predicate] returns true, or -1 if it was always false. */ private fun <T> Sequence<T>.lastIndexWhile(predicate: (T) -> Boolean): Int = takeWhile(predicate).count() - 1 + + /** Counts the number of notifications for each type of bucket */ + data class BucketTypeCounter( + var ongoing: Int = 0, + var important: Int = 0, + var other: Int = 0, + ) { + fun incrementForBucket(@PriorityBucket bucket: Int?) { + when (bucket) { + BUCKET_MEDIA_CONTROLS, + null -> Unit // not counted as notifications at all + BUCKET_TOP_ONGOING -> ongoing++ + BUCKET_HEADS_UP -> important++ + BUCKET_TOP_UNSEEN -> important++ + else -> other++ + } + } + + fun shouldForceIntoShelf(): Boolean = ongoing > 1 || important > 1 || other > 0 + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java index 05a43917f7e0..7434891805ca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java @@ -288,11 +288,12 @@ public interface CentralSurfaces extends Dumpable, LifecycleOwner, CoreStartable void awakenDreams(); /** - * Handle a touch event while dreaming when the touch was initiated within a prescribed - * swipeable area. This method is provided for cases where swiping in certain areas of a dream - * should be handled by CentralSurfaces instead (e.g. swiping communal hub open). + * Handle a touch event while dreaming or on the glanceable hub when the touch was initiated + * within a prescribed swipeable area. This method is provided for cases where swiping in + * certain areas should be handled by CentralSurfaces instead (e.g. swiping hub open, opening + * the notification shade over dream or hub). */ - void handleDreamTouch(MotionEvent event); + void handleExternalShadeWindowTouch(MotionEvent event); boolean isBouncerShowing(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt index a7b54847cdf9..906baa2a42f8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt @@ -80,7 +80,7 @@ abstract class CentralSurfacesEmptyImpl : CentralSurfaces { override fun updateScrimController() {} override fun shouldIgnoreTouch() = false override fun isDeviceInteractive() = false - override fun handleDreamTouch(event: MotionEvent?) {} + override fun handleExternalShadeWindowTouch(event: MotionEvent?) {} override fun handleCommunalHubTouch(event: MotionEvent?) {} override fun awakenDreams() {} override fun isBouncerShowing() = false diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 7567f36302b4..42680ab4beba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -2954,8 +2954,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { }; @Override - public void handleDreamTouch(MotionEvent event) { - getNotificationShadeWindowViewController().handleDreamTouch(event); + public void handleExternalShadeWindowTouch(MotionEvent event) { + getNotificationShadeWindowViewController().handleExternalTouch(event); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java index cff46ab812bf..0ba4aabcb0e2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java @@ -223,7 +223,8 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da } return; } - StatusBarIcon icon = new StatusBarIcon(iconPkg, UserHandle.SYSTEM, iconId, 0, 0, "Demo"); + StatusBarIcon icon = new StatusBarIcon(iconPkg, UserHandle.SYSTEM, iconId, 0, 0, "Demo", + StatusBarIcon.Type.SystemIcon); icon.visible = true; StatusBarIconView v = new StatusBarIconView(getContext(), slot, null, false); v.setTag(slot); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.kt index 08a890dbadb5..d699b3821a36 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.kt @@ -155,6 +155,7 @@ open class StatusBarIconHolder private constructor() { 0, 0, contentDescription, + StatusBarIcon.Type.SystemIcon, ) holder.tag = state.subId return holder diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImpl.java index fabf858d0832..85213cb0ebff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImpl.java @@ -227,8 +227,8 @@ public class StatusBarIconControllerImpl implements Tunable, StatusBarIconHolder holder = mStatusBarIconList.getIconHolder(slot, 0); if (holder == null) { StatusBarIcon icon = new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(), - Icon.createWithResource( - mContext, resourceId), 0, 0, contentDescription); + Icon.createWithResource(mContext, resourceId), 0, 0, + contentDescription, StatusBarIcon.Type.SystemIcon); holder = StatusBarIconHolder.fromIcon(icon); setIcon(slot, holder); } else { @@ -295,7 +295,7 @@ public class StatusBarIconControllerImpl implements Tunable, } else { holder.setIcon(new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(), Icon.createWithResource(mContext, state.callStrengthResId), 0, 0, - state.callStrengthDescription)); + state.callStrengthDescription, StatusBarIcon.Type.SystemIcon)); } setIcon(slot, holder); } @@ -320,7 +320,7 @@ public class StatusBarIconControllerImpl implements Tunable, } else { holder.setIcon(new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(), Icon.createWithResource(mContext, state.noCallingResId), 0, 0, - state.noCallingDescription)); + state.noCallingDescription, StatusBarIcon.Type.SystemIcon)); } setIcon(slot, holder); } diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/GestureViewModelFactory.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/GestureViewModelFactory.kt new file mode 100644 index 000000000000..504bd5fbcb42 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/GestureViewModelFactory.kt @@ -0,0 +1,39 @@ +/* + * 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.touchpad.tutorial.ui + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider + +sealed class GestureTutorialViewModel : ViewModel() + +class BackGestureTutorialViewModel : GestureTutorialViewModel() + +class HomeGestureTutorialViewModel : GestureTutorialViewModel() + +class GestureViewModelFactory : ViewModelProvider.Factory { + + @Suppress("UNCHECKED_CAST") + override fun <T : ViewModel> create(modelClass: Class<T>): T { + return when (modelClass) { + BackGestureTutorialViewModel::class.java -> BackGestureTutorialViewModel() + HomeGestureTutorialViewModel::class.java -> HomeGestureTutorialViewModel() + else -> error("Unknown ViewModel class: ${modelClass.name}") + } + as T + } +} diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TouchpadTutorialViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TouchpadTutorialViewModel.kt new file mode 100644 index 000000000000..7669524ee316 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TouchpadTutorialViewModel.kt @@ -0,0 +1,43 @@ +/* + * 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.touchpad.tutorial.ui + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import javax.inject.Inject + +class TouchpadTutorialViewModel : ViewModel() { + + private val _screen = MutableStateFlow(Screen.TUTORIAL_SELECTION) + val screen: StateFlow<Screen> = _screen + + class Factory @Inject constructor() : ViewModelProvider.Factory { + + @Suppress("UNCHECKED_CAST") + override fun <T : ViewModel> create(modelClass: Class<T>): T { + return TouchpadTutorialViewModel() as T + } + } +} + +enum class Screen { + TUTORIAL_SELECTION, + BACK_GESTURE, + HOME_GESTURE, +} diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TutorialSelectionViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TutorialSelectionViewModel.kt new file mode 100644 index 000000000000..1a8272d8e7e3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TutorialSelectionViewModel.kt @@ -0,0 +1,30 @@ +/* + * 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.touchpad.tutorial.ui + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider + +class TutorialSelectionViewModel : ViewModel() + +class TutorialSelectionViewModelFactory : ViewModelProvider.Factory { + + @Suppress("UNCHECKED_CAST") + override fun <T : ViewModel> create(modelClass: Class<T>): T { + return TutorialSelectionViewModel() as T + } +} diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt new file mode 100644 index 000000000000..09dd909cd9a3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt @@ -0,0 +1,76 @@ +/* + * 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.touchpad.tutorial.ui.view + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.lifecycle.Lifecycle.State.STARTED +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.viewmodel.compose.viewModel +import com.android.compose.theme.PlatformTheme +import com.android.systemui.touchpad.tutorial.ui.BackGestureTutorialViewModel +import com.android.systemui.touchpad.tutorial.ui.GestureViewModelFactory +import com.android.systemui.touchpad.tutorial.ui.HomeGestureTutorialViewModel +import com.android.systemui.touchpad.tutorial.ui.Screen.BACK_GESTURE +import com.android.systemui.touchpad.tutorial.ui.Screen.HOME_GESTURE +import com.android.systemui.touchpad.tutorial.ui.Screen.TUTORIAL_SELECTION +import com.android.systemui.touchpad.tutorial.ui.TouchpadTutorialViewModel +import com.android.systemui.touchpad.tutorial.ui.TutorialSelectionViewModel +import com.android.systemui.touchpad.tutorial.ui.TutorialSelectionViewModelFactory +import javax.inject.Inject + +class TouchpadTutorialActivity +@Inject +constructor( + private val viewModelFactory: TouchpadTutorialViewModel.Factory, +) : ComponentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { PlatformTheme { TouchpadTutorialScreen(viewModelFactory) } } + } +} + +@Composable +fun TouchpadTutorialScreen(viewModelFactory: ViewModelProvider.Factory) { + val vm = viewModel<TouchpadTutorialViewModel>(factory = viewModelFactory) + val activeScreen by vm.screen.collectAsStateWithLifecycle(STARTED) + when (activeScreen) { + TUTORIAL_SELECTION -> TutorialSelectionScreen() + BACK_GESTURE -> BackGestureTutorialScreen() + HOME_GESTURE -> HomeGestureTutorialScreen() + } +} + +@Composable +fun TutorialSelectionScreen() { + val vm = viewModel<TutorialSelectionViewModel>(factory = TutorialSelectionViewModelFactory()) +} + +@Composable +fun BackGestureTutorialScreen() { + val vm = viewModel<BackGestureTutorialViewModel>(factory = GestureViewModelFactory()) +} + +@Composable +fun HomeGestureTutorialScreen() { + val vm = viewModel<HomeGestureTutorialViewModel>(factory = GestureViewModelFactory()) +} diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt index ed522331baef..d92127cf97cb 100644 --- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt +++ b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt @@ -19,6 +19,7 @@ import android.content.ContentResolver import android.database.ContentObserver import android.net.Uri import android.provider.Settings.SettingNotFoundException +import com.android.app.tracing.TraceUtils.trace /** * Used to interact with mainly with Settings.Global, but can also be used for Settings.System and @@ -37,6 +38,7 @@ import android.provider.Settings.SettingNotFoundException interface SettingsProxy { /** Returns the [ContentResolver] this instance was constructed with. */ fun getContentResolver(): ContentResolver + /** * Construct the content URI for a particular name/value pair, useful for monitoring changes * with a ContentObserver. @@ -45,6 +47,7 @@ interface SettingsProxy { * @return the corresponding content URI, or null if not present */ fun getUriFor(name: String): Uri + /** * Convenience wrapper around [ContentResolver.registerContentObserver].' * @@ -53,9 +56,11 @@ interface SettingsProxy { fun registerContentObserverSync(name: String, settingsObserver: ContentObserver) { registerContentObserverSync(getUriFor(name), settingsObserver) } + /** Convenience wrapper around [ContentResolver.registerContentObserver].' */ fun registerContentObserverSync(uri: Uri, settingsObserver: ContentObserver) = registerContentObserverSync(uri, false, settingsObserver) + /** * Convenience wrapper around [ContentResolver.registerContentObserver].' * @@ -66,15 +71,26 @@ interface SettingsProxy { notifyForDescendants: Boolean, settingsObserver: ContentObserver ) = registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver) + /** Convenience wrapper around [ContentResolver.registerContentObserver].' */ fun registerContentObserverSync( uri: Uri, notifyForDescendants: Boolean, settingsObserver: ContentObserver - ) = getContentResolver().registerContentObserver(uri, notifyForDescendants, settingsObserver) + ) { + trace({ "SP#registerObserver#[$uri]" }) { + getContentResolver() + .registerContentObserver(uri, notifyForDescendants, settingsObserver) + } + } + /** See [ContentResolver.unregisterContentObserver]. */ - fun unregisterContentObserverSync(settingsObserver: ContentObserver) = - getContentResolver().unregisterContentObserver(settingsObserver) + fun unregisterContentObserverSync(settingsObserver: ContentObserver) { + trace({ "SP#unregisterObserver" }) { + getContentResolver().unregisterContentObserver(settingsObserver) + } + } + /** * Look up a name in the database. * @@ -82,6 +98,7 @@ interface SettingsProxy { * @return the corresponding value, or null if not present */ fun getString(name: String): String + /** * Store a name/value pair into the database. * @@ -90,6 +107,7 @@ interface SettingsProxy { * @return true if the value was set, false on database errors */ fun putString(name: String, value: String): Boolean + /** * Store a name/value pair into the database. * @@ -120,6 +138,7 @@ interface SettingsProxy { * @see .resetToDefaults */ fun putString(name: String, value: String, tag: String, makeDefault: Boolean): Boolean + /** * Convenience function for retrieving a single secure settings value as an integer. Note that * internally setting values are always stored as strings; this function converts the string to @@ -138,6 +157,7 @@ interface SettingsProxy { def } } + /** * Convenience function for retrieving a single secure settings value as an integer. Note that * internally setting values are always stored as strings; this function converts the string to @@ -160,6 +180,7 @@ interface SettingsProxy { throw SettingNotFoundException(name) } } + /** * Convenience function for updating a single settings value as an integer. This will either * create a new entry in the table if the given name does not exist, or modify the value of the @@ -173,6 +194,7 @@ interface SettingsProxy { fun putInt(name: String, value: Int): Boolean { return putString(name, value.toString()) } + /** * Convenience function for retrieving a single secure settings value as a boolean. Note that * internally setting values are always stored as strings; this function converts the string to @@ -186,6 +208,7 @@ interface SettingsProxy { fun getBool(name: String, def: Boolean): Boolean { return getInt(name, if (def) 1 else 0) != 0 } + /** * Convenience function for retrieving a single secure settings value as a boolean. Note that * internally setting values are always stored as strings; this function converts the string to @@ -203,6 +226,7 @@ interface SettingsProxy { fun getBool(name: String): Boolean { return getInt(name) != 0 } + /** * Convenience function for updating a single settings value as a boolean. This will either * create a new entry in the table if the given name does not exist, or modify the value of the @@ -216,6 +240,7 @@ interface SettingsProxy { fun putBool(name: String, value: Boolean): Boolean { return putInt(name, if (value) 1 else 0) } + /** * Convenience function for retrieving a single secure settings value as a `long`. Note that * internally setting values are always stored as strings; this function converts the string to @@ -230,6 +255,7 @@ interface SettingsProxy { val valString = getString(name) return parseLongOrUseDefault(valString, def) } + /** * Convenience function for retrieving a single secure settings value as a `long`. Note that * internally setting values are always stored as strings; this function converts the string to @@ -248,6 +274,7 @@ interface SettingsProxy { val valString = getString(name) return parseLongOrThrow(name, valString) } + /** * Convenience function for updating a secure settings value as a long integer. This will either * create a new entry in the table if the given name does not exist, or modify the value of the @@ -261,6 +288,7 @@ interface SettingsProxy { fun putLong(name: String, value: Long): Boolean { return putString(name, value.toString()) } + /** * Convenience function for retrieving a single secure settings value as a floating point * number. Note that internally setting values are always stored as strings; this function @@ -275,6 +303,7 @@ interface SettingsProxy { val v = getString(name) return parseFloat(v, def) } + /** * Convenience function for retrieving a single secure settings value as a float. Note that * internally setting values are always stored as strings; this function converts the string to @@ -293,6 +322,7 @@ interface SettingsProxy { val v = getString(name) return parseFloatOrThrow(name, v) } + /** * Convenience function for updating a single settings value as a floating point number. This * will either create a new entry in the table if the given name does not exist, or modify the @@ -306,6 +336,7 @@ interface SettingsProxy { fun putFloat(name: String, value: Float): Boolean { return putString(name, value.toString()) } + companion object { /** Convert a string to a long, or uses a default if the string is malformed or null */ @JvmStatic @@ -319,6 +350,7 @@ interface SettingsProxy { } return value } + /** Convert a string to a long, or throws an exception if the string is malformed or null */ @JvmStatic @Throws(SettingNotFoundException::class) @@ -332,6 +364,7 @@ interface SettingsProxy { throw SettingNotFoundException(name) } } + /** Convert a string to a float, or uses a default if the string is malformed or null */ @JvmStatic fun parseFloat(v: String?, def: Float): Float { @@ -341,6 +374,7 @@ interface SettingsProxy { def } } + /** * Convert a string to a float, or throws an exception if the string is malformed or null */ diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt b/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt index ed139434d3bd..ed65f1ae1667 100644 --- a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt +++ b/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt @@ -51,6 +51,7 @@ interface UserSettingsProxy : SettingsProxy { "userId cannot be set in interface, use setter from an implementation instead." ) } + /** * Returns the actual current user handle when querying with the current user. Otherwise, * returns the passed in user id. @@ -60,9 +61,11 @@ interface UserSettingsProxy : SettingsProxy { userHandle } else userTracker.userId } + override fun registerContentObserverSync(uri: Uri, settingsObserver: ContentObserver) { registerContentObserverForUserSync(uri, settingsObserver, userId) } + /** Convenience wrapper around [ContentResolver.registerContentObserver].' */ override fun registerContentObserverSync( uri: Uri, @@ -71,6 +74,7 @@ interface UserSettingsProxy : SettingsProxy { ) { registerContentObserverForUserSync(uri, notifyForDescendants, settingsObserver, userId) } + /** * Convenience wrapper around [ContentResolver.registerContentObserver] * @@ -83,6 +87,7 @@ interface UserSettingsProxy : SettingsProxy { ) { registerContentObserverForUserSync(getUriFor(name), settingsObserver, userHandle) } + /** Convenience wrapper around [ContentResolver.registerContentObserver] */ fun registerContentObserverForUserSync( uri: Uri, @@ -91,6 +96,7 @@ interface UserSettingsProxy : SettingsProxy { ) { registerContentObserverForUserSync(uri, false, settingsObserver, userHandle) } + /** * Convenience wrapper around [ContentResolver.registerContentObserver] * @@ -109,6 +115,7 @@ interface UserSettingsProxy : SettingsProxy { userHandle ) } + /** Convenience wrapper around [ContentResolver.registerContentObserver] */ fun registerContentObserverForUserSync( uri: Uri, @@ -127,6 +134,7 @@ interface UserSettingsProxy : SettingsProxy { Unit } } + /** * Look up a name in the database. * @@ -136,8 +144,10 @@ interface UserSettingsProxy : SettingsProxy { override fun getString(name: String): String { return getStringForUser(name, userId) } + /** See [getString]. */ fun getStringForUser(name: String, userHandle: Int): String + /** * Store a name/value pair into the database. Values written by this method will be overridden * if a restore happens in the future. @@ -147,11 +157,14 @@ interface UserSettingsProxy : SettingsProxy { * @return true if the value was set, false on database errors */ fun putString(name: String, value: String, overrideableByRestore: Boolean): Boolean + override fun putString(name: String, value: String): Boolean { return putStringForUser(name, value, userId) } + /** Similar implementation to [putString] for the specified [userHandle]. */ fun putStringForUser(name: String, value: String, userHandle: Int): Boolean + /** Similar implementation to [putString] for the specified [userHandle]. */ fun putStringForUser( name: String, @@ -161,9 +174,11 @@ interface UserSettingsProxy : SettingsProxy { @UserIdInt userHandle: Int, overrideableByRestore: Boolean ): Boolean + override fun getInt(name: String, def: Int): Int { return getIntForUser(name, def, userId) } + /** Similar implementation to [getInt] for the specified [userHandle]. */ fun getIntForUser(name: String, def: Int, userHandle: Int): Int { val v = getStringForUser(name, userHandle) @@ -173,8 +188,10 @@ interface UserSettingsProxy : SettingsProxy { def } } + @Throws(SettingNotFoundException::class) override fun getInt(name: String) = getIntForUser(name, userId) + /** Similar implementation to [getInt] for the specified [userHandle]. */ @Throws(SettingNotFoundException::class) fun getIntForUser(name: String, userHandle: Int): Int { @@ -185,52 +202,66 @@ interface UserSettingsProxy : SettingsProxy { throw SettingNotFoundException(name) } } + override fun putInt(name: String, value: Int) = putIntForUser(name, value, userId) + /** Similar implementation to [getInt] for the specified [userHandle]. */ fun putIntForUser(name: String, value: Int, userHandle: Int) = putStringForUser(name, value.toString(), userHandle) + override fun getBool(name: String, def: Boolean) = getBoolForUser(name, def, userId) + /** Similar implementation to [getBool] for the specified [userHandle]. */ fun getBoolForUser(name: String, def: Boolean, userHandle: Int) = getIntForUser(name, if (def) 1 else 0, userHandle) != 0 + @Throws(SettingNotFoundException::class) override fun getBool(name: String) = getBoolForUser(name, userId) + /** Similar implementation to [getBool] for the specified [userHandle]. */ @Throws(SettingNotFoundException::class) fun getBoolForUser(name: String, userHandle: Int): Boolean { return getIntForUser(name, userHandle) != 0 } + override fun putBool(name: String, value: Boolean): Boolean { return putBoolForUser(name, value, userId) } + /** Similar implementation to [putBool] for the specified [userHandle]. */ fun putBoolForUser(name: String, value: Boolean, userHandle: Int) = putIntForUser(name, if (value) 1 else 0, userHandle) + /** Similar implementation to [getLong] for the specified [userHandle]. */ fun getLongForUser(name: String, def: Long, userHandle: Int): Long { val valString = getStringForUser(name, userHandle) return parseLongOrUseDefault(valString, def) } + /** Similar implementation to [getLong] for the specified [userHandle]. */ @Throws(SettingNotFoundException::class) fun getLongForUser(name: String, userHandle: Int): Long { val valString = getStringForUser(name, userHandle) return parseLongOrThrow(name, valString) } + /** Similar implementation to [putLong] for the specified [userHandle]. */ fun putLongForUser(name: String, value: Long, userHandle: Int) = putStringForUser(name, value.toString(), userHandle) + /** Similar implementation to [getFloat] for the specified [userHandle]. */ fun getFloatForUser(name: String, def: Float, userHandle: Int): Float { val v = getStringForUser(name, userHandle) return parseFloat(v, def) } + /** Similar implementation to [getFloat] for the specified [userHandle]. */ @Throws(SettingNotFoundException::class) fun getFloatForUser(name: String, userHandle: Int): Float { val v = getStringForUser(name, userHandle) return parseFloatOrThrow(name, v) } + /** Similar implementation to [putFloat] for the specified [userHandle]. */ fun putFloatForUser(name: String, value: Float, userHandle: Int) = putStringForUser(name, value.toString(), userHandle) diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index ce5545c05e49..e613216d10d1 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -136,6 +136,7 @@ import com.android.systemui.util.AlphaTintDrawableWrapper; import com.android.systemui.util.RoundedCornerProgressDrawable; import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.volume.domain.interactor.VolumePanelNavigationInteractor; +import com.android.systemui.volume.ui.binder.VolumeDialogMenuIconBinder; import com.android.systemui.volume.ui.navigation.VolumeNavigator; import dagger.Lazy; @@ -311,6 +312,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, private int mDialogTimeoutMillis; private final VibratorHelper mVibratorHelper; private final com.android.systemui.util.time.SystemClock mSystemClock; + private final VolumeDialogMenuIconBinder mVolumeDialogMenuIconBinder; public VolumeDialogImpl( Context context, @@ -329,6 +331,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, DumpManager dumpManager, Lazy<SecureSettings> secureSettings, VibratorHelper vibratorHelper, + VolumeDialogMenuIconBinder volumeDialogMenuIconBinder, com.android.systemui.util.time.SystemClock systemClock) { mContext = new ContextThemeWrapper(context, R.style.volume_dialog_theme); @@ -361,6 +364,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mVolumePanelNavigationInteractor = volumePanelNavigationInteractor; mVolumeNavigator = volumeNavigator; mSecureSettings = secureSettings; + mVolumeDialogMenuIconBinder = volumeDialogMenuIconBinder; mDialogTimeoutMillis = DIALOG_TIMEOUT_MILLIS; dumpManager.registerDumpable("VolumeDialogImpl", this); @@ -436,6 +440,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, if (mDevicePostureController != null) { mDevicePostureController.removeCallback(mDevicePostureControllerCallback); } + mVolumeDialogMenuIconBinder.destroy(); } @Override @@ -671,6 +676,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mSettingsView = mDialog.findViewById(R.id.settings_container); mSettingsIcon = mDialog.findViewById(R.id.settings); + mVolumeDialogMenuIconBinder.bind(mSettingsIcon); if (mRows.isEmpty()) { if (!AudioSystem.isSingleVolume(mContext)) { diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogModule.kt b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogModule.kt new file mode 100644 index 000000000000..54dc3db22b65 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogModule.kt @@ -0,0 +1,46 @@ +/* + * 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.volume + +import com.android.systemui.volume.panel.shared.flag.VolumePanelFlag +import com.android.systemui.volume.ui.viewmodel.AnimatedVolumeMenuIconViewModel +import com.android.systemui.volume.ui.viewmodel.StaticVolumeMenuIconViewModel +import com.android.systemui.volume.ui.viewmodel.VolumeMenuIconViewModel +import dagger.Lazy +import dagger.Module +import dagger.Provides + +@Module +interface VolumeDialogModule { + + companion object { + + @Provides + fun provideVolumeMenuIconViewModel( + volumePanelFlag: VolumePanelFlag, + static: Lazy<StaticVolumeMenuIconViewModel>, + animated: Lazy<AnimatedVolumeMenuIconViewModel>, + ): VolumeMenuIconViewModel { + return if (volumePanelFlag.canUseNewVolumePanel()) { + animated + } else { + static + } + .get() + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java index dc1e8cf2ea01..fd68bfb783c0 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java +++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java @@ -38,11 +38,13 @@ import com.android.systemui.volume.CsdWarningDialog; import com.android.systemui.volume.VolumeComponent; import com.android.systemui.volume.VolumeDialogComponent; import com.android.systemui.volume.VolumeDialogImpl; +import com.android.systemui.volume.VolumeDialogModule; import com.android.systemui.volume.VolumePanelDialogReceiver; import com.android.systemui.volume.VolumeUI; import com.android.systemui.volume.domain.interactor.VolumePanelNavigationInteractor; import com.android.systemui.volume.panel.dagger.VolumePanelComponent; import com.android.systemui.volume.panel.dagger.factory.VolumePanelComponentFactory; +import com.android.systemui.volume.ui.binder.VolumeDialogMenuIconBinder; import com.android.systemui.volume.ui.navigation.VolumeNavigator; import dagger.Binds; @@ -61,6 +63,7 @@ import dagger.multibindings.IntoSet; CaptioningModule.class, MediaDevicesModule.class, SpatializerModule.class, + VolumeDialogModule.class, }, subcomponents = { VolumePanelComponent.class @@ -112,6 +115,7 @@ public interface VolumeModule { DumpManager dumpManager, Lazy<SecureSettings> secureSettings, VibratorHelper vibratorHelper, + VolumeDialogMenuIconBinder volumeDialogMenuIconBinder, SystemClock systemClock) { VolumeDialogImpl impl = new VolumeDialogImpl( context, @@ -130,6 +134,7 @@ public interface VolumeModule { dumpManager, secureSettings, vibratorHelper, + volumeDialogMenuIconBinder, systemClock); impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false); impl.setAutomute(true); diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt index 6e1ebc820b08..12e624cae4d4 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt @@ -19,10 +19,10 @@ package com.android.systemui.volume.panel.component.mediaoutput.domain.interacto import android.media.session.MediaController import android.media.session.PlaybackState import com.android.settingslib.volume.data.repository.MediaControllerRepository +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaControllerChangeModel import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession -import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope import javax.inject.Inject import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -38,7 +38,7 @@ import kotlinx.coroutines.withContext /** Allows to observe and change [MediaDeviceSession] state. */ @OptIn(ExperimentalCoroutinesApi::class) -@VolumePanelScope +@SysUISingleton class MediaDeviceSessionInteractor @Inject constructor( diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt index 31a89775e916..828221001861 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt @@ -23,11 +23,12 @@ import android.util.Log import com.android.settingslib.media.MediaDevice import com.android.settingslib.volume.data.repository.LocalMediaRepository import com.android.settingslib.volume.data.repository.MediaControllerRepository +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.volume.panel.component.mediaoutput.data.repository.LocalMediaRepositoryFactory import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaDeviceSessions import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession -import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope import com.android.systemui.volume.panel.shared.model.Result import com.android.systemui.volume.panel.shared.model.filterData import com.android.systemui.volume.panel.shared.model.wrapInResult @@ -52,13 +53,13 @@ import kotlinx.coroutines.withContext /** Provides observable models about the current media session state. */ @OptIn(ExperimentalCoroutinesApi::class) -@VolumePanelScope +@SysUISingleton class MediaOutputInteractor @Inject constructor( private val localMediaRepositoryFactory: LocalMediaRepositoryFactory, private val packageManager: PackageManager, - @VolumePanelScope private val coroutineScope: CoroutineScope, + @Application private val coroutineScope: CoroutineScope, @Background private val backgroundCoroutineContext: CoroutineContext, mediaControllerRepository: MediaControllerRepository, private val mediaControllerInteractor: MediaControllerInteractor, @@ -74,7 +75,7 @@ constructor( .onStart { emit(activeSessions) } } .map { getMediaControllers(it) } - .stateIn(coroutineScope, SharingStarted.Eagerly, MediaControllers(null, null)) + .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), MediaControllers(null, null)) /** [MediaDeviceSessions] that contains currently active sessions. */ val activeMediaDeviceSessions: Flow<MediaDeviceSessions> = @@ -85,7 +86,11 @@ constructor( remote = it.remote?.mediaDeviceSession() ) } - .stateIn(coroutineScope, SharingStarted.Eagerly, MediaDeviceSessions(null, null)) + .stateIn( + coroutineScope, + SharingStarted.WhileSubscribed(), + MediaDeviceSessions(null, null) + ) /** Returns the default [MediaDeviceSession] from [activeMediaDeviceSessions] */ val defaultActiveMediaSession: StateFlow<Result<MediaDeviceSession?>> = @@ -100,7 +105,7 @@ constructor( } .wrapInResult() .flowOn(backgroundCoroutineContext) - .stateIn(coroutineScope, SharingStarted.Eagerly, Result.Loading()) + .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), Result.Loading()) private val localMediaRepository: Flow<LocalMediaRepository> = defaultActiveMediaSession diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt index 850162e65aa6..c18573ed1545 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt @@ -32,9 +32,13 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import kotlin.math.roundToInt import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch @@ -49,6 +53,7 @@ constructor( private val uiEventLogger: UiEventLogger, ) : SliderViewModel { + private val volumeChanges = MutableStateFlow<Int?>(null) private val streamsAffectedByRing = setOf( AudioManager.STREAM_RING, @@ -104,12 +109,17 @@ constructor( } .stateIn(coroutineScope, SharingStarted.Eagerly, SliderState.Empty) + init { + volumeChanges + .filterNotNull() + .onEach { audioVolumeInteractor.setVolume(audioStream, it) } + .launchIn(coroutineScope) + } + override fun onValueChanged(state: SliderState, newValue: Float) { val audioViewModel = state as? State audioViewModel ?: return - coroutineScope.launch { - audioVolumeInteractor.setVolume(audioStream, newValue.roundToInt()) - } + volumeChanges.tryEmit(newValue.roundToInt()) } override fun onValueChangeFinished() { diff --git a/packages/SystemUI/src/com/android/systemui/volume/ui/binder/VolumeDialogMenuIconBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/ui/binder/VolumeDialogMenuIconBinder.kt new file mode 100644 index 000000000000..a352e286dcfe --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/ui/binder/VolumeDialogMenuIconBinder.kt @@ -0,0 +1,79 @@ +/* + * 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.volume.ui.binder + +import android.animation.ValueAnimator +import android.graphics.drawable.Animatable2 +import android.widget.ImageView +import androidx.core.animation.doOnEnd +import com.android.systemui.common.shared.model.Icon +import com.android.systemui.common.ui.binder.IconViewBinder +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.statusbar.CrossFadeHelper +import com.android.systemui.volume.ui.viewmodel.VolumeMenuIconViewModel +import javax.inject.Inject +import kotlin.coroutines.resume +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch +import kotlinx.coroutines.suspendCancellableCoroutine + +/** Binds volume dialog menu button icon. */ +class VolumeDialogMenuIconBinder +@Inject +constructor( + @Application private val coroutineScope: CoroutineScope, + private val viewModel: VolumeMenuIconViewModel, +) { + + private var job: Job? = null + + fun bind(iconImageView: ImageView?) { + job?.cancel() + job = + iconImageView?.let { imageView -> + coroutineScope.launch { + viewModel.icon.collectLatest { icon -> + animate { CrossFadeHelper.fadeOut(imageView, it) } + IconViewBinder.bind(icon, imageView) + if (icon is Icon.Loaded && icon.drawable is Animatable2) { + icon.drawable.start() + } + animate { CrossFadeHelper.fadeIn(imageView, it) } + } + } + } + } + + private suspend fun animate(update: (value: Float) -> Unit) = + suspendCancellableCoroutine { continuation -> + val anim = ValueAnimator.ofFloat(0f, 1f) + anim.start() + anim.addUpdateListener { update(it.animatedValue as Float) } + anim.doOnEnd { continuation.resume(Unit) } + continuation.invokeOnCancellation { + anim.removeAllListeners() + anim.cancel() + } + } + + fun destroy() { + job?.cancel() + job = null + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/ui/viewmodel/VolumeMenuIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/ui/viewmodel/VolumeMenuIconViewModel.kt new file mode 100644 index 000000000000..0bd3adba503a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/ui/viewmodel/VolumeMenuIconViewModel.kt @@ -0,0 +1,81 @@ +/* + * 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.volume.ui.viewmodel + +import android.annotation.SuppressLint +import android.content.Context +import com.android.systemui.common.shared.model.Icon +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.res.R +import com.android.systemui.util.drawable.LoopedAnimatable2DrawableWrapper +import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaDeviceSessionInteractor +import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor +import com.android.systemui.volume.panel.shared.model.filterData +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChangedBy +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.mapLatest + +/** View Model that provides an icon for the menu button of the volume dialog. */ +interface VolumeMenuIconViewModel { + + val icon: Flow<Icon> +} + +@OptIn(ExperimentalCoroutinesApi::class) +@SuppressLint("UseCompatLoadingForDrawables") +class AnimatedVolumeMenuIconViewModel +@Inject +constructor( + @Application private val context: Context, + private val mediaOutputInteractor: MediaOutputInteractor, + private val mediaDeviceSessionInteractor: MediaDeviceSessionInteractor, +) : VolumeMenuIconViewModel { + + override val icon: Flow<Icon> + get() = + mediaOutputInteractor.defaultActiveMediaSession + .filterData() + .flatMapLatest { session -> + if (session == null) { + flowOf(null) + } else { + mediaDeviceSessionInteractor.playbackState(session) + } + } + .distinctUntilChangedBy { it?.isActive } + .mapLatest { playbackState -> + if (playbackState?.isActive == true) { + Icon.Loaded( + LoopedAnimatable2DrawableWrapper.fromDrawable( + context.getDrawable(R.drawable.audio_bars_playing)!! + ), + null, + ) + } else { + Icon.Resource(R.drawable.horizontal_ellipsis, null) + } + } +} + +class StaticVolumeMenuIconViewModel @Inject constructor() : VolumeMenuIconViewModel { + + override val icon: Flow<Icon> = flowOf(Icon.Resource(R.drawable.horizontal_ellipsis, null)) +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesCheckerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesCheckerTest.java new file mode 100644 index 000000000000..51f6cdb2cb89 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesCheckerTest.java @@ -0,0 +1,116 @@ +/* + * 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.accessibility.hearingaid; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; +import com.android.settingslib.bluetooth.LocalBluetoothAdapter; +import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +@SmallTest +public class HearingDevicesCheckerTest extends SysuiTestCase { + @Rule + public MockitoRule mockito = MockitoJUnit.rule(); + + private final List<CachedBluetoothDevice> mCachedDevices = new ArrayList<>(); + @Mock + private LocalBluetoothManager mLocalBluetoothManager; + @Mock + private LocalBluetoothAdapter mLocalBluetoothAdapter; + @Mock + private CachedBluetoothDeviceManager mCachedBluetoothDeviceManager; + @Mock + private CachedBluetoothDevice mCachedDevice; + @Mock + private BluetoothDevice mDevice; + private HearingDevicesChecker mDevicesChecker; + + @Before + public void setUp() { + when(mLocalBluetoothManager.getBluetoothAdapter()).thenReturn(mLocalBluetoothAdapter); + when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn( + mCachedBluetoothDeviceManager); + when(mCachedBluetoothDeviceManager.getCachedDevicesCopy()).thenReturn(mCachedDevices); + when(mCachedDevice.getDevice()).thenReturn(mDevice); + when(mDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn( + null); + + mDevicesChecker = new HearingDevicesChecker(mContext, mLocalBluetoothManager); + } + + @Test + public void isAnyPairedHearingDevice_bluetoothDisable_returnFalse() { + when(mLocalBluetoothAdapter.isEnabled()).thenReturn(false); + + assertThat(mDevicesChecker.isAnyPairedHearingDevice()).isFalse(); + } + + @Test + public void isAnyActiveHearingDevice_bluetoothDisable_returnFalse() { + when(mLocalBluetoothAdapter.isEnabled()).thenReturn(false); + + assertThat(mDevicesChecker.isAnyActiveHearingDevice()).isFalse(); + } + + @Test + public void isAnyPairedHearingDevice_hearingAidBonded_returnTrue() { + when(mLocalBluetoothAdapter.isEnabled()).thenReturn(true); + when(mCachedDevice.isHearingAidDevice()).thenReturn(true); + when(mCachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); + mCachedDevices.add(mCachedDevice); + + assertThat(mDevicesChecker.isAnyPairedHearingDevice()).isTrue(); + } + + @Test + public void isAnyActiveHearingDevice_hearingAidActiveAndConnected_returnTrue() { + when(mLocalBluetoothAdapter.isEnabled()).thenReturn(true); + when(mCachedDevice.isActiveDevice(BluetoothProfile.HEARING_AID)).thenReturn(true); + when(mCachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); + when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); + when(mDevice.isConnected()).thenReturn(true); + when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true); + mCachedDevices.add(mCachedDevice); + + assertThat(mDevicesChecker.isAnyActiveHearingDevice()).isTrue(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManagerTest.java index e9c742d63d81..cb9c26c7a4b6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManagerTest.java @@ -21,20 +21,17 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.bluetooth.BluetoothDevice; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import androidx.test.filters.SmallTest; -import com.android.settingslib.bluetooth.CachedBluetoothDevice; -import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; -import com.android.settingslib.bluetooth.LocalBluetoothAdapter; -import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.systemui.SysuiTestCase; import com.android.systemui.animation.DialogTransitionAnimator; import com.android.systemui.animation.Expandable; import com.android.systemui.statusbar.phone.SystemUIDialog; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Rule; @@ -44,9 +41,6 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; -import java.util.ArrayList; -import java.util.List; - /** Tests for {@link HearingDevicesDialogManager}. */ @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @@ -56,7 +50,8 @@ public class HearingDevicesDialogManagerTest extends SysuiTestCase { @Rule public MockitoRule mockito = MockitoJUnit.rule(); - private final List<CachedBluetoothDevice> mCachedDevices = new ArrayList<>(); + private final FakeExecutor mMainExecutor = new FakeExecutor(new FakeSystemClock()); + private final FakeExecutor mBackgroundExecutor = new FakeExecutor(new FakeSystemClock()); @Mock private Expandable mExpandable; @Mock @@ -68,13 +63,7 @@ public class HearingDevicesDialogManagerTest extends SysuiTestCase { @Mock private SystemUIDialog mDialog; @Mock - private LocalBluetoothManager mLocalBluetoothManager; - @Mock - private LocalBluetoothAdapter mLocalBluetoothAdapter; - @Mock - private CachedBluetoothDeviceManager mCachedBluetoothDeviceManager; - @Mock - private CachedBluetoothDevice mCachedDevice; + private HearingDevicesChecker mDevicesChecker; private HearingDevicesDialogManager mManager; @@ -82,36 +71,35 @@ public class HearingDevicesDialogManagerTest extends SysuiTestCase { public void setUp() { when(mDialogFactory.create(anyBoolean())).thenReturn(mDialogDelegate); when(mDialogDelegate.createDialog()).thenReturn(mDialog); - when(mLocalBluetoothManager.getBluetoothAdapter()).thenReturn(mLocalBluetoothAdapter); - when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn( - mCachedBluetoothDeviceManager); - when(mCachedBluetoothDeviceManager.getCachedDevicesCopy()).thenReturn(mCachedDevices); mManager = new HearingDevicesDialogManager( mDialogTransitionAnimator, mDialogFactory, - mLocalBluetoothManager + mDevicesChecker, + mBackgroundExecutor, + mMainExecutor ); } @Test - public void showDialog_bluetoothDisable_showPairNewDeviceTrue() { - when(mLocalBluetoothAdapter.isEnabled()).thenReturn(false); + public void showDialog_existHearingDevice_showPairNewDeviceFalse() { + when(mDevicesChecker.isAnyPairedHearingDevice()).thenReturn(true); mManager.showDialog(mExpandable); + mBackgroundExecutor.runAllReady(); + mMainExecutor.runAllReady(); - verify(mDialogFactory).create(eq(true)); + verify(mDialogFactory).create(eq(/* showPairNewDevice= */ false)); } @Test - public void showDialog_containsHearingAid_showPairNewDeviceFalse() { - when(mLocalBluetoothAdapter.isEnabled()).thenReturn(true); - when(mCachedDevice.isHearingAidDevice()).thenReturn(true); - when(mCachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); - mCachedDevices.add(mCachedDevice); + public void showDialog_noHearingDevice_showPairNewDeviceTrue() { + when(mDevicesChecker.isAnyPairedHearingDevice()).thenReturn(false); mManager.showDialog(mExpandable); + mBackgroundExecutor.runAllReady(); + mMainExecutor.runAllReady(); - verify(mDialogFactory).create(eq(false)); + verify(mDialogFactory).create(eq(/* showPairNewDevice= */ true)); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java index 3a6b07539a43..40b8fc77b50f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java @@ -21,12 +21,14 @@ import static com.android.systemui.doze.DozeMachine.State.INITIALIZED; import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -35,6 +37,7 @@ import static org.mockito.Mockito.when; import android.app.StatusBarManager; import android.hardware.Sensor; import android.hardware.display.AmbientDisplayConfiguration; +import android.platform.test.annotations.EnableFlags; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; import android.view.Display; @@ -43,6 +46,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.InstanceId; import com.android.internal.logging.UiEventLogger; +import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; import com.android.systemui.biometrics.AuthController; import com.android.systemui.broadcast.BroadcastDispatcher; @@ -71,6 +75,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -85,6 +90,7 @@ public class DozeTriggersTest extends SysuiTestCase { private DozeHost mHost; @Mock private BroadcastDispatcher mBroadcastDispatcher; + private final AmbientDisplayConfiguration mConfig = DozeConfigurationUtil.createMockConfig(); @Mock private DockManager mDockManager; @Mock @@ -105,6 +111,8 @@ public class DozeTriggersTest extends SysuiTestCase { private SelectedUserInteractor mSelectedUserInteractor; @Mock private SessionTracker mSessionTracker; + @Captor + private ArgumentCaptor<DozeHost.Callback> mHostCallbackCaptor; private DozeTriggers mTriggers; private FakeSensorManager mSensors; @@ -116,7 +124,7 @@ public class DozeTriggersTest extends SysuiTestCase { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); setupDozeTriggers( - DozeConfigurationUtil.createMockConfig(), + mConfig, DozeConfigurationUtil.createMockParameters()); } @@ -174,10 +182,69 @@ public class DozeTriggersTest extends SysuiTestCase { } @Test + public void testOnNotification_startsPulseRequest() { + // GIVEN device is dozing + Runnable pulseSuppressListener = mock(Runnable.class); + when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE); + doAnswer(invocation -> null).when(mHost).addCallback(mHostCallbackCaptor.capture()); + mTriggers.transitionTo(UNINITIALIZED, DozeMachine.State.INITIALIZED); + mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE); + clearInvocations(mMachine); + + // WHEN receive an alerting notification + mHostCallbackCaptor.getValue().onNotificationAlerted(pulseSuppressListener); + + // THEN entering to pulse + verify(mHost).setPulsePending(true); + // AND suppress listeners are NOT notified + verify(pulseSuppressListener, never()).run(); + } + + @Test + public void testOnNotification_cannotPulse_notificationSuppressed() { + // GIVEN device is dozing + Runnable pulseSuppressListener = mock(Runnable.class); + when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE); + doAnswer(invocation -> null).when(mHost).addCallback(mHostCallbackCaptor.capture()); + mTriggers.transitionTo(UNINITIALIZED, DozeMachine.State.INITIALIZED); + mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE); + clearInvocations(mMachine); + // AND pulsing is disabled + when(mConfig.pulseOnNotificationEnabled(anyInt())).thenReturn(false); + + // WHEN receive an alerting notification + mHostCallbackCaptor.getValue().onNotificationAlerted(pulseSuppressListener); + + // THEN NOT starting pulse + verify(mHost, never()).setPulsePending(anyBoolean()); + // AND the notification is suppressed + verify(pulseSuppressListener).run(); + } + + @Test + @EnableFlags(Flags.FLAG_NOTIFICATION_PULSING_FIX) + public void testOnNotification_alreadyPulsing_notificationNotSuppressed() { + // GIVEN device is pulsing + Runnable pulseSuppressListener = mock(Runnable.class); + when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_PULSING); + doAnswer(invocation -> null).when(mHost).addCallback(mHostCallbackCaptor.capture()); + mTriggers.transitionTo(UNINITIALIZED, DozeMachine.State.INITIALIZED); + mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE_PULSING); + clearInvocations(mMachine); + + // WHEN receive an alerting notification + mHostCallbackCaptor.getValue().onNotificationAlerted(pulseSuppressListener); + + // THEN entering to pulse + verify(mHost, never()).setPulsePending(anyBoolean()); + // AND suppress listeners are NOT notified + verify(pulseSuppressListener, never()).run(); + } + + @Test public void testOnNotification_noPulseIfPulseIsNotPendingAnymore() { when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE); - ArgumentCaptor<DozeHost.Callback> captor = ArgumentCaptor.forClass(DozeHost.Callback.class); - doAnswer(invocation -> null).when(mHost).addCallback(captor.capture()); + doAnswer(invocation -> null).when(mHost).addCallback(mHostCallbackCaptor.capture()); mTriggers.transitionTo(UNINITIALIZED, DozeMachine.State.INITIALIZED); mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE); @@ -189,7 +256,7 @@ public class DozeTriggersTest extends SysuiTestCase { // WHEN prox check returns FAR mProximitySensor.setLastEvent(new ThresholdSensorEvent(false, 2)); - captor.getValue().onNotificationAlerted(null /* pulseSuppressedListener */); + mHostCallbackCaptor.getValue().onNotificationAlerted(null /* pulseSuppressedListener */); mProximitySensor.alertListeners(); // THEN don't request pulse because the pending pulse was abandoned early diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java index e7caf000ef67..69e74d841919 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java @@ -85,7 +85,7 @@ public class DozeUiTest extends SysuiTestCase { mHandler = mHandlerThread.getThreadHandler(); mFakeExecutor = new FakeExecutor(new FakeSystemClock()); mDozeUi = new DozeUi(mContext, mAlarmManager, mWakeLock, mHost, mHandler, - mDozeParameters, mFakeExecutor, mDozeLog); + mHandler, mDozeParameters, mFakeExecutor, mDozeLog); mDozeUi.setDozeMachine(mMachine); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt index 86a976f30898..e02fb29d1070 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt @@ -570,13 +570,13 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest // WHEN biometrics succeeds with wake and unlock mode powerInteractor.setAwakeForTest() keyguardRepository.setBiometricUnlockState(BiometricUnlockMode.WAKE_AND_UNLOCK) - runCurrent() + advanceTimeBy(60L) assertThat(transitionRepository) .startedTransition( to = KeyguardState.GONE, from = KeyguardState.DOZING, - ownerName = "FromDozingTransitionInteractor(biometric wake and unlock)", + ownerName = "FromDozingTransitionInteractor", animatorAssertion = { it.isNotNull() } ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt index 7d4f03453fa7..201ee88cdd80 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.ui.view.layout.sections import android.view.View +import android.widget.LinearLayout import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.constraintlayout.widget.ConstraintSet.GONE @@ -58,7 +59,7 @@ class SmartspaceSectionTest : SysuiTestCase() { private val smartspaceView = View(mContext).also { it.id = sharedR.id.bc_smartspace_view } private val weatherView = View(mContext).also { it.id = sharedR.id.weather_smartspace_view } - private val dateView = View(mContext).also { it.id = sharedR.id.date_smartspace_view } + private val dateView = LinearLayout(mContext).also { it.id = sharedR.id.date_smartspace_view } private lateinit var constraintLayout: ConstraintLayout private lateinit var constraintSet: ConstraintSet @@ -109,7 +110,7 @@ class SmartspaceSectionTest : SysuiTestCase() { whenever(keyguardSmartspaceViewModel.isDateWeatherDecoupled).thenReturn(true) underTest.addViews(constraintLayout) assert(smartspaceView.parent == constraintLayout) - assert(weatherView.parent == constraintLayout) + assertThat(weatherView.parent).isEqualTo(dateView) assert(dateView.parent == constraintLayout) } @@ -127,7 +128,7 @@ class SmartspaceSectionTest : SysuiTestCase() { whenever(keyguardSmartspaceViewModel.isDateWeatherDecoupled).thenReturn(true) underTest.addViews(constraintLayout) underTest.applyConstraints(constraintSet) - assertWeatherSmartspaceConstrains(constraintSet) + assertThat(weatherView.parent).isEqualTo(dateView) val smartspaceConstraints = constraintSet.getConstraint(smartspaceView.id) assertThat(smartspaceConstraints.layout.topToBottom).isEqualTo(dateView.id) @@ -141,7 +142,6 @@ class SmartspaceSectionTest : SysuiTestCase() { hasCustomWeatherDataDisplay.value = true underTest.addViews(constraintLayout) underTest.applyConstraints(constraintSet) - assertWeatherSmartspaceConstrains(constraintSet) val dateConstraints = constraintSet.getConstraint(dateView.id) assertThat(dateConstraints.layout.bottomToTop).isEqualTo(smartspaceView.id) @@ -168,12 +168,4 @@ class SmartspaceSectionTest : SysuiTestCase() { assertThat(constraintSet.getVisibility(weatherView.id)).isEqualTo(GONE) assertThat(constraintSet.getVisibility(dateView.id)).isEqualTo(GONE) } - - private fun assertWeatherSmartspaceConstrains(cs: ConstraintSet) { - val weatherConstraints = cs.getConstraint(weatherView.id) - assertThat(weatherConstraints.layout.topToTop).isEqualTo(dateView.id) - assertThat(weatherConstraints.layout.bottomToBottom).isEqualTo(dateView.id) - assertThat(weatherConstraints.layout.startToEnd).isEqualTo(dateView.id) - assertThat(weatherConstraints.layout.startMargin).isEqualTo(4) - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt index f7b3f2ea2804..6a2637d669d5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt @@ -40,7 +40,6 @@ import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState -import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.media.controls.MediaTestUtils @@ -159,7 +158,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { testDispatcher = UnconfinedTestDispatcher() mediaCarouselController = MediaCarouselController( - applicationScope = kosmos.applicationCoroutineScope, context = context, mediaControlPanelFactory = mediaControlPanelFactory, visualStabilityProvider = visualStabilityProvider, @@ -895,10 +893,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { mediaCarouselController.updateHostVisibility = { updatedVisibility = true } mediaCarouselController.mediaCarousel = mediaCarousel - val settingsJob = - mediaCarouselController.listenForLockscreenSettingChanges( - kosmos.applicationCoroutineScope - ) + val settingsJob = mediaCarouselController.listenForLockscreenSettingChanges(this) secureSettings.putBool(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, false) val keyguardJob = mediaCarouselController.listenForAnyStateToLockscreenTransition(this) @@ -925,10 +920,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { mediaCarouselController.updateHostVisibility = { updatedVisibility = true } mediaCarouselController.mediaCarousel = mediaCarousel - val settingsJob = - mediaCarouselController.listenForLockscreenSettingChanges( - kosmos.applicationCoroutineScope - ) + val settingsJob = mediaCarouselController.listenForLockscreenSettingChanges(this) secureSettings.putBool(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, true) val keyguardJob = mediaCarouselController.listenForAnyStateToLockscreenTransition(this) diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt index 2f61579d53c3..721162099169 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt @@ -2,6 +2,7 @@ package com.android.systemui.mediaprojection.appselector.data import android.app.ActivityManager.RecentTaskInfo import android.content.pm.UserInfo +import android.graphics.Rect import android.os.UserManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest @@ -14,8 +15,10 @@ import com.android.systemui.settings.UserTracker import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever +import com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50 import com.android.wm.shell.recents.RecentTasks import com.android.wm.shell.util.GroupedRecentTaskInfo +import com.android.wm.shell.util.SplitBounds import com.google.common.truth.Truth.assertThat import java.util.Optional import java.util.function.Consumer @@ -101,6 +104,17 @@ class ShellRecentTaskListProviderTest : SysuiTestCase() { } @Test + fun loadRecentTasks_singleTaskPair_returnsTasksAsForeground() { + givenRecentTasks( + createTaskPair(taskId1 = 2, taskId2 = 3, isVisible = true), + ) + + val result = runBlocking { recentTaskListProvider.loadRecentTasks() } + + assertThat(result[0].isForegroundTask).isTrue() + } + + @Test fun loadRecentTasks_multipleTasks_returnsSecondVisibleTaskAsForegroundTask() { givenRecentTasks( createSingleTask(taskId = 1), @@ -144,6 +158,21 @@ class ShellRecentTaskListProviderTest : SysuiTestCase() { } @Test + fun loadRecentTasks_firstTaskIsGroupedAndVisible_marksBothGroupedTasksAsForeground() { + givenRecentTasks( + createTaskPair(taskId1 = 1, taskId2 = 2, isVisible = true), + createSingleTask(taskId = 3), + createSingleTask(taskId = 4), + ) + + val result = runBlocking { recentTaskListProvider.loadRecentTasks() } + + assertThat(result.map { it.isForegroundTask }) + .containsExactly(true, true, false, false) + .inOrder() + } + + @Test fun loadRecentTasks_secondTaskIsGroupedAndInvisible_marksBothGroupedTasksAsNotForeground() { givenRecentTasks( createSingleTask(taskId = 1), @@ -159,6 +188,21 @@ class ShellRecentTaskListProviderTest : SysuiTestCase() { } @Test + fun loadRecentTasks_firstTaskIsGroupedAndInvisible_marksBothGroupedTasksAsNotForeground() { + givenRecentTasks( + createTaskPair(taskId1 = 1, taskId2 = 2, isVisible = false), + createSingleTask(taskId = 3), + createSingleTask(taskId = 4), + ) + + val result = runBlocking { recentTaskListProvider.loadRecentTasks() } + + assertThat(result.map { it.isForegroundTask }) + .containsExactly(false, false, false, false) + .inOrder() + } + + @Test fun loadRecentTasks_assignsCorrectUserType() { givenRecentTasks( createSingleTask(taskId = 1, userId = 10, userType = STANDARD), @@ -224,7 +268,7 @@ class ShellRecentTaskListProviderTest : SysuiTestCase() { GroupedRecentTaskInfo.forSplitTasks( createTaskInfo(taskId1, userId1, isVisible), createTaskInfo(taskId2, userId2, isVisible), - null + SplitBounds(Rect(), Rect(), taskId1, taskId2, SNAP_TO_50_50) ) private fun createTaskInfo(taskId: Int, userId: Int, isVisible: Boolean = false) = diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java index 56a2adcef699..16a022f720ae 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java @@ -140,8 +140,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @SmallTest @@ -1620,60 +1618,6 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { verify(mAppWidgetManager, times(1)).setWidgetPreview(any(), anyInt(), any()); } - @Test - @EnableFlags({ - android.appwidget.flags.Flags.FLAG_GENERATED_PREVIEWS, - android.appwidget.flags.Flags.FLAG_DRAW_DATA_PARCEL - }) - public void testUpdateGeneratedPreviewWithDataParcel_userLocked() throws InterruptedException { - when(mUserManager.isUserUnlocked(mUserTracker.getUserHandle())).thenReturn(false); - - mManager.updateGeneratedPreviewForUser(mUserTracker.getUserHandle()); - assertThat(waitForBackgroundJob()).isTrue(); - verify(mAppWidgetManager, times(0)).setWidgetPreview(any(), anyInt(), any()); - } - - @Test - @EnableFlags({ - android.appwidget.flags.Flags.FLAG_GENERATED_PREVIEWS, - android.appwidget.flags.Flags.FLAG_DRAW_DATA_PARCEL - }) - public void testUpdateGeneratedPreviewWithDataParcel_userUnlocked() - throws InterruptedException { - when(mUserManager.isUserUnlocked(mUserTracker.getUserHandle())).thenReturn(true); - when(mAppWidgetManager.setWidgetPreview(any(), anyInt(), any())).thenReturn(true); - - mManager.updateGeneratedPreviewForUser(mUserTracker.getUserHandle()); - assertThat(waitForBackgroundJob()).isTrue(); - verify(mAppWidgetManager, times(1)).setWidgetPreview(any(), anyInt(), any()); - } - - @Test - @EnableFlags({ - android.appwidget.flags.Flags.FLAG_GENERATED_PREVIEWS, - android.appwidget.flags.Flags.FLAG_DRAW_DATA_PARCEL - }) - public void testUpdateGeneratedPreviewWithDataParcel_doesNotSetTwice() - throws InterruptedException { - when(mUserManager.isUserUnlocked(mUserTracker.getUserHandle())).thenReturn(true); - when(mAppWidgetManager.setWidgetPreview(any(), anyInt(), any())).thenReturn(true); - - mManager.updateGeneratedPreviewForUser(mUserTracker.getUserHandle()); - mManager.updateGeneratedPreviewForUser(mUserTracker.getUserHandle()); - assertThat(waitForBackgroundJob()).isTrue(); - verify(mAppWidgetManager, times(1)).setWidgetPreview(any(), anyInt(), any()); - } - - private boolean waitForBackgroundJob() throws InterruptedException { - final CountDownLatch latch = new CountDownLatch(1); - mFakeExecutor.execute(latch::countDown); - mFakeExecutor.runAllReady(); - mFakeExecutor.advanceClockToNext(); - mFakeExecutor.runAllReady(); - return latch.await(30000, TimeUnit.MILLISECONDS); - - } - private void setFinalField(String fieldName, int value) { try { Field field = NotificationManager.Policy.class.getDeclaredField(fieldName); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt index 2d282dcd1514..8aaa121640a3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt @@ -14,6 +14,7 @@ package com.android.systemui.qs import android.graphics.Rect +import android.platform.test.flag.junit.FlagsParameterization import android.testing.TestableContext import android.testing.TestableLooper import android.testing.TestableLooper.RunWithLooper @@ -25,15 +26,16 @@ import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.accessibility.AccessibilityNodeInfo import android.widget.FrameLayout import android.widget.LinearLayout -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import com.android.systemui.res.R import com.android.systemui.SysuiTestCase +import com.android.systemui.flags.DisableSceneContainer +import com.android.systemui.flags.parameterizeSceneContainerFlag import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.qs.QSTileView import com.android.systemui.qs.QSPanelControllerBase.TileRecord import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileViewImpl +import com.android.systemui.res.R import com.google.common.truth.Truth.assertThat import org.junit.After import org.junit.Before @@ -44,11 +46,17 @@ import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters -@RunWith(AndroidJUnit4::class) +@RunWith(ParameterizedAndroidJunit4::class) @RunWithLooper @SmallTest -class QSPanelTest : SysuiTestCase() { +class QSPanelTest(flags: FlagsParameterization) : SysuiTestCase() { + + init { + mSetFlagsRule.setFlagsParameterization(flags) + } @Mock private lateinit var qsLogger: QSLogger @@ -57,9 +65,8 @@ class QSPanelTest : SysuiTestCase() { private lateinit var footer: View - private val themedContext = TestableContext( - ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings) - ) + private val themedContext = + TestableContext(ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings)) @Before @Throws(Exception::class) @@ -106,38 +113,8 @@ class QSPanelTest : SysuiTestCase() { } @Test - fun testTilesFooterVisibleRTLLandscapeMedia() { - qsPanel.layoutDirection = View.LAYOUT_DIRECTION_RTL - // We need at least a tile so the layout has a height - qsPanel.tileLayout?.addTile( - QSPanelControllerBase.TileRecord( - mock(QSTile::class.java), - QSTileViewImpl(themedContext) - ) - ) - - val mediaView = FrameLayout(themedContext) - mediaView.addView(View(themedContext), MATCH_PARENT, 800) - - qsPanel.setUsingHorizontalLayout(/* horizontal */ true, mediaView, /* force */ true) - qsPanel.measure( - /* width */ View.MeasureSpec.makeMeasureSpec(3000, View.MeasureSpec.EXACTLY), - /* height */ View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY) - ) - qsPanel.layout(0, 0, qsPanel.measuredWidth, qsPanel.measuredHeight) - - val tiles = qsPanel.tileLayout as View - // Tiles are effectively to the right of media - assertThat(mediaView isLeftOf tiles) - assertThat(tiles.isVisibleToUser).isTrue() - - assertThat(mediaView isLeftOf footer) - assertThat(footer.isVisibleToUser).isTrue() - } - - @Test + @DisableSceneContainer fun testTilesFooterVisibleLandscapeMedia() { - qsPanel.layoutDirection = View.LAYOUT_DIRECTION_LTR // We need at least a tile so the layout has a height qsPanel.tileLayout?.addTile( QSPanelControllerBase.TileRecord( @@ -158,10 +135,10 @@ class QSPanelTest : SysuiTestCase() { val tiles = qsPanel.tileLayout as View // Tiles are effectively to the left of media - assertThat(tiles isLeftOf mediaView) + assertThat(tiles isLeftOf mediaView).isTrue() assertThat(tiles.isVisibleToUser).isTrue() - assertThat(footer isLeftOf mediaView) + assertThat(footer isLeftOf mediaView).isTrue() assertThat(footer.isVisibleToUser).isTrue() } @@ -169,8 +146,8 @@ class QSPanelTest : SysuiTestCase() { fun testBottomPadding() { val padding = 10 themedContext.orCreateTestableResources.addOverride( - R.dimen.qs_panel_padding_bottom, - padding + R.dimen.qs_panel_padding_bottom, + padding ) qsPanel.updatePadding() assertThat(qsPanel.paddingBottom).isEqualTo(padding) @@ -182,8 +159,8 @@ class QSPanelTest : SysuiTestCase() { val paddingCombined = 100 themedContext.orCreateTestableResources.addOverride(R.dimen.qs_panel_padding_top, padding) themedContext.orCreateTestableResources.addOverride( - R.dimen.qs_panel_padding_top, - paddingCombined + R.dimen.qs_panel_padding_top, + paddingCombined ) qsPanel.updatePadding() @@ -220,7 +197,8 @@ class QSPanelTest : SysuiTestCase() { } @Test - fun initializedWithNoMedia_tileLayoutParentIsAlwaysQsPanel() { + @DisableSceneContainer + fun initializedWithNoMedia_sceneContainerDisabled_tileLayoutParentIsAlwaysQsPanel() { lateinit var panel: QSPanel lateinit var tileLayout: View testableLooper.runWithLooper { @@ -249,6 +227,7 @@ class QSPanelTest : SysuiTestCase() { } @Test + @DisableSceneContainer fun initializeWithNoMedia_mediaNeverAttached() { lateinit var panel: QSPanel testableLooper.runWithLooper { @@ -288,6 +267,10 @@ class QSPanelTest : SysuiTestCase() { assertThat(qsPanel.tileLayout!!.maxColumns).isEqualTo(2) } + companion object { + @Parameters(name = "{0}") @JvmStatic fun getParams() = parameterizeSceneContainerFlag() + } + private infix fun View.isLeftOf(other: View): Boolean { val rect = Rect() getBoundsOnScreen(rect) diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt index 661830848682..130aafbcc175 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt @@ -19,8 +19,6 @@ package com.android.systemui.qs.tileimpl import android.content.Context import android.graphics.Rect import android.graphics.drawable.Drawable -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags import android.service.quicksettings.Tile import android.testing.TestableLooper import android.text.TextUtils @@ -30,13 +28,11 @@ import android.view.accessibility.AccessibilityNodeInfo import android.widget.TextView import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import com.android.systemui.Flags.FLAG_QUICK_SETTINGS_VISUAL_HAPTICS_LONGPRESS import com.android.systemui.res.R import com.android.systemui.SysuiTestCase import com.android.systemui.haptics.qs.QSLongPressEffect import com.android.systemui.haptics.qs.qsLongPressEffect import com.android.systemui.plugins.qs.QSTile -import com.android.systemui.qs.qsTileFactory import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import org.junit.Before @@ -540,30 +536,10 @@ class QSTileViewImplTest : SysuiTestCase() { assertThat(tileView.haveLongPressPropertiesBeenReset).isTrue() } - @Test - @EnableFlags(FLAG_QUICK_SETTINGS_VISUAL_HAPTICS_LONGPRESS) - fun onInit_withLongPressEffect_longPressEffectHasTileAndExpandable() { - val tile = kosmos.qsTileFactory.createTile("Test Tile") - tileView.init(tile) - - assertThat(tileView.isTileAddedToLongPress).isTrue() - assertThat(tileView.isExpandableAddedToLongPress).isTrue() - } - - @Test - @DisableFlags(FLAG_QUICK_SETTINGS_VISUAL_HAPTICS_LONGPRESS) - fun onInit_withoutLongPressEffect_longPressEffectDoesNotHaveTileAndExpandable() { - val tile = kosmos.qsTileFactory.createTile("Test Tile") - tileView.init(tile) - - assertThat(tileView.isTileAddedToLongPress).isFalse() - assertThat(tileView.isExpandableAddedToLongPress).isFalse() - } - class FakeTileView( context: Context, collapsed: Boolean, - private val longPressEffect: QSLongPressEffect?, + longPressEffect: QSLongPressEffect?, ) : QSTileViewImpl( ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings), collapsed, @@ -571,11 +547,6 @@ class QSTileViewImplTest : SysuiTestCase() { ) { var constantLongPressEffectDuration = 500 - val isTileAddedToLongPress: Boolean - get() = longPressEffect?.qsTile != null - val isExpandableAddedToLongPress: Boolean - get() = longPressEffect?.expandable != null - override fun getLongPressEffectDuration(): Int = constantLongPressEffectDuration fun changeState(state: QSTile.State) { handleStateChanged(state) diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java index 59ee0b843043..76c8cf081262 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java @@ -28,6 +28,7 @@ import android.os.Handler; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.provider.Settings; +import android.service.quicksettings.Tile; import android.testing.TestableLooper; import android.view.View; @@ -37,14 +38,18 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; +import com.android.systemui.accessibility.hearingaid.HearingDevicesChecker; import com.android.systemui.accessibility.hearingaid.HearingDevicesDialogManager; import com.android.systemui.animation.Expandable; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; +import com.android.systemui.res.R; +import com.android.systemui.statusbar.policy.BluetoothController; import org.junit.After; import org.junit.Before; @@ -78,7 +83,11 @@ public class HearingDevicesTileTest extends SysuiTestCase { @Mock private QSLogger mQSLogger; @Mock + private HearingDevicesChecker mDevicesChecker; + @Mock HearingDevicesDialogManager mHearingDevicesDialogManager; + @Mock + BluetoothController mBluetoothController; private TestableLooper mTestableLooper; private HearingDevicesTile mTile; @@ -98,7 +107,9 @@ public class HearingDevicesTileTest extends SysuiTestCase { mStatusBarStateController, mActivityStarter, mQSLogger, - mHearingDevicesDialogManager); + mHearingDevicesDialogManager, + mDevicesChecker, + mBluetoothController); mTile.initialize(); mTestableLooper.processAllMessages(); @@ -142,4 +153,41 @@ public class HearingDevicesTileTest extends SysuiTestCase { verify(mHearingDevicesDialogManager).showDialog(expandable); } + + @Test + public void handleUpdateState_activeHearingDevice_stateActiveConnectedLabel() { + when(mDevicesChecker.isAnyActiveHearingDevice()).thenReturn(true); + when(mDevicesChecker.isAnyPairedHearingDevice()).thenReturn(true); + + BooleanState activeState = new BooleanState(); + mTile.handleUpdateState(activeState, null); + + assertThat(activeState.state).isEqualTo(Tile.STATE_ACTIVE); + assertThat(activeState.secondaryLabel.toString()).isEqualTo( + mContext.getString(R.string.quick_settings_hearing_devices_connected)); + } + + @Test + public void handleUpdateState_bondedInactiveHearingDevice_stateInactiveDisconnectedLabel() { + when(mDevicesChecker.isAnyActiveHearingDevice()).thenReturn(false); + when(mDevicesChecker.isAnyPairedHearingDevice()).thenReturn(true); + + BooleanState disconnectedState = new BooleanState(); + mTile.handleUpdateState(disconnectedState, null); + + assertThat(disconnectedState.state).isEqualTo(Tile.STATE_INACTIVE); + assertThat(disconnectedState.secondaryLabel.toString()).isEqualTo( + mContext.getString(R.string.quick_settings_hearing_devices_disconnected)); + } + + @Test + public void handleUpdateState_noHearingDevice_stateInactive() { + when(mDevicesChecker.isAnyActiveHearingDevice()).thenReturn(false); + when(mDevicesChecker.isAnyPairedHearingDevice()).thenReturn(false); + + BooleanState inactiveState = new BooleanState(); + mTile.handleUpdateState(inactiveState, null); + + assertThat(inactiveState.state).isEqualTo(Tile.STATE_INACTIVE); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt index df59e572bd3b..73548baad377 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt @@ -72,13 +72,13 @@ class RecordIssueTileTest : SysuiTestCase() { @Mock private lateinit var dialogLauncherAnimator: DialogTransitionAnimator @Mock private lateinit var panelInteractor: PanelInteractor @Mock private lateinit var userContextProvider: UserContextProvider + @Mock private lateinit var issueRecordingState: IssueRecordingState @Mock private lateinit var traceurMessageSender: TraceurMessageSender @Mock private lateinit var delegateFactory: RecordIssueDialogDelegate.Factory @Mock private lateinit var dialogDelegate: RecordIssueDialogDelegate @Mock private lateinit var dialog: SystemUIDialog private lateinit var testableLooper: TestableLooper - private val issueRecordingState = IssueRecordingState() private lateinit var tile: RecordIssueTile @Before @@ -114,7 +114,7 @@ class RecordIssueTileTest : SysuiTestCase() { @Test fun qsTileUi_shouldLookCorrect_whenInactive() { - issueRecordingState.isRecording = false + whenever(issueRecordingState.isRecording).thenReturn(false) val testState = tile.newTileState() tile.handleUpdateState(testState, null) @@ -126,7 +126,7 @@ class RecordIssueTileTest : SysuiTestCase() { @Test fun qsTileUi_shouldLookCorrect_whenRecording() { - issueRecordingState.isRecording = true + whenever(issueRecordingState.isRecording).thenReturn(true) val testState = tile.newTileState() tile.handleUpdateState(testState, null) @@ -137,7 +137,7 @@ class RecordIssueTileTest : SysuiTestCase() { @Test fun inActiveQsTile_switchesToActive_whenClicked() { - issueRecordingState.isRecording = false + whenever(issueRecordingState.isRecording).thenReturn(false) val testState = tile.newTileState() tile.handleUpdateState(testState, null) @@ -147,7 +147,7 @@ class RecordIssueTileTest : SysuiTestCase() { @Test fun activeQsTile_switchesToInActive_whenClicked() { - issueRecordingState.isRecording = true + whenever(issueRecordingState.isRecording).thenReturn(true) val testState = tile.newTileState() tile.handleUpdateState(testState, null) @@ -157,7 +157,7 @@ class RecordIssueTileTest : SysuiTestCase() { @Test fun showPrompt_shouldUseKeyguardDismissUtil_ToShowDialog() { - issueRecordingState.isRecording = false + whenever(issueRecordingState.isRecording).thenReturn(false) tile.handleClick(null) testableLooper.processAllMessages() diff --git a/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt index ca606505af68..503c52f89b0a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt @@ -17,7 +17,6 @@ package com.android.systemui.recordissue import android.app.Dialog -import android.content.Context import android.content.SharedPreferences import android.os.UserHandle import android.testing.TestableLooper @@ -35,9 +34,8 @@ import com.android.systemui.mediaprojection.SessionCreationSource import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDisabledDialogDelegate import com.android.systemui.model.SysUiState -import com.android.systemui.qs.tiles.RecordIssueTile +import com.android.systemui.recordissue.IssueRecordingState.Companion.ISSUE_TYPE_NOT_SET import com.android.systemui.res.R -import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.statusbar.phone.SystemUIDialogManager @@ -72,7 +70,7 @@ class RecordIssueDialogDelegateTest : SysuiTestCase() { @Mock private lateinit var dprLazy: dagger.Lazy<ScreenCaptureDevicePolicyResolver> @Mock private lateinit var mediaProjectionMetricsLogger: MediaProjectionMetricsLogger @Mock private lateinit var userTracker: UserTracker - @Mock private lateinit var userFileManager: UserFileManager + @Mock private lateinit var state: IssueRecordingState @Mock private lateinit var sharedPreferences: SharedPreferences @Mock private lateinit var screenCaptureDisabledDialogDelegate: ScreenCaptureDisabledDialogDelegate @@ -90,7 +88,6 @@ class RecordIssueDialogDelegateTest : SysuiTestCase() { private lateinit var dialog: SystemUIDialog private lateinit var factory: SystemUIDialog.Factory private lateinit var latch: CountDownLatch - private var issueRecordingState = IssueRecordingState() @Before fun setup() { @@ -99,14 +96,7 @@ class RecordIssueDialogDelegateTest : SysuiTestCase() { whenever(sysuiState.setFlag(anyLong(), anyBoolean())).thenReturn(sysuiState) whenever(screenCaptureDisabledDialogDelegate.createSysUIDialog()) .thenReturn(screenCaptureDisabledDialog) - whenever( - userFileManager.getSharedPreferences( - eq(RecordIssueTile.TILE_SPEC), - eq(Context.MODE_PRIVATE), - anyInt() - ) - ) - .thenReturn(sharedPreferences) + whenever(state.issueTypeRes).thenReturn(ISSUE_TYPE_NOT_SET) factory = spy( @@ -129,9 +119,8 @@ class RecordIssueDialogDelegateTest : SysuiTestCase() { mainExecutor, dprLazy, mediaProjectionMetricsLogger, - userFileManager, screenCaptureDisabledDialogDelegate, - issueRecordingState, + state, traceurMessageSender ) { latch.countDown() @@ -190,8 +179,7 @@ class RecordIssueDialogDelegateTest : SysuiTestCase() { whenever(devicePolicyResolver.isScreenCaptureCompletelyDisabled(any<UserHandle>())) .thenReturn(false) whenever(flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)).thenReturn(true) - whenever(sharedPreferences.getBoolean(HAS_APPROVED_SCREEN_RECORDING, false)) - .thenReturn(false) + whenever(state.hasUserApprovedScreenRecording).thenReturn(false) val screenRecordSwitch = dialog.requireViewById<Switch>(R.id.screenrecord_switch) screenRecordSwitch.isChecked = true diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt new file mode 100644 index 000000000000..4945ace3b88c --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt @@ -0,0 +1,81 @@ +/* + * 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.screenshot.policy + +import android.content.ComponentName +import android.graphics.Insets +import android.graphics.Rect +import android.os.UserHandle +import android.view.Display.DEFAULT_DISPLAY +import android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_CHORD +import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN +import com.android.systemui.screenshot.ImageCapture +import com.android.systemui.screenshot.ScreenshotData +import com.android.systemui.screenshot.data.model.DisplayContentScenarios.ActivityNames.FILES +import com.android.systemui.screenshot.data.model.DisplayContentScenarios.TaskSpec +import com.android.systemui.screenshot.data.model.DisplayContentScenarios.singleFullScreen +import com.android.systemui.screenshot.data.repository.DisplayContentRepository +import com.android.systemui.screenshot.policy.TestUserIds.PERSONAL +import com.android.systemui.screenshot.policy.TestUserIds.WORK +import com.google.common.truth.Truth.assertWithMessage +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking +import org.junit.Test + +class PolicyRequestProcessorTest { + + val imageCapture = object : ImageCapture { + override fun captureDisplay(displayId: Int, crop: Rect?) = null + override suspend fun captureTask(taskId: Int) = null + } + + /** Tests behavior when no policies are applied */ + @Test + fun testProcess_defaultOwner_whenNoPolicyApplied() { + val fullScreenWork = DisplayContentRepository { + singleFullScreen(TaskSpec(taskId = 1001, name = FILES, userId = WORK)) + } + + val request = + ScreenshotData(TAKE_SCREENSHOT_FULLSCREEN, + SCREENSHOT_KEY_CHORD, + null, + topComponent = null, + screenBounds = Rect(0, 0, 1, 1), + taskId = -1, + insets = Insets.NONE, + bitmap = null, + displayId = DEFAULT_DISPLAY) + + /* Create a policy request processor with no capture policies */ + val requestProcessor = + PolicyRequestProcessor(Dispatchers.Unconfined, + imageCapture, + policies = emptyList(), + defaultOwner = UserHandle.of(PERSONAL), + defaultComponent = ComponentName("default", "Component"), + displayTasks = fullScreenWork) + + val result = runBlocking { requestProcessor.process(request) } + + assertWithMessage( + "With no policy, the screenshot should be assigned to the default user" + ).that(result.userHandle).isEqualTo(UserHandle.of(PERSONAL)) + + assertWithMessage("The topComponent of the screenshot").that(result.topComponent) + .isEqualTo(ComponentName.unflattenFromString(FILES)) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt index 4a867a8ecf22..586adbd65ce8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt @@ -519,6 +519,46 @@ class NotificationShadeWindowViewControllerTest(flags: FlagsParameterization) : } @Test + fun handleExternalTouch_intercepted_sendsOnTouch() { + // Accept dispatch and also intercept. + whenever(view.dispatchTouchEvent(any())).thenReturn(true) + whenever(view.onInterceptTouchEvent(any())).thenReturn(true) + + underTest.handleExternalTouch(DOWN_EVENT) + underTest.handleExternalTouch(MOVE_EVENT) + + // Once intercepted, both events are sent to the view. + verify(view).onTouchEvent(DOWN_EVENT) + verify(view).onTouchEvent(MOVE_EVENT) + } + + @Test + fun handleExternalTouch_notDispatched_interceptNotCalled() { + // Don't accept dispatch + whenever(view.dispatchTouchEvent(any())).thenReturn(false) + + underTest.handleExternalTouch(DOWN_EVENT) + + // Interception is not offered. + verify(view, never()).onInterceptTouchEvent(any()) + } + + @Test + fun handleExternalTouch_notIntercepted_onTouchNotSent() { + // Accept dispatch, but don't dispatch + whenever(view.dispatchTouchEvent(any())).thenReturn(true) + whenever(view.onInterceptTouchEvent(any())).thenReturn(false) + + underTest.handleExternalTouch(DOWN_EVENT) + underTest.handleExternalTouch(MOVE_EVENT) + + // Interception offered for both events, but onTouchEvent is never called. + verify(view).onInterceptTouchEvent(DOWN_EVENT) + verify(view).onInterceptTouchEvent(MOVE_EVENT) + verify(view, never()).onTouchEvent(any()) + } + + @Test fun testGetKeyguardMessageArea() = testScope.runTest { underTest.keyguardMessageArea diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java index 2b3f13986113..6ad8b8bc3637 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java @@ -18,12 +18,16 @@ package com.android.systemui.statusbar; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static java.util.Collections.singletonList; + +import android.annotation.Nullable; import android.app.Dialog; import android.graphics.drawable.Icon; import android.os.Handler; @@ -44,11 +48,13 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import org.mockito.stubbing.Answer; import java.util.Arrays; -import java.util.Collections; +import java.util.List; @SmallTest @RunWith(AndroidJUnit4.class) @@ -56,7 +62,7 @@ public class KeyboardShortcutsTest extends SysuiTestCase { @Rule public MockitoRule mockito = MockitoJUnit.rule(); - private static int DEVICE_ID = 1; + private static final int DEVICE_ID = 1; private KeyboardShortcuts mKeyboardShortcuts; @Mock private Dialog mDialog; @@ -66,26 +72,35 @@ public class KeyboardShortcutsTest extends SysuiTestCase { @Before public void setUp() { mKeyboardShortcuts = new KeyboardShortcuts(mContext, mWindowManager); - mKeyboardShortcuts.sInstance = mKeyboardShortcuts; + KeyboardShortcuts.sInstance = mKeyboardShortcuts; mKeyboardShortcuts.mKeyboardShortcutsDialog = mDialog; mKeyboardShortcuts.mContext = mContext; mKeyboardShortcuts.mBackgroundHandler = mHandler; + when(mHandler.post(any())) + .thenAnswer( + new Answer<>() { + @Override + public Object answer(InvocationOnMock invocation) { + ((Runnable) invocation.getArgument(0)).run(); + return null; + } + }); } @Test public void toggle_isShowingTrue_instanceShouldBeNull() { when(mDialog.isShowing()).thenReturn(true); - mKeyboardShortcuts.toggle(mContext, DEVICE_ID); + KeyboardShortcuts.toggle(mContext, DEVICE_ID); - assertThat(mKeyboardShortcuts.sInstance).isNull(); + assertThat(KeyboardShortcuts.sInstance).isNull(); } @Test public void toggle_isShowingFalse_showKeyboardShortcuts() { when(mDialog.isShowing()).thenReturn(false); - mKeyboardShortcuts.toggle(mContext, DEVICE_ID); + KeyboardShortcuts.toggle(mContext, DEVICE_ID); verify(mWindowManager).requestAppKeyboardShortcuts(any(), anyInt()); verify(mWindowManager).requestImeKeyboardShortcuts(any(), anyInt()); @@ -95,7 +110,7 @@ public class KeyboardShortcutsTest extends SysuiTestCase { public void sanitiseShortcuts_clearsIcons() { KeyboardShortcutGroup group = createKeyboardShortcutGroupForIconTests(); - KeyboardShortcuts.sanitiseShortcuts(Collections.singletonList(group)); + KeyboardShortcuts.sanitiseShortcuts(singletonList(group)); verify(group.getItems().get(0)).clearIcon(); verify(group.getItems().get(1)).clearIcon(); @@ -106,7 +121,7 @@ public class KeyboardShortcutsTest extends SysuiTestCase { KeyboardShortcutGroup group = createKeyboardShortcutGroupForIconTests(); group.setPackageName(null); - KeyboardShortcuts.sanitiseShortcuts(Collections.singletonList(group)); + KeyboardShortcuts.sanitiseShortcuts(singletonList(group)); verify(group.getItems().get(0)).clearIcon(); verify(group.getItems().get(1)).clearIcon(); @@ -116,16 +131,9 @@ public class KeyboardShortcutsTest extends SysuiTestCase { @EnableFlags(Flags.FLAG_VALIDATE_KEYBOARD_SHORTCUT_HELPER_ICON_URI) public void requestAppKeyboardShortcuts_callback_sanitisesIcons() { KeyboardShortcutGroup group = createKeyboardShortcutGroupForIconTests(); + KeyboardShortcuts.toggle(mContext, DEVICE_ID); - mKeyboardShortcuts.toggle(mContext, DEVICE_ID); - - ArgumentCaptor<WindowManager.KeyboardShortcutsReceiver> callbackCaptor = - ArgumentCaptor.forClass(WindowManager.KeyboardShortcutsReceiver.class); - ArgumentCaptor<Runnable> handlerRunnableCaptor = ArgumentCaptor.forClass(Runnable.class); - verify(mWindowManager).requestAppKeyboardShortcuts(callbackCaptor.capture(), anyInt()); - callbackCaptor.getValue().onKeyboardShortcutsReceived(Collections.singletonList(group)); - verify(mHandler).post(handlerRunnableCaptor.capture()); - handlerRunnableCaptor.getValue().run(); + emitAppShortcuts(singletonList(group), DEVICE_ID); verify(group.getItems().get(0)).clearIcon(); verify(group.getItems().get(1)).clearIcon(); @@ -135,20 +143,38 @@ public class KeyboardShortcutsTest extends SysuiTestCase { @EnableFlags(Flags.FLAG_VALIDATE_KEYBOARD_SHORTCUT_HELPER_ICON_URI) public void requestImeKeyboardShortcuts_callback_sanitisesIcons() { KeyboardShortcutGroup group = createKeyboardShortcutGroupForIconTests(); + KeyboardShortcuts.toggle(mContext, DEVICE_ID); - mKeyboardShortcuts.toggle(mContext, DEVICE_ID); - - ArgumentCaptor<WindowManager.KeyboardShortcutsReceiver> callbackCaptor = - ArgumentCaptor.forClass(WindowManager.KeyboardShortcutsReceiver.class); - ArgumentCaptor<Runnable> handlerRunnableCaptor = ArgumentCaptor.forClass(Runnable.class); - verify(mWindowManager).requestImeKeyboardShortcuts(callbackCaptor.capture(), anyInt()); - callbackCaptor.getValue().onKeyboardShortcutsReceived(Collections.singletonList(group)); - verify(mHandler).post(handlerRunnableCaptor.capture()); - handlerRunnableCaptor.getValue().run(); + emitImeShortcuts(singletonList(group), DEVICE_ID); verify(group.getItems().get(0)).clearIcon(); verify(group.getItems().get(1)).clearIcon(); + } + + @Test + public void onImeAndAppShortcutsReceived_appShortcutsNull_doesNotCrash() { + KeyboardShortcutGroup group = createKeyboardShortcutGroupForIconTests(); + KeyboardShortcuts.toggle(mContext, DEVICE_ID); + + emitImeShortcuts(singletonList(group), DEVICE_ID); + emitAppShortcuts(/* groups= */ null, DEVICE_ID); + } + + @Test + public void onImeAndAppShortcutsReceived_imeShortcutsNull_doesNotCrash() { + KeyboardShortcutGroup group = createKeyboardShortcutGroupForIconTests(); + KeyboardShortcuts.toggle(mContext, DEVICE_ID); + emitAppShortcuts(singletonList(group), DEVICE_ID); + emitImeShortcuts(/* groups= */ null, DEVICE_ID); + } + + @Test + public void onImeAndAppShortcutsReceived_bothNull_doesNotCrash() { + KeyboardShortcuts.toggle(mContext, DEVICE_ID); + + emitImeShortcuts(/* groups= */ null, DEVICE_ID); + emitAppShortcuts(/* groups= */ null, DEVICE_ID); } private KeyboardShortcutGroup createKeyboardShortcutGroupForIconTests() { @@ -159,9 +185,23 @@ public class KeyboardShortcutsTest extends SysuiTestCase { when(info1.getIcon()).thenReturn(icon); when(info2.getIcon()).thenReturn(icon); - KeyboardShortcutGroup group = new KeyboardShortcutGroup("label", - Arrays.asList(new KeyboardShortcutInfo[]{ info1, info2})); + KeyboardShortcutGroup group = + new KeyboardShortcutGroup("label", Arrays.asList(info1, info2)); group.setPackageName("com.example"); return group; } + + private void emitImeShortcuts(@Nullable List<KeyboardShortcutGroup> groups, int deviceId) { + ArgumentCaptor<WindowManager.KeyboardShortcutsReceiver> callbackCaptor = + ArgumentCaptor.forClass(WindowManager.KeyboardShortcutsReceiver.class); + verify(mWindowManager).requestImeKeyboardShortcuts(callbackCaptor.capture(), eq(deviceId)); + callbackCaptor.getValue().onKeyboardShortcutsReceived(groups); + } + + private void emitAppShortcuts(@Nullable List<KeyboardShortcutGroup> groups, int deviceId) { + ArgumentCaptor<WindowManager.KeyboardShortcutsReceiver> callbackCaptor = + ArgumentCaptor.forClass(WindowManager.KeyboardShortcutsReceiver.class); + verify(mWindowManager).requestAppKeyboardShortcuts(callbackCaptor.capture(), eq(deviceId)); + callbackCaptor.getValue().onKeyboardShortcutsReceived(groups); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java index b6ee46ddafeb..50131cb06631 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java @@ -97,7 +97,8 @@ public class StatusBarIconViewTest extends SysuiTestCase { mIconView = new StatusBarIconView(mContext, "test_slot", null); mStatusBarIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage", - Icon.createWithResource(mContext, R.drawable.ic_android), 0, 0, ""); + Icon.createWithResource(mContext, R.drawable.ic_android), 0, 0, "", + StatusBarIcon.Type.SystemIcon); } @Test @@ -138,7 +139,7 @@ public class StatusBarIconViewTest extends SysuiTestCase { Bitmap largeBitmap = Bitmap.createBitmap(6000, 6000, Bitmap.Config.ARGB_8888); Icon icon = Icon.createWithBitmap(largeBitmap); StatusBarIcon largeIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage", - icon, 0, 0, ""); + icon, 0, 0, "", StatusBarIcon.Type.SystemIcon); assertTrue(mIconView.set(largeIcon)); // The view should downscale the bitmap. @@ -152,7 +153,7 @@ public class StatusBarIconViewTest extends SysuiTestCase { Bitmap bitmap = Bitmap.createBitmap(60, 60, Bitmap.Config.ARGB_8888); Icon icon = Icon.createWithBitmap(bitmap); StatusBarIcon largeIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage", - icon, 0, 0, ""); + icon, 0, 0, "", StatusBarIcon.Type.SystemIcon); mIconView.setNotification(getMockSbn()); mIconView.getIcon(largeIcon); // no crash? good @@ -172,7 +173,7 @@ public class StatusBarIconViewTest extends SysuiTestCase { Bitmap bitmap = Bitmap.createBitmap(60, 60, Bitmap.Config.ARGB_8888); Icon icon = Icon.createWithBitmap(bitmap); StatusBarIcon largeIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage", - icon, 0, 0, ""); + icon, 0, 0, "", StatusBarIcon.Type.SystemIcon); mIconView.getIcon(largeIcon); // No crash? good } @@ -430,7 +431,7 @@ public class StatusBarIconViewTest extends SysuiTestCase { width, height, Bitmap.Config.ARGB_8888); Icon icon = Icon.createWithBitmap(bitmap); mStatusBarIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage", - icon, 0, 0, ""); + icon, 0, 0, "", StatusBarIcon.Type.SystemIcon); // Since we only want to verify icon scale logic here, we directly use // {@link StatusBarIconView#setImageDrawable(Drawable)} to set the image drawable // to iconView instead of call {@link StatusBarIconView#set(StatusBarIcon)}. It's to prevent diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt index 9e733be6665c..acb005f6e72f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt @@ -19,71 +19,86 @@ package com.android.systemui.statusbar.notification import android.platform.test.annotations.DisableFlags import android.provider.DeviceConfig import android.provider.Settings - import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.dx.mockito.inline.extended.ExtendedMockito - import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection import com.android.systemui.util.DeviceConfigProxyFake import com.android.systemui.util.Utils import com.android.systemui.util.mockito.any - import org.junit.After import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mockito.`when` import org.mockito.MockitoSession +import org.mockito.kotlin.whenever import org.mockito.quality.Strictness @RunWith(AndroidJUnit4::class) @SmallTest -@DisableFlags(PriorityPeopleSection.FLAG_NAME) // this class has no logic with the flag enabled +// this class has no testable logic with either of these flags enabled +@DisableFlags(PriorityPeopleSection.FLAG_NAME, NotificationMinimalismPrototype.V2.FLAG_NAME) class NotificationSectionsFeatureManagerTest : SysuiTestCase() { - var manager: NotificationSectionsFeatureManager? = null - val proxyFake = DeviceConfigProxyFake() + lateinit var manager: NotificationSectionsFeatureManager + private val proxyFake = DeviceConfigProxyFake() private lateinit var staticMockSession: MockitoSession @Before - public fun setup() { + fun setup() { manager = NotificationSectionsFeatureManager(proxyFake, mContext) - manager!!.clearCache() - staticMockSession = ExtendedMockito.mockitoSession() - .mockStatic<Utils>(Utils::class.java) - .strictness(Strictness.LENIENT) - .startMocking() - `when`(Utils.useQsMediaPlayer(any())).thenReturn(false) - Settings.Global.putInt(context.getContentResolver(), - Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 0) + manager.clearCache() + staticMockSession = + ExtendedMockito.mockitoSession() + .mockStatic(Utils::class.java) + .strictness(Strictness.LENIENT) + .startMocking() + whenever(Utils.useQsMediaPlayer(any())).thenReturn(false) + Settings.Global.putInt( + context.getContentResolver(), + Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, + 0 + ) } @After - public fun teardown() { + fun teardown() { staticMockSession.finishMocking() } @Test - public fun testPeopleFilteringOff_newInterruptionModelOn() { + fun testPeopleFilteringOff_newInterruptionModelOn() { proxyFake.setProperty( - DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_USE_PEOPLE_FILTERING, "false", false) + DeviceConfig.NAMESPACE_SYSTEMUI, + NOTIFICATIONS_USE_PEOPLE_FILTERING, + "false", + false + ) - assertFalse("People filtering should be disabled", manager!!.isFilteringEnabled()) - assertTrue("Expecting 2 buckets when people filtering is disabled", - manager!!.getNumberOfBuckets() == 2) + assertFalse("People filtering should be disabled", manager.isFilteringEnabled()) + assertTrue( + "Expecting 2 buckets when people filtering is disabled", + manager.getNumberOfBuckets() == 2 + ) } @Test - public fun testPeopleFilteringOn_newInterruptionModelOn() { + fun testPeopleFilteringOn_newInterruptionModelOn() { proxyFake.setProperty( - DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_USE_PEOPLE_FILTERING, "true", false) + DeviceConfig.NAMESPACE_SYSTEMUI, + NOTIFICATIONS_USE_PEOPLE_FILTERING, + "true", + false + ) - assertTrue("People filtering should be enabled", manager!!.isFilteringEnabled()) - assertTrue("Expecting 5 buckets when people filtering is enabled", - manager!!.getNumberOfBuckets() == 5) + assertTrue("People filtering should be enabled", manager.isFilteringEnabled()) + assertTrue( + "Expecting 5 buckets when people filtering is enabled", + manager.getNumberOfBuckets() == 5 + ) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java index 0d3ab865669e..b278f1a48b3d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java @@ -41,6 +41,7 @@ import android.os.AsyncTask; import android.os.CancellationSignal; import android.os.Handler; import android.os.Looper; +import android.platform.test.annotations.DisableFlags; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.util.TypedValue; @@ -60,6 +61,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.BindParams; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationCallback; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag; +import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor; import com.android.systemui.statusbar.policy.InflatedSmartReplyState; import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder; import com.android.systemui.statusbar.policy.SmartReplyStateInflater; @@ -81,6 +83,7 @@ import java.util.concurrent.TimeUnit; @SmallTest @RunWith(AndroidJUnit4.class) @RunWithLooper(setAsMainLooper = true) +@DisableFlags(NotificationRowContentBinderRefactor.FLAG_NAME) public class NotificationContentInflaterTest extends SysuiTestCase { private NotificationContentInflater mNotificationInflater; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt new file mode 100644 index 000000000000..e6cba1c39c85 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt @@ -0,0 +1,572 @@ +/* + * Copyright (C) 2017 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.row + +import android.app.Notification +import android.content.Context +import android.os.AsyncTask +import android.os.Build +import android.os.CancellationSignal +import android.platform.test.annotations.EnableFlags +import android.testing.TestableLooper.RunWithLooper +import android.util.TypedValue +import android.view.View +import android.view.ViewGroup +import android.widget.RemoteViews +import android.widget.TextView +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.res.R +import com.android.systemui.statusbar.notification.ConversationNotificationProcessor +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.BindParams +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationCallback +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag +import com.android.systemui.statusbar.notification.row.shared.HeadsUpStatusBarModel +import com.android.systemui.statusbar.notification.row.shared.NewRemoteViews +import com.android.systemui.statusbar.notification.row.shared.NotificationContentModel +import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor +import com.android.systemui.statusbar.policy.InflatedSmartReplyState +import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder +import com.android.systemui.statusbar.policy.SmartReplyStateInflater +import com.android.systemui.util.concurrency.mockExecutorHandler +import java.util.concurrent.CountDownLatch +import java.util.concurrent.Executor +import java.util.concurrent.TimeUnit +import org.junit.Assert +import org.junit.Before +import org.junit.Ignore +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.spy +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@SmallTest +@RunWith(AndroidJUnit4::class) +@RunWithLooper +@EnableFlags(NotificationRowContentBinderRefactor.FLAG_NAME) +class NotificationRowContentBinderImplTest : SysuiTestCase() { + private lateinit var mNotificationInflater: NotificationRowContentBinderImpl + private lateinit var mBuilder: Notification.Builder + private lateinit var mRow: ExpandableNotificationRow + private lateinit var mHelper: NotificationTestHelper + + private var mCache: NotifRemoteViewCache = mock() + private var mConversationNotificationProcessor: ConversationNotificationProcessor = mock() + private var mInflatedSmartReplyState: InflatedSmartReplyState = mock() + private var mInflatedSmartReplies: InflatedSmartReplyViewHolder = mock() + private var mNotifLayoutInflaterFactoryProvider: NotifLayoutInflaterFactory.Provider = mock() + private var mHeadsUpStyleProvider: HeadsUpStyleProvider = mock() + private var mNotifLayoutInflaterFactory: NotifLayoutInflaterFactory = mock() + private val mSmartReplyStateInflater: SmartReplyStateInflater = + object : SmartReplyStateInflater { + override fun inflateSmartReplyViewHolder( + sysuiContext: Context, + notifPackageContext: Context, + entry: NotificationEntry, + existingSmartReplyState: InflatedSmartReplyState?, + newSmartReplyState: InflatedSmartReplyState + ): InflatedSmartReplyViewHolder { + return mInflatedSmartReplies + } + + override fun inflateSmartReplyState(entry: NotificationEntry): InflatedSmartReplyState { + return mInflatedSmartReplyState + } + } + + @Before + fun setUp() { + allowTestableLooperAsMainThread() + mBuilder = + Notification.Builder(mContext, "no-id") + .setSmallIcon(R.drawable.ic_person) + .setContentTitle("Title") + .setContentText("Text") + .setStyle(Notification.BigTextStyle().bigText("big text")) + mHelper = NotificationTestHelper(mContext, mDependency) + val row = mHelper.createRow(mBuilder.build()) + mRow = spy(row) + whenever(mNotifLayoutInflaterFactoryProvider.provide(any(), any())) + .thenReturn(mNotifLayoutInflaterFactory) + mNotificationInflater = + NotificationRowContentBinderImpl( + mCache, + mock(), + mConversationNotificationProcessor, + mock(), + mSmartReplyStateInflater, + mNotifLayoutInflaterFactoryProvider, + mHeadsUpStyleProvider, + mock() + ) + } + + @Test + fun testIncreasedHeadsUpBeingUsed() { + val params = BindParams() + params.usesIncreasedHeadsUpHeight = true + val builder = spy(mBuilder) + mNotificationInflater.inflateNotificationViews( + mRow.entry, + mRow, + params, + true /* inflateSynchronously */, + NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, + builder, + mContext, + mSmartReplyStateInflater + ) + verify(builder).createHeadsUpContentView(true) + } + + @Test + fun testIncreasedHeightBeingUsed() { + val params = BindParams() + params.usesIncreasedHeight = true + val builder = spy(mBuilder) + mNotificationInflater.inflateNotificationViews( + mRow.entry, + mRow, + params, + true /* inflateSynchronously */, + NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, + builder, + mContext, + mSmartReplyStateInflater + ) + verify(builder).createContentView(true) + } + + @Test + fun testInflationCallsUpdated() { + inflateAndWait( + mNotificationInflater, + NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, + mRow + ) + verify(mRow).onNotificationUpdated() + } + + @Test + fun testInflationOnlyInflatesSetFlags() { + inflateAndWait( + mNotificationInflater, + NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP, + mRow + ) + Assert.assertNotNull(mRow.privateLayout.headsUpChild) + verify(mRow).onNotificationUpdated() + } + + @Test + fun testInflationThrowsErrorDoesntCallUpdated() { + mRow.privateLayout.removeAllViews() + mRow.entry.sbn.notification.contentView = + RemoteViews(mContext.packageName, R.layout.status_bar) + inflateAndWait( + true /* expectingException */, + mNotificationInflater, + NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, + mRow + ) + Assert.assertTrue(mRow.privateLayout.childCount == 0) + verify(mRow, times(0)).onNotificationUpdated() + } + + @Test + fun testAsyncTaskRemoved() { + mRow.entry.abortTask() + inflateAndWait( + mNotificationInflater, + NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, + mRow + ) + verify(mRow).onNotificationUpdated() + } + + @Test + fun testRemovedNotInflated() { + mRow.setRemoved() + mNotificationInflater.setInflateSynchronously(true) + mNotificationInflater.bindContent( + mRow.entry, + mRow, + NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, + BindParams(), + false /* forceInflate */, + null /* callback */ + ) + Assert.assertNull(mRow.entry.runningTask) + } + + @Test + @Ignore("b/345418902") + fun testInflationIsRetriedIfAsyncFails() { + val headsUpStatusBarModel = HeadsUpStatusBarModel("private", "public") + val result = + NotificationRowContentBinderImpl.InflationProgress( + packageContext = mContext, + remoteViews = NewRemoteViews(), + contentModel = NotificationContentModel(headsUpStatusBarModel) + ) + val countDownLatch = CountDownLatch(1) + NotificationRowContentBinderImpl.applyRemoteView( + AsyncTask.SERIAL_EXECUTOR, + inflateSynchronously = false, + isMinimized = false, + result = result, + reInflateFlags = NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED, + inflationId = 0, + remoteViewCache = mock(), + entry = mRow.entry, + row = mRow, + isNewView = true, /* isNewView */ + remoteViewClickHandler = { _, _, _ -> true }, + callback = + object : InflationCallback { + override fun handleInflationException(entry: NotificationEntry, e: Exception) { + countDownLatch.countDown() + throw RuntimeException("No Exception expected") + } + + override fun onAsyncInflationFinished(entry: NotificationEntry) { + countDownLatch.countDown() + } + }, + parentLayout = mRow.privateLayout, + existingView = null, + existingWrapper = null, + runningInflations = HashMap(), + applyCallback = + object : NotificationRowContentBinderImpl.ApplyCallback() { + override fun setResultView(v: View) {} + + override val remoteView: RemoteViews + get() = + AsyncFailRemoteView( + mContext.packageName, + com.android.systemui.tests.R.layout.custom_view_dark + ) + }, + logger = mock(), + ) + Assert.assertTrue(countDownLatch.await(500, TimeUnit.MILLISECONDS)) + } + + @Test + fun doesntReapplyDisallowedRemoteView() { + mBuilder.setStyle(Notification.MediaStyle()) + val mediaView = mBuilder.createContentView() + mBuilder.setStyle(Notification.DecoratedCustomViewStyle()) + mBuilder.setCustomContentView( + RemoteViews(context.packageName, com.android.systemui.tests.R.layout.custom_view_dark) + ) + val decoratedMediaView = mBuilder.createContentView() + Assert.assertFalse( + "The decorated media style doesn't allow a view to be reapplied!", + NotificationRowContentBinderImpl.canReapplyRemoteView(mediaView, decoratedMediaView) + ) + } + + @Test + @Ignore("b/345418902") + fun testUsesSameViewWhenCachedPossibleToReuse() { + // GIVEN a cached view. + val contractedRemoteView = mBuilder.createContentView() + whenever( + mCache.hasCachedView( + mRow.entry, + NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED + ) + ) + .thenReturn(true) + whenever( + mCache.getCachedView( + mRow.entry, + NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED + ) + ) + .thenReturn(contractedRemoteView) + + // GIVEN existing bound view with same layout id. + val view = contractedRemoteView.apply(mContext, null /* parent */) + mRow.privateLayout.setContractedChild(view) + + // WHEN inflater inflates + inflateAndWait( + mNotificationInflater, + NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED, + mRow + ) + + // THEN the view should be re-used + Assert.assertEquals( + "Binder inflated a new view even though the old one was cached and usable.", + view, + mRow.privateLayout.contractedChild + ) + } + + @Test + fun testInflatesNewViewWhenCachedNotPossibleToReuse() { + // GIVEN a cached remote view. + val contractedRemoteView = mBuilder.createHeadsUpContentView() + whenever( + mCache.hasCachedView( + mRow.entry, + NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED + ) + ) + .thenReturn(true) + whenever( + mCache.getCachedView( + mRow.entry, + NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED + ) + ) + .thenReturn(contractedRemoteView) + + // GIVEN existing bound view with different layout id. + val view: View = TextView(mContext) + mRow.privateLayout.setContractedChild(view) + + // WHEN inflater inflates + inflateAndWait( + mNotificationInflater, + NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED, + mRow + ) + + // THEN the view should be a new view + Assert.assertNotEquals( + "Binder (somehow) used the same view when inflating.", + view, + mRow.privateLayout.contractedChild + ) + } + + @Test + fun testInflationCachesCreatedRemoteView() { + // WHEN inflater inflates + inflateAndWait( + mNotificationInflater, + NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED, + mRow + ) + + // THEN inflater informs cache of the new remote view + verify(mCache) + .putCachedView( + eq(mRow.entry), + eq(NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED), + any() + ) + } + + @Test + fun testUnbindRemovesCachedRemoteView() { + // WHEN inflated unbinds content + mNotificationInflater.unbindContent( + mRow.entry, + mRow, + NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP + ) + + // THEN inflated informs cache to remove remote view + verify(mCache) + .removeCachedView( + eq(mRow.entry), + eq(NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP) + ) + } + + @Test + fun testNotificationViewHeightTooSmallFailsValidation() { + val validationError = + getValidationError( + measuredHeightDp = 5f, + targetSdk = Build.VERSION_CODES.R, + contentView = mock(), + ) + Assert.assertNotNull(validationError) + } + + @Test + fun testNotificationViewHeightPassesForNewerSDK() { + val validationError = + getValidationError( + measuredHeightDp = 5f, + targetSdk = Build.VERSION_CODES.S, + contentView = mock(), + ) + Assert.assertNull(validationError) + } + + @Test + fun testNotificationViewHeightPassesForTemplatedViews() { + val validationError = + getValidationError( + measuredHeightDp = 5f, + targetSdk = Build.VERSION_CODES.R, + contentView = null, + ) + Assert.assertNull(validationError) + } + + @Test + fun testNotificationViewPassesValidation() { + val validationError = + getValidationError( + measuredHeightDp = 20f, + targetSdk = Build.VERSION_CODES.R, + contentView = mock(), + ) + Assert.assertNull(validationError) + } + + private fun getValidationError( + measuredHeightDp: Float, + targetSdk: Int, + contentView: RemoteViews? + ): String? { + val view: View = mock() + whenever(view.measuredHeight) + .thenReturn( + TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_SP, + measuredHeightDp, + mContext.resources.displayMetrics + ) + .toInt() + ) + mRow.entry.targetSdk = targetSdk + mRow.entry.sbn.notification.contentView = contentView + return NotificationRowContentBinderImpl.isValidView(view, mRow.entry, mContext.resources) + } + + @Test + fun testInvalidNotificationDoesNotInvokeCallback() { + mRow.privateLayout.removeAllViews() + mRow.entry.sbn.notification.contentView = + RemoteViews( + mContext.packageName, + com.android.systemui.tests.R.layout.invalid_notification_height + ) + inflateAndWait( + true, + mNotificationInflater, + NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, + mRow + ) + Assert.assertEquals(0, mRow.privateLayout.childCount.toLong()) + verify(mRow, times(0)).onNotificationUpdated() + } + + private class ExceptionHolder { + var mException: Exception? = null + + fun setException(exception: Exception?) { + mException = exception + } + } + + private class AsyncFailRemoteView(packageName: String?, layoutId: Int) : + RemoteViews(packageName, layoutId) { + var mHandler = mockExecutorHandler { p0 -> p0.run() } + + override fun apply(context: Context, parent: ViewGroup): View { + return super.apply(context, parent) + } + + override fun applyAsync( + context: Context, + parent: ViewGroup, + executor: Executor, + listener: OnViewAppliedListener, + handler: InteractionHandler? + ): CancellationSignal { + mHandler.post { listener.onError(RuntimeException("Failed to inflate async")) } + return CancellationSignal() + } + + override fun applyAsync( + context: Context, + parent: ViewGroup, + executor: Executor, + listener: OnViewAppliedListener + ): CancellationSignal { + return applyAsync(context, parent, executor, listener, null) + } + } + + companion object { + private fun inflateAndWait( + inflater: NotificationRowContentBinderImpl, + @InflationFlag contentToInflate: Int, + row: ExpandableNotificationRow + ) { + inflateAndWait(false /* expectingException */, inflater, contentToInflate, row) + } + + private fun inflateAndWait( + expectingException: Boolean, + inflater: NotificationRowContentBinderImpl, + @InflationFlag contentToInflate: Int, + row: ExpandableNotificationRow, + ) { + val countDownLatch = CountDownLatch(1) + val exceptionHolder = ExceptionHolder() + inflater.setInflateSynchronously(true) + val callback: InflationCallback = + object : InflationCallback { + override fun handleInflationException(entry: NotificationEntry, e: Exception) { + if (!expectingException) { + exceptionHolder.setException(e) + } + countDownLatch.countDown() + } + + override fun onAsyncInflationFinished(entry: NotificationEntry) { + if (expectingException) { + exceptionHolder.setException( + RuntimeException( + "Inflation finished even though there should be an error" + ) + ) + } + countDownLatch.countDown() + } + } + inflater.bindContent( + row.entry, + row, + contentToInflate, + BindParams(), + false /* forceInflate */, + callback /* callback */ + ) + Assert.assertTrue(countDownLatch.await(500, TimeUnit.MILLISECONDS)) + exceptionHolder.mException?.let { throw it } + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java index 65941adf280e..21d586b1b5fc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java @@ -84,6 +84,7 @@ import com.android.systemui.statusbar.notification.people.PeopleNotificationIden import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.ExpandableNotificationRowLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.OnExpandClickListener; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag; +import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor; import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -192,16 +193,27 @@ public class NotificationTestHelper { mBgCoroutineContext, mMainCoroutineContext); - NotificationRowContentBinder contentBinder = new NotificationContentInflater( - mock(NotifRemoteViewCache.class), - mock(NotificationRemoteInputManager.class), - mock(ConversationNotificationProcessor.class), - mock(MediaFeatureFlag.class), - mock(Executor.class), - new MockSmartReplyInflater(), - mock(NotifLayoutInflaterFactory.Provider.class), - mock(HeadsUpStyleProvider.class), - mock(NotificationRowContentBinderLogger.class)); + NotificationRowContentBinder contentBinder = + NotificationRowContentBinderRefactor.isEnabled() + ? new NotificationRowContentBinderImpl( + mock(NotifRemoteViewCache.class), + mock(NotificationRemoteInputManager.class), + mock(ConversationNotificationProcessor.class), + mock(Executor.class), + new MockSmartReplyInflater(), + mock(NotifLayoutInflaterFactory.Provider.class), + mock(HeadsUpStyleProvider.class), + mock(NotificationRowContentBinderLogger.class)) + : new NotificationContentInflater( + mock(NotifRemoteViewCache.class), + mock(NotificationRemoteInputManager.class), + mock(ConversationNotificationProcessor.class), + mock(MediaFeatureFlag.class), + mock(Executor.class), + new MockSmartReplyInflater(), + mock(NotifLayoutInflaterFactory.Provider.class), + mock(HeadsUpStyleProvider.class), + mock(NotificationRowContentBinderLogger.class)); contentBinder.setInflateSynchronously(true); mBindStage = new RowContentBindStage(contentBinder, mock(NotifInflationErrorManager.class), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt index 617c553d773d..7e523fbd8747 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt @@ -86,6 +86,7 @@ class StatusBarIconControllerImplTest : SysuiTestCase() { /* iconLevel= */ 0, /* number= */ 0, "contentDescription", + StatusBarIcon.Type.SystemIcon, ) underTest.setIconFromTile(slotName, externalIcon) @@ -114,6 +115,7 @@ class StatusBarIconControllerImplTest : SysuiTestCase() { /* iconLevel= */ 0, /* number= */ 0, "contentDescription", + StatusBarIcon.Type.SystemIcon, ) commandQueueCallbacks.setIcon(slotName, externalIcon) @@ -240,6 +242,7 @@ class StatusBarIconControllerImplTest : SysuiTestCase() { /* iconLevel= */ 0, /* number= */ 0, "externalDescription", + StatusBarIcon.Type.SystemIcon, ) underTest.setIconFromTile(slotName, startingExternalIcon) @@ -278,6 +281,7 @@ class StatusBarIconControllerImplTest : SysuiTestCase() { /* iconLevel= */ 0, /* number= */ 0, "externalDescription", + StatusBarIcon.Type.SystemIcon, ) underTest.setIconFromTile(slotName, startingExternalIcon) @@ -290,6 +294,7 @@ class StatusBarIconControllerImplTest : SysuiTestCase() { /* iconLevel= */ 0, /* number= */ 0, "newExternalDescription", + StatusBarIcon.Type.SystemIcon, ) underTest.setIconFromTile(slotName, newExternalIcon) @@ -325,6 +330,7 @@ class StatusBarIconControllerImplTest : SysuiTestCase() { /* iconLevel= */ 0, /* number= */ 0, "externalDescription", + StatusBarIcon.Type.SystemIcon, ) commandQueueCallbacks.setIcon(slotName, startingExternalIcon) @@ -337,6 +343,7 @@ class StatusBarIconControllerImplTest : SysuiTestCase() { /* iconLevel= */ 0, /* number= */ 0, "newExternalDescription", + StatusBarIcon.Type.SystemIcon, ) commandQueueCallbacks.setIcon(slotName, newExternalIcon) @@ -404,6 +411,7 @@ class StatusBarIconControllerImplTest : SysuiTestCase() { /* iconLevel= */ 0, /* number= */ 0, "contentDescription", + StatusBarIcon.Type.SystemIcon, ) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java index 05d07e5256b8..dbdbe65ecac0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java @@ -87,6 +87,7 @@ import com.android.systemui.util.settings.FakeSettings; import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.time.FakeSystemClock; import com.android.systemui.volume.domain.interactor.VolumePanelNavigationInteractor; +import com.android.systemui.volume.ui.binder.VolumeDialogMenuIconBinder; import com.android.systemui.volume.ui.navigation.VolumeNavigator; import dagger.Lazy; @@ -148,6 +149,8 @@ public class VolumeDialogImplTest extends SysuiTestCase { private VolumePanelNavigationInteractor mVolumePanelNavigationInteractor; @Mock private VolumeNavigator mVolumeNavigator; + @Mock + private VolumeDialogMenuIconBinder mVolumeDialogMenuIconBinder; private final CsdWarningDialog.Factory mCsdWarningDialogFactory = new CsdWarningDialog.Factory() { @@ -211,6 +214,7 @@ public class VolumeDialogImplTest extends SysuiTestCase { mDumpManager, mLazySecureSettings, mVibratorHelper, + mVolumeDialogMenuIconBinder, new FakeSystemClock()); mDialog.init(0, null); State state = createShellState(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index 0f89dcc42c82..fabb9b770a11 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -169,6 +169,7 @@ import com.android.wm.shell.bubbles.BubbleViewInfoTask; import com.android.wm.shell.bubbles.BubbleViewProvider; import com.android.wm.shell.bubbles.Bubbles; import com.android.wm.shell.bubbles.StackEducationView; +import com.android.wm.shell.bubbles.bar.BubbleBarLayerView; import com.android.wm.shell.bubbles.properties.BubbleProperties; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.FloatingContentCoordinator; @@ -2109,6 +2110,33 @@ public class BubblesTest extends SysuiTestCase { } @Test + public void registerBubbleBarListener_switchToBarWhileExpanded() { + mBubbleProperties.mIsBubbleBarEnabled = true; + mPositioner.setIsLargeScreen(true); + + mEntryListener.onEntryAdded(mRow); + mBubbleController.updateBubble(mBubbleEntry); + BubbleStackView stackView = mBubbleController.getStackView(); + spyOn(stackView); + + mBubbleData.setExpanded(true); + + assertStackMode(); + assertThat(mBubbleData.isExpanded()).isTrue(); + assertThat(stackView.isExpanded()).isTrue(); + + FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener(); + mBubbleController.registerBubbleStateListener(bubbleStateListener); + + BubbleBarLayerView layerView = mBubbleController.getLayerView(); + spyOn(layerView); + + assertBarMode(); + assertThat(mBubbleData.isExpanded()).isTrue(); + assertThat(layerView.isExpanded()).isTrue(); + } + + @Test public void switchBetweenBarAndStack_noBubbles_shouldBeIgnored() { mBubbleProperties.mIsBubbleBarEnabled = false; mPositioner.setIsLargeScreen(true); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt index ef7aa6308491..d1fbb5e95ee6 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt @@ -16,11 +16,16 @@ package com.android.systemui.scene.domain.interactor +import com.android.compose.animation.scene.SceneKey +import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.scene.data.repository.sceneContainerRepository +import com.android.systemui.scene.domain.resolver.HomeSceneFamilyResolver +import com.android.systemui.scene.domain.resolver.SceneResolver import com.android.systemui.scene.shared.logger.sceneLogger +import com.android.systemui.scene.shared.model.SceneFamilies val Kosmos.sceneInteractor by Kosmos.Fixture { @@ -28,6 +33,18 @@ val Kosmos.sceneInteractor by applicationScope = applicationCoroutineScope, repository = sceneContainerRepository, logger = sceneLogger, + sceneFamilyResolvers = { sceneFamilyResolvers }, deviceUnlockedInteractor = deviceUnlockedInteractor, ) } + +val Kosmos.sceneFamilyResolvers: Map<SceneKey, SceneResolver> + get() = mapOf(SceneFamilies.Home to homeSceneFamilyResolver) + +val Kosmos.homeSceneFamilyResolver by + Kosmos.Fixture { + HomeSceneFamilyResolver( + applicationScope = applicationCoroutineScope, + deviceEntryInteractor = deviceEntryInteractor, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt index d08855f190ed..cc836acac37d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt @@ -20,8 +20,6 @@ package com.android.systemui.shade import com.android.systemui.assist.AssistManager import com.android.systemui.concurrency.fakeExecutor -import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor -import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher @@ -52,15 +50,14 @@ val Kosmos.shadeControllerSceneImpl by shadeInteractor = shadeInteractor, sceneInteractor = sceneInteractor, notificationStackScrollLayout = mock<NotificationStackScrollLayout>(), - deviceEntryInteractor = deviceEntryInteractor, touchLog = mock<LogBuffer>(), vibratorHelper = mock<VibratorHelper>(), commandQueue = mock<CommandQueue>(), statusBarKeyguardViewManager = mock<StatusBarKeyguardViewManager>(), notificationShadeWindowController = mock<NotificationShadeWindowController>(), - assistManagerLazy = { mock<AssistManager>() }, - deviceUnlockedInteractor = deviceUnlockedInteractor, - ) + ) { + mock<AssistManager>() + } } val Kosmos.shadeControllerImpl by diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeSceneViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeSceneViewModelKosmos.kt index 872eba06961e..1ca3509cbd79 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeSceneViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeSceneViewModelKosmos.kt @@ -17,13 +17,7 @@ package com.android.systemui.shade.ui.viewmodel import com.android.systemui.kosmos.Kosmos -import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeSceneViewModel val Kosmos.notificationsShadeSceneViewModel: NotificationsShadeSceneViewModel by - Kosmos.Fixture { - NotificationsShadeSceneViewModel( - applicationScope = applicationCoroutineScope, - overlayShadeViewModel = overlayShadeViewModel, - ) - } + Kosmos.Fixture { NotificationsShadeSceneViewModel() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModelKosmos.kt index 45ec03241495..fec102857619 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModelKosmos.kt @@ -14,21 +14,16 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.shade.ui.viewmodel -import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.scene.domain.interactor.sceneInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.overlayShadeViewModel: OverlayShadeViewModel by Kosmos.Fixture { OverlayShadeViewModel( applicationScope = applicationCoroutineScope, sceneInteractor = sceneInteractor, - deviceEntryInteractor = deviceEntryInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/QuickSettingsShadeSceneViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/QuickSettingsShadeSceneViewModelKosmos.kt index c5625e47040a..4d81ea16220c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/QuickSettingsShadeSceneViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/QuickSettingsShadeSceneViewModelKosmos.kt @@ -18,7 +18,6 @@ package com.android.systemui.shade.ui.viewmodel import com.android.systemui.brightness.ui.viewmodel.brightnessSliderViewModel import com.android.systemui.kosmos.Kosmos -import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.qs.panels.ui.viewmodel.editModeViewModel import com.android.systemui.qs.panels.ui.viewmodel.tileGridViewModel import com.android.systemui.qs.ui.adapter.qsSceneAdapter @@ -27,7 +26,6 @@ import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeSceneViewModel val Kosmos.quickSettingsShadeSceneViewModel: QuickSettingsShadeSceneViewModel by Kosmos.Fixture { QuickSettingsShadeSceneViewModel( - applicationScope = applicationCoroutineScope, overlayShadeViewModel = overlayShadeViewModel, brightnessSliderViewModel = brightnessSliderViewModel, tileGridViewModel = tileGridViewModel, diff --git a/ravenwood/OWNERS b/ravenwood/OWNERS index a90328c2e8c6..badfca0a040e 100644 --- a/ravenwood/OWNERS +++ b/ravenwood/OWNERS @@ -2,6 +2,7 @@ set noparent jsharkey@google.com omakoto@google.com +dplotnikov@google.com per-file ravenwood-annotation-allowed-classes.txt = dplotnikov@google.com per-file texts/ravenwood-annotation-allowed-classes.txt = dplotnikov@google.com diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Parcel_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Parcel_host.java index 61ec7b4bbc72..22e11e18ae31 100644 --- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Parcel_host.java +++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Parcel_host.java @@ -164,6 +164,9 @@ public class Parcel_host { p.mPos = pos; } public static void nativeSetDataCapacity(long nativePtr, int size) { + if (size < 0) { + throw new IllegalArgumentException("size < 0: size=" + size); + } var p = getInstance(nativePtr); if (p.getCapacity() < size) { p.forceSetCapacity(size); diff --git a/ravenwood/test-authors.md b/ravenwood/test-authors.md index 2ab43bbeaad0..0a0b200adabc 100644 --- a/ravenwood/test-authors.md +++ b/ravenwood/test-authors.md @@ -6,6 +6,20 @@ Ravenwood explicitly does not support “large” integration tests that expect When writing tests under Ravenwood, all Android API symbols associated with your declared `sdk_version` are available to link against using, but unsupported APIs will throw an exception. This design choice enables mocking of unsupported APIs, and supports sharing of test code to build “bivalent” test suites that run against either Ravenwood or a traditional device. +## Manually running tests + +To run all Ravenwood tests, use: + +``` +./frameworks/base/ravenwood/scripts/run-ravenwood-tests.sh +``` + +To run a specific test, use "atest" as normal, selecting the test from a Ravenwood suite such as: + +``` +atest CtsOsTestCasesRavenwood:ParcelTest\#testSetDataCapacityNegative +``` + ## Typical test structure Below are the typical steps needed to add a straightforward “small” unit test: diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index 7342b0003ed5..edb6390ea874 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -1379,30 +1379,6 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ } } - @RequiresNoPermission - @Override - public boolean isMagnificationSystemUIConnected() { - if (svcConnTracingEnabled()) { - logTraceSvcConn("isMagnificationSystemUIConnected", ""); - } - synchronized (mLock) { - if (!hasRightsToCurrentUserLocked()) { - return false; - } - if (!mSecurityPolicy.canControlMagnification(this)) { - return false; - } - final long identity = Binder.clearCallingIdentity(); - try { - MagnificationProcessor magnificationProcessor = - mSystemSupport.getMagnificationProcessor(); - return magnificationProcessor.isMagnificationSystemUIConnected(); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - } - public boolean isMagnificationCallbackEnabled(int displayId) { return mInvocationHandler.isMagnificationCallbackEnabled(displayId); } @@ -1947,11 +1923,6 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ InvocationHandler.MSG_CLEAR_ACCESSIBILITY_CACHE); } - public void notifyMagnificationSystemUIConnectionChangedLocked(boolean connected) { - mInvocationHandler - .notifyMagnificationSystemUIConnectionChangedLocked(connected); - } - public void notifyMagnificationChangedLocked(int displayId, @NonNull Region region, @NonNull MagnificationConfig config) { mInvocationHandler @@ -2003,21 +1974,6 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ return (mGenericMotionEventSources & eventSourceWithoutClass) != 0; } - /** - * Called by the invocation handler to notify the service that the - * magnification systemui connection has changed. - */ - private void notifyMagnificationSystemUIConnectionChangedInternal(boolean connected) { - final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); - if (listener != null) { - try { - listener.onMagnificationSystemUIConnectionChanged(connected); - } catch (RemoteException re) { - Slog.e(LOG_TAG, - "Error sending magnification sysui connection changes to " + mService, re); - } - } - } /** * Called by the invocation handler to notify the service that the @@ -2414,7 +2370,6 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ private static final int MSG_BIND_INPUT = 12; private static final int MSG_UNBIND_INPUT = 13; private static final int MSG_START_INPUT = 14; - private static final int MSG_ON_MAGNIFICATION_SYSTEM_UI_CONNECTION_CHANGED = 15; /** List of magnification callback states, mapping from displayId -> Boolean */ @GuardedBy("mlock") @@ -2441,13 +2396,6 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ notifyClearAccessibilityCacheInternal(); } break; - case MSG_ON_MAGNIFICATION_SYSTEM_UI_CONNECTION_CHANGED: { - final SomeArgs args = (SomeArgs) message.obj; - final boolean connected = args.argi1 == 1; - notifyMagnificationSystemUIConnectionChangedInternal(connected); - args.recycle(); - } break; - case MSG_ON_MAGNIFICATION_CHANGED: { final SomeArgs args = (SomeArgs) message.obj; final Region region = (Region) args.arg1; @@ -2505,15 +2453,6 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ } } - public void notifyMagnificationSystemUIConnectionChangedLocked(boolean connected) { - final SomeArgs args = SomeArgs.obtain(); - args.argi1 = connected ? 1 : 0; - - final Message msg = - obtainMessage(MSG_ON_MAGNIFICATION_SYSTEM_UI_CONNECTION_CHANGED, args); - msg.sendToTarget(); - } - public void notifyMagnificationChangedLocked(int displayId, @NonNull Region region, @NonNull MagnificationConfig config) { synchronized (mLock) { diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index d09cb3ee103a..4f9db8bece63 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -1812,17 +1812,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } /** - * Called by the MagnificationController when the magnification systemui connection changes. - * - * @param connected Whether the connection is ready. - */ - public void notifyMagnificationSystemUIConnectionChanged(boolean connected) { - synchronized (mLock) { - notifyMagnificationSystemUIConnectionChangedLocked(connected); - } - } - - /** * Called by the MagnificationController when the state of display * magnification changes. * @@ -2254,14 +2243,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mProxyManager.clearCacheLocked(); } - private void notifyMagnificationSystemUIConnectionChangedLocked(boolean connected) { - final AccessibilityUserState state = getCurrentUserStateLocked(); - for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { - final AccessibilityServiceConnection service = state.mBoundServices.get(i); - service.notifyMagnificationSystemUIConnectionChangedLocked(connected); - } - } - private void notifyMagnificationChangedLocked(int displayId, @NonNull Region region, @NonNull MagnificationConfig config) { final AccessibilityUserState state = getCurrentUserStateLocked(); diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java index 420bac759ea6..4cb3d247edb0 100644 --- a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java @@ -489,14 +489,6 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon /** @throws UnsupportedOperationException since a proxy does not need magnification */ @RequiresNoPermission @Override - public boolean isMagnificationSystemUIConnected() throws UnsupportedOperationException { - throw new UnsupportedOperationException("isMagnificationSystemUIConnected is not" - + " supported"); - } - - /** @throws UnsupportedOperationException since a proxy does not need magnification */ - @RequiresNoPermission - @Override public boolean isMagnificationCallbackEnabled(int displayId) { throw new UnsupportedOperationException("isMagnificationCallbackEnabled is not supported"); } diff --git a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java index 63a183d506f8..f85d786f89c5 100644 --- a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java +++ b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java @@ -101,8 +101,10 @@ class UiAutomationManager { SystemActionPerformer systemActionPerformer, AccessibilityWindowManager awm, int flags) { accessibilityServiceInfo.setComponentName(COMPONENT_NAME); - Slogf.i(LOG_TAG, "Registering UiTestAutomationService (id=%s) when called by user %d", - accessibilityServiceInfo.getId(), Binder.getCallingUserHandle().getIdentifier()); + Slogf.i(LOG_TAG, "Registering UiTestAutomationService (id=%s, flags=0x%x) when" + + " called by user %d", + accessibilityServiceInfo.getId(), flags, + Binder.getCallingUserHandle().getIdentifier()); if (mUiAutomationService != null) { throw new IllegalStateException( "UiAutomationService " + mUiAutomationService.mServiceInterface @@ -272,8 +274,10 @@ class UiAutomationManager { mMainHandler.post(() -> { try { final IAccessibilityServiceClient serviceInterface; + final UiAutomationService uiAutomationService; synchronized (mLock) { serviceInterface = mServiceInterface; + uiAutomationService = mUiAutomationService; if (serviceInterface == null) { mService = null; } else { @@ -283,8 +287,8 @@ class UiAutomationManager { } // If the serviceInterface is null, the UiAutomation has been shut down on // another thread. - if (serviceInterface != null) { - mUiAutomationService.addWindowTokensForAllDisplays(); + if (serviceInterface != null && uiAutomationService != null) { + uiAutomationService.addWindowTokensForAllDisplays(); if (mTrace.isA11yTracingEnabledForTypes( AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE_CLIENT)) { mTrace.logTrace("UiAutomationService.connectServiceUnknownThread", diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java index 7f4c808b2251..19e3e690924e 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java @@ -18,6 +18,7 @@ package com.android.server.accessibility.magnification; import static android.accessibilityservice.AccessibilityTrace.FLAGS_MAGNIFICATION_CONNECTION; import static android.accessibilityservice.AccessibilityTrace.FLAGS_MAGNIFICATION_CONNECTION_CALLBACK; +import static android.os.Build.HW_TIMEOUT_MULTIPLIER; import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK; import static com.android.server.accessibility.AccessibilityManagerService.INVALID_SERVICE_ID; @@ -126,9 +127,8 @@ public class MagnificationConnectionManager implements @ConnectionState private int mConnectionState = DISCONNECTED; - ConnectionStateChangedCallback mConnectionStateChangedCallback = null; - private static final int WAIT_CONNECTION_TIMEOUT_MILLIS = 100; + private static final int WAIT_CONNECTION_TIMEOUT_MILLIS = 200 * HW_TIMEOUT_MULTIPLIER; private final Object mLock; private final Context mContext; @@ -265,9 +265,6 @@ public class MagnificationConnectionManager implements } } } - if (mConnectionStateChangedCallback != null) { - mConnectionStateChangedCallback.onConnectionStateChanged(connection != null); - } } /** @@ -275,7 +272,7 @@ public class MagnificationConnectionManager implements */ public boolean isConnected() { synchronized (mLock) { - return mConnectionWrapper != null && mConnectionState == CONNECTED; + return mConnectionWrapper != null; } } @@ -683,8 +680,7 @@ public class MagnificationConnectionManager implements */ public boolean onFullscreenMagnificationActivationChanged(int displayId, boolean activated) { synchronized (mLock) { - waitForConnectionIfNeeded(); - if (mConnectionWrapper == null) { + if (!waitConnectionWithTimeoutIfNeeded()) { Slog.w(TAG, "onFullscreenMagnificationActivationChanged mConnectionWrapper is null. " + "mConnectionState=" + connectionStateToString(mConnectionState)); @@ -1294,8 +1290,7 @@ public class MagnificationConnectionManager implements float centerY, float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY, MagnificationAnimationCallback animationCallback) { - waitForConnectionIfNeeded(); - if (mConnectionWrapper == null) { + if (!waitConnectionWithTimeoutIfNeeded()) { Slog.w(TAG, "enableWindowMagnificationInternal mConnectionWrapper is null. " + "mConnectionState=" + connectionStateToString(mConnectionState)); @@ -1337,7 +1332,7 @@ public class MagnificationConnectionManager implements displayId, positionX, positionY, animationCallback); } - private void waitForConnectionIfNeeded() { + boolean waitConnectionWithTimeoutIfNeeded() { // Wait for the connection with a timeout. final long endMillis = SystemClock.uptimeMillis() + WAIT_CONNECTION_TIMEOUT_MILLIS; while (mConnectionState == CONNECTING && (SystemClock.uptimeMillis() < endMillis)) { @@ -1347,9 +1342,6 @@ public class MagnificationConnectionManager implements /* ignore */ } } - } - - interface ConnectionStateChangedCallback { - void onConnectionStateChanged(boolean connected); + return isConnected(); } } diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java index 9b7884711a6d..1489d16c3764 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java @@ -799,14 +799,18 @@ public class MagnificationController implements MagnificationConnectionManager.C this, mScaleProvider, mBackgroundExecutor, - () -> (isMagnificationConnectionManagerInitialized() - && getMagnificationConnectionManager().isConnected()) + () -> isMagnificationSystemUIConnectionReady() ); } } return mFullScreenMagnificationController; } + private boolean isMagnificationSystemUIConnectionReady() { + return isMagnificationConnectionManagerInitialized() + && getMagnificationConnectionManager().waitConnectionWithTimeoutIfNeeded(); + } + /** * Is {@link #mFullScreenMagnificationController} is initialized. * @return {code true} if {@link #mFullScreenMagnificationController} is initialized. @@ -828,8 +832,6 @@ public class MagnificationController implements MagnificationConnectionManager.C mMagnificationConnectionManager = new MagnificationConnectionManager(mContext, mLock, this, mAms.getTraceManager(), mScaleProvider); - mMagnificationConnectionManager.mConnectionStateChangedCallback = - mAms::notifyMagnificationSystemUIConnectionChanged; } return mMagnificationConnectionManager; } diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java index 603683906d06..ed8f1ab3a1b2 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java @@ -147,10 +147,6 @@ public class MagnificationProcessor { return false; } - public boolean isMagnificationSystemUIConnected() { - return mController.getMagnificationConnectionManager().isConnected(); - } - private boolean setScaleAndCenterForFullScreenMagnification(int displayId, float scale, float centerX, float centerY, boolean animate, int id) { diff --git a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java index f289115159b8..aa76200c5270 100644 --- a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java +++ b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java @@ -62,6 +62,7 @@ import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; +import android.os.SystemClock; import android.provider.Settings; import android.service.autofill.Dataset; import android.text.TextUtils; @@ -211,17 +212,21 @@ public final class PresentationStatsEventLogger { AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_AUTOFILL_PROVIDER; public static final int DETECTION_PREFER_PCC = AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_PCC; - private final int mSessionId; + private static final int DEFAULT_VALUE_INT = -1; + + private final int mSessionId; /** * For app_package_uid. */ private final int mCallingAppUid; private Optional<PresentationStatsEventInternal> mEventInternal; + private final long mSessionStartTimestamp; - private PresentationStatsEventLogger(int sessionId, int callingAppUid) { + private PresentationStatsEventLogger(int sessionId, int callingAppUid, long timestamp) { mSessionId = sessionId; mCallingAppUid = callingAppUid; + mSessionStartTimestamp = timestamp; mEventInternal = Optional.empty(); } @@ -229,8 +234,8 @@ public final class PresentationStatsEventLogger { * Create PresentationStatsEventLogger, populated with sessionId and the callingAppUid */ public static PresentationStatsEventLogger createPresentationLog( - int sessionId, int callingAppUid) { - return new PresentationStatsEventLogger(sessionId, callingAppUid); + int sessionId, int callingAppUid, long timestamp) { + return new PresentationStatsEventLogger(sessionId, callingAppUid, timestamp); } public void startNewEvent() { @@ -370,28 +375,50 @@ public final class PresentationStatsEventLogger { }); } + public void maybeSetFillRequestSentTimestampMs() { + maybeSetFillRequestSentTimestampMs(getElapsedTime()); + } + public void maybeSetFillResponseReceivedTimestampMs(int timestamp) { mEventInternal.ifPresent(event -> { event.mFillResponseReceivedTimestampMs = timestamp; }); } + public void maybeSetFillResponseReceivedTimestampMs() { + maybeSetFillResponseReceivedTimestampMs(getElapsedTime()); + } + public void maybeSetSuggestionSentTimestampMs(int timestamp) { mEventInternal.ifPresent(event -> { event.mSuggestionSentTimestampMs = timestamp; }); } + public void maybeSetSuggestionSentTimestampMs() { + maybeSetSuggestionSentTimestampMs(getElapsedTime()); + } + public void maybeSetSuggestionPresentedTimestampMs(int timestamp) { mEventInternal.ifPresent(event -> { - event.mSuggestionPresentedTimestampMs = timestamp; + // mSuggestionPresentedTimestampMs only tracks the first suggested timestamp. + if (event.mSuggestionPresentedTimestampMs == DEFAULT_VALUE_INT) { + event.mSuggestionPresentedTimestampMs = timestamp; + } + + event.mSuggestionPresentedLastTimestampMs = timestamp; }); } + public void maybeSetSuggestionPresentedTimestampMs() { + maybeSetSuggestionPresentedTimestampMs(getElapsedTime()); + } + public void maybeSetSelectedDatasetId(int selectedDatasetId) { mEventInternal.ifPresent(event -> { event.mSelectedDatasetId = selectedDatasetId; }); + setPresentationSelectedTimestamp(); } public void maybeSetDialogDismissed(boolean dialogDismissed) { @@ -479,6 +506,11 @@ public final class PresentationStatsEventLogger { }); } + /** Set latency_authentication_ui_display_millis as long as mEventInternal presents. */ + public void maybeSetLatencyAuthenticationUiDisplayMillis() { + maybeSetLatencyAuthenticationUiDisplayMillis(getElapsedTime()); + } + /** * Set latency_dataset_display_millis as long as mEventInternal presents. */ @@ -488,6 +520,11 @@ public final class PresentationStatsEventLogger { }); } + /** Set latency_dataset_display_millis as long as mEventInternal presents. */ + public void maybeSetLatencyDatasetDisplayMillis() { + maybeSetLatencyDatasetDisplayMillis(getElapsedTime()); + } + /** * Set available_pcc_count. */ @@ -524,6 +561,53 @@ public final class PresentationStatsEventLogger { }); } + /** + * Set various timestamps whenever the ViewState is modified + * + * <p>If the ViewState contains ViewState.STATE_AUTOFILLED, sets field_autofilled_timestamp_ms + * else, set field_first_modified_timestamp_ms (if unset) and field_last_modified_timestamp_ms + */ + public void onFieldTextUpdated(ViewState state) { + mEventInternal.ifPresent( + event -> { + int timestamp = getElapsedTime(); + // Focused id should be set before this is called + if (state.id != null && state.id.getViewId() != event.mFocusedId) { + // if these don't match, the currently field different than before + Slog.w( + TAG, + "current id: " + + state.id.getViewId() + + " is different than focused id: " + + event.mFocusedId); + return; + } + + if ((state.getState() & ViewState.STATE_AUTOFILLED) != 0) { + event.mAutofilledTimestampMs = timestamp; + } else { + if (event.mFieldModifiedFirstTimestampMs == DEFAULT_VALUE_INT) { + event.mFieldModifiedFirstTimestampMs = timestamp; + } + event.mFieldModifiedLastTimestampMs = timestamp; + } + }); + } + + public void setPresentationSelectedTimestamp() { + mEventInternal.ifPresent(event -> { + event.mSelectionTimestamp = getElapsedTime(); + }); + } + + /** + * Returns timestamp (relative to mSessionStartTimestamp) + */ + private int getElapsedTime() { + return (int)(SystemClock.elapsedRealtime() - mSessionStartTimestamp); + } + + private int convertDatasetPickReason(@Dataset.DatasetEligibleReason int val) { switch (val) { case 0: @@ -648,7 +732,17 @@ public final class PresentationStatsEventLogger { + " mViewFillFailureCount=" + event.mViewFillFailureCount + " mFocusedId=" + event.mFocusedId + " mViewFillSuccessCount=" + event.mViewFillSuccessCount - + " mViewFilledButUnexpectedCount=" + event.mViewFilledButUnexpectedCount); + + " mViewFilledButUnexpectedCount=" + event.mViewFilledButUnexpectedCount + + " event.mSelectionTimestamp=" + event.mSelectionTimestamp + + " event.mAutofilledTimestampMs=" + event.mAutofilledTimestampMs + + " event.mFieldModifiedFirstTimestampMs=" + + event.mFieldModifiedFirstTimestampMs + + " event.mFieldModifiedLastTimestampMs=" + event.mFieldModifiedLastTimestampMs + + " event.mSuggestionPresentedLastTimestampMs=" + + event.mSuggestionPresentedLastTimestampMs + + " event.mFocusedVirtualAutofillId=" + event.mFocusedVirtualAutofillId + + " event.mFieldFirstLength=" + event.mFieldFirstLength + + " event.mFieldLastLength=" + event.mFieldLastLength); } // TODO(b/234185326): Distinguish empty responses from other no presentation reasons. @@ -694,7 +788,15 @@ public final class PresentationStatsEventLogger { event.mViewFillFailureCount, event.mFocusedId, event.mViewFillSuccessCount, - event.mViewFilledButUnexpectedCount); + event.mViewFilledButUnexpectedCount, + event.mSelectionTimestamp, + event.mAutofilledTimestampMs, + event.mFieldModifiedFirstTimestampMs, + event.mFieldModifiedLastTimestampMs, + event.mSuggestionPresentedLastTimestampMs, + event.mFocusedVirtualAutofillId, + event.mFieldFirstLength, + event.mFieldLastLength); mEventInternal = Optional.empty(); } @@ -708,31 +810,39 @@ public final class PresentationStatsEventLogger { int mCountNotShownImePresentationNotDrawn; int mCountNotShownImeUserNotSeen; int mDisplayPresentationType = AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE; - int mAutofillServiceUid = -1; - int mInlineSuggestionHostUid = -1; + int mAutofillServiceUid = DEFAULT_VALUE_INT; + int mInlineSuggestionHostUid = DEFAULT_VALUE_INT; boolean mIsRequestTriggered; - int mFillRequestSentTimestampMs; - int mFillResponseReceivedTimestampMs; - int mSuggestionSentTimestampMs; - int mSuggestionPresentedTimestampMs; - int mSelectedDatasetId = -1; + int mFillRequestSentTimestampMs = DEFAULT_VALUE_INT; + int mFillResponseReceivedTimestampMs = DEFAULT_VALUE_INT; + int mSuggestionSentTimestampMs = DEFAULT_VALUE_INT; + int mSuggestionPresentedTimestampMs = DEFAULT_VALUE_INT; + int mSelectedDatasetId = DEFAULT_VALUE_INT; boolean mDialogDismissed = false; boolean mNegativeCtaButtonClicked = false; boolean mPositiveCtaButtonClicked = false; int mAuthenticationType = AUTHENTICATION_TYPE_UNKNOWN; int mAuthenticationResult = AUTHENTICATION_RESULT_UNKNOWN; - int mLatencyAuthenticationUiDisplayMillis = -1; - int mLatencyDatasetDisplayMillis = -1; - int mAvailablePccCount = -1; - int mAvailablePccOnlyCount = -1; + int mLatencyAuthenticationUiDisplayMillis = DEFAULT_VALUE_INT; + int mLatencyDatasetDisplayMillis = DEFAULT_VALUE_INT; + int mAvailablePccCount = DEFAULT_VALUE_INT; + int mAvailablePccOnlyCount = DEFAULT_VALUE_INT; @DatasetPickedReason int mSelectedDatasetPickedReason = PICK_REASON_UNKNOWN; @DetectionPreference int mDetectionPreference = DETECTION_PREFER_UNKNOWN; - int mFieldClassificationRequestId = -1; + int mFieldClassificationRequestId = DEFAULT_VALUE_INT; boolean mIsCredentialRequest = false; boolean mWebviewRequestedCredential = false; - int mViewFillableTotalCount = -1; - int mViewFillFailureCount = -1; - int mFocusedId = -1; + int mViewFillableTotalCount = DEFAULT_VALUE_INT; + int mViewFillFailureCount = DEFAULT_VALUE_INT; + int mFocusedId = DEFAULT_VALUE_INT; + int mSelectionTimestamp = DEFAULT_VALUE_INT; + int mAutofilledTimestampMs = DEFAULT_VALUE_INT; + int mFieldModifiedFirstTimestampMs = DEFAULT_VALUE_INT; + int mFieldModifiedLastTimestampMs = DEFAULT_VALUE_INT; + int mSuggestionPresentedLastTimestampMs = DEFAULT_VALUE_INT; + int mFocusedVirtualAutofillId = DEFAULT_VALUE_INT; + int mFieldFirstLength = DEFAULT_VALUE_INT; + int mFieldLastLength = DEFAULT_VALUE_INT; // Default value for success count is set to 0 explicitly. Setting it to -1 for // uninitialized doesn't help much, as this would be non-zero only if callback is received. diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index c46464b7cac8..aa67ffed0b2d 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -1553,7 +1553,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mLatencyBaseTime = mStartTime; mRequestCount = 0; mPresentationStatsEventLogger = PresentationStatsEventLogger.createPresentationLog( - sessionId, uid); + sessionId, uid, mLatencyBaseTime); mFillRequestEventLogger = FillRequestEventLogger.forSessionId(sessionId); mFillResponseEventLogger = FillResponseEventLogger.forSessionId(sessionId); mSessionCommittedEventLogger = SessionCommittedEventLogger.forSessionId(sessionId); @@ -1575,14 +1575,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @Override public void notifyInlineUiShown(AutofillId autofillId) { notifyFillUiShown(autofillId); - - synchronized (mLock) { - // TODO(b/262448552): Log when chip inflates instead of here - final long inlineUiShownRelativeTimestamp = - SystemClock.elapsedRealtime() - mLatencyBaseTime; - mPresentationStatsEventLogger.maybeSetSuggestionPresentedTimestampMs( - (int) (inlineUiShownRelativeTimestamp)); - } } @Override @@ -2678,6 +2670,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mLoggedInlineDatasetShown = true; } mService.logDatasetShown(this.id, mClientState, uiType); + mPresentationStatsEventLogger.maybeSetSuggestionPresentedTimestampMs(); Slog.d(TAG, "onShown(): " + uiType); } } @@ -4788,7 +4781,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState updateFilteringStateOnValueChangedLocked(textValue, viewState); viewState.setCurrentValue(value); - final String filterText = textValue; final AutofillValue filledValue = viewState.getAutofilledValue(); @@ -4815,6 +4807,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState currentView.maybeCallOnFillReady(flags); } } + mPresentationStatsEventLogger.onFieldTextUpdated(viewState); if (viewState.id.equals(this.mCurrentViewId) && (viewState.getState() & ViewState.STATE_INLINE_SHOWN) != 0) { @@ -4902,10 +4895,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState synchronized (mLock) { // Time passed since Session was created - final long suggestionSentRelativeTimestamp = - SystemClock.elapsedRealtime() - mLatencyBaseTime; - mPresentationStatsEventLogger.maybeSetSuggestionSentTimestampMs( - (int) (suggestionSentRelativeTimestamp)); + mPresentationStatsEventLogger.maybeSetSuggestionSentTimestampMs(); } final AutofillId[] ids = response.getFillDialogTriggerIds(); @@ -4922,13 +4912,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // Note: Cannot disable before requestShowFillDialog() because the method // need to check whether fill dialog enabled. setFillDialogDisabled(); - synchronized (mLock) { - // Logs when fill dialog ui is shown; time since Session was created - final long fillDialogUiShownRelativeTimestamp = - SystemClock.elapsedRealtime() - mLatencyBaseTime; - mPresentationStatsEventLogger.maybeSetSuggestionPresentedTimestampMs( - (int) (fillDialogUiShownRelativeTimestamp)); - } return; } else { setFillDialogDisabled(); @@ -4970,10 +4953,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // Log first time UI is shown. mUiShownTime = SystemClock.elapsedRealtime(); final long duration = mUiShownTime - mStartTime; - // This logs when dropdown ui was shown. Timestamp is relative to - // when the session was created - mPresentationStatsEventLogger.maybeSetSuggestionPresentedTimestampMs( - (int) (mUiShownTime - mLatencyBaseTime)); if (sDebug) { final StringBuilder msg = new StringBuilder("1st UI for ") diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index 0d0c21dcf49c..c9cce1568335 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -18,6 +18,7 @@ package com.android.server.companion; import static android.Manifest.permission.ASSOCIATE_COMPANION_DEVICES; +import static android.Manifest.permission.BLUETOOTH_CONNECT; import static android.Manifest.permission.DELIVER_COMPANION_MESSAGES; import static android.Manifest.permission.MANAGE_COMPANION_DEVICES; import static android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED; @@ -52,6 +53,9 @@ import android.app.AppOpsManager; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.ecm.EnhancedConfirmationManager; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; import android.companion.AssociationInfo; import android.companion.AssociationRequest; import android.companion.IAssociationRequestCallback; @@ -541,6 +545,31 @@ public class CompanionDeviceManagerService extends SystemService { } @Override + @EnforcePermission(BLUETOOTH_CONNECT) + public boolean removeBond(int associationId, String packageName, int userId) { + removeBond_enforcePermission(); + + Slog.i(TAG, "removeBond() " + + "associationId=" + associationId + ", " + + "package=u" + userId + "/" + packageName); + enforceCallerCanManageAssociationsForPackage(getContext(), userId, packageName, + "remove bonds"); + + AssociationInfo association = mAssociationStore + .getAssociationWithCallerChecks(associationId); + MacAddress address = association.getDeviceMacAddress(); + if (address == null) { + throw new IllegalArgumentException( + "Association id=[" + associationId + "] doesn't have a device address."); + } + + BluetoothAdapter btAdapter = getContext().getSystemService(BluetoothManager.class) + .getAdapter(); + BluetoothDevice btDevice = btAdapter.getRemoteDevice(address.toString().toUpperCase()); + return btDevice.removeBond(); + } + + @Override public PendingIntent buildPermissionTransferUserConsentIntent(String packageName, int userId, int associationId) { return mSystemDataTransferProcessor.buildPermissionTransferUserConsentIntent( diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java index 4a9900763a94..6704049e3612 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java @@ -1055,7 +1055,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub @Override // Binder call @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - public int getVirtualCameraId(@NonNull VirtualCameraConfig cameraConfig) + public String getVirtualCameraId(@NonNull VirtualCameraConfig cameraConfig) throws RemoteException { super.getVirtualCameraId_enforcePermission(); Objects.requireNonNull(cameraConfig); diff --git a/services/companion/java/com/android/server/companion/virtual/camera/VirtualCameraController.java b/services/companion/java/com/android/server/companion/virtual/camera/VirtualCameraController.java index 743086ee1c16..62efafbe12c6 100644 --- a/services/companion/java/com/android/server/companion/virtual/camera/VirtualCameraController.java +++ b/services/companion/java/com/android/server/companion/virtual/camera/VirtualCameraController.java @@ -135,7 +135,7 @@ public final class VirtualCameraController implements IBinder.DeathRecipient { } /** Return the id of the virtual camera with the given config. */ - public int getCameraId(@NonNull VirtualCameraConfig cameraConfig) { + public String getCameraId(@NonNull VirtualCameraConfig cameraConfig) { connectVirtualCameraServiceIfNeeded(); try { diff --git a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java index f5db6e962d01..bc35fea2ce32 100644 --- a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java +++ b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java @@ -20,6 +20,7 @@ import static android.Manifest.permission.ACCESS_CONTEXTUAL_SEARCH; import static android.app.AppOpsManager.OP_ASSIST_SCREENSHOT; import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE; import static android.content.Context.CONTEXTUAL_SEARCH_SERVICE; +import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION; import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION; @@ -245,7 +246,7 @@ public class ContextualSearchManagerService extends SystemService { if (DEBUG_USER) Log.d(TAG, "Launch component: " + launchIntent.getComponent()); launchIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_ANIMATION - | FLAG_ACTIVITY_NO_USER_ACTION); + | FLAG_ACTIVITY_NO_USER_ACTION | FLAG_ACTIVITY_CLEAR_TASK); launchIntent.putExtra( ContextualSearchManager.EXTRA_INVOCATION_TIME_MS, SystemClock.uptimeMillis()); diff --git a/services/core/Android.bp b/services/core/Android.bp index f1339e91d3d4..167c38418058 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -93,38 +93,6 @@ genrule { } genrule { - name: "checked-protolog.json", - srcs: [ - ":generate-protolog.json", - ":services.core.protolog.json", - ], - cmd: "cp $(location :generate-protolog.json) $(out) && " + - "{ ! (diff $(out) $(location :services.core.protolog.json) | grep -q '^<') || " + - "{ echo -e '\\n\\n################################################################\\n#\\n" + - "# ERROR: ProtoLog viewer config is stale. To update it, run:\\n#\\n" + - "# cp $${ANDROID_BUILD_TOP}/$(location :generate-protolog.json) " + - "$${ANDROID_BUILD_TOP}/$(location :services.core.protolog.json)\\n#\\n" + - "################################################################\\n\\n' >&2 && false; } }", - out: ["services.core.protolog.json"], -} - -genrule { - name: "checked-core.protolog.pb", - srcs: [ - ":gen-core.protolog.pb", - ":file-core.protolog.pb", - ], - cmd: "cp $(location :gen-core.protolog.pb) $(out) && " + - "{ ! (diff $(out) $(location :file-core.protolog.pb) | grep -q '^<') || " + - "{ echo -e '\\n\\n################################################################\\n#\\n" + - "# ERROR: ProtoLog viewer config is stale. To update it, run:\\n#\\n" + - "# cp $${ANDROID_BUILD_TOP}/$(location :gen-core.protolog.pb) " + - "$${ANDROID_BUILD_TOP}/$(location :file-core.protolog.pb)\\n#\\n" + - "################################################################\\n\\n' >&2 && false; } }", - out: ["core.protolog.pb"], -} - -genrule { name: "statslog-art-java-gen", tools: ["stats-log-api-gen"], cmd: "$(location stats-log-api-gen) --java $(out) --module art" + @@ -303,7 +271,7 @@ prebuilt_etc { genrule { name: "services.core.json.gz", - srcs: [":checked-protolog.json"], + srcs: [":generate-protolog.json"], out: ["services.core.protolog.json.gz"], cmd: "gzip -c < $(in) > $(out)", } @@ -315,5 +283,5 @@ prebuilt_etc { prebuilt_etc { name: "core.protolog.pb", - src: ":checked-core.protolog.pb", + src: ":gen-core.protolog.pb", } diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index e64a87f3966b..43774bbc51ca 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -368,17 +368,17 @@ public abstract class PackageManagerInternal { Intent intent, @Nullable String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int filterCallingUid, int userId); - /** * Retrieve all receivers that can handle a broadcast of the given intent. + * * @param filterCallingUid The results will be filtered in the context of this UID instead * of the calling UID. - * @param forSend true if the invocation is intended for sending broadcasts. The value - * of this parameter affects how packages are filtered. + * @param forSend true if the invocation is intended for sending broadcasts. The value + * of this parameter affects how packages are filtered. */ - public abstract List<ResolveInfo> queryIntentReceivers(Intent intent, - String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, - int filterCallingUid, int userId, boolean forSend); + public abstract List<ResolveInfo> queryIntentReceivers( + Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, + int filterCallingUid, int callingPid, int userId, boolean forSend); /** * Retrieve all services that can be performed for the given intent. @@ -611,17 +611,9 @@ public abstract class PackageManagerInternal { @NonNull Set<String> outInvalidPackageNames); /** - * Resolves an activity intent, allowing instant apps to be resolved. - */ - public abstract ResolveInfo resolveIntent(Intent intent, String resolvedType, - @PackageManager.ResolveInfoFlagsBits long flags, - @PrivateResolveFlags long privateResolveFlags, int userId, boolean resolveForStart, - int filterCallingUid); - - /** * Resolves an exported activity intent, allowing instant apps to be resolved. */ - public abstract ResolveInfo resolveIntentExported(Intent intent, String resolvedType, + public abstract ResolveInfo resolveIntent(Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, @PrivateResolveFlags long privateResolveFlags, int userId, boolean resolveForStart, int filterCallingUid, int callingPid); @@ -632,6 +624,15 @@ public abstract class PackageManagerInternal { public abstract ResolveInfo resolveService(Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId, int callingUid); + + /** + * Resolves a service intent for start. + */ + public abstract ResolveInfo resolveService( + Intent intent, String resolvedType, + @PackageManager.ResolveInfoFlagsBits long flags, int userId, + int callingUid, int callingPid); + /** * Resolves a content provider intent. */ diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS index 2545620a2630..c4d38e46da3c 100644 --- a/services/core/java/com/android/server/OWNERS +++ b/services/core/java/com/android/server/OWNERS @@ -1,5 +1,5 @@ # BootReceiver / Watchdog -per-file BootReceiver.java,Watchdog.java = gaillard@google.com +per-file BootReceiver.java,Watchdog.java = benmiles@google.com # Connectivity / Networking per-file ConnectivityService.java,ConnectivityServiceInitializer.java,NetworkManagementService.java,NsdService.java,VpnManagerService.java = file:/services/core/java/com/android/server/net/OWNERS diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java index 8c1bb3b0cb71..44aea15b2bde 100644 --- a/services/core/java/com/android/server/SystemConfig.java +++ b/services/core/java/com/android/server/SystemConfig.java @@ -352,7 +352,7 @@ public class SystemConfig { @NonNull private final Set<String> mInitialNonStoppedSystemPackages = new ArraySet<>(); // Which packages (key) are allowed to join particular SharedUid (value). - @NonNull private final Map<String, String> mPackageToSharedUidAllowList = new ArrayMap<>(); + @NonNull private final ArrayMap<String, String> mPackageToSharedUidAllowList = new ArrayMap<>(); // A map of preloaded package names and the path to its app metadata file path. private final ArrayMap<String, String> mAppMetadataFilePaths = new ArrayMap<>(); @@ -574,7 +574,7 @@ public class SystemConfig { } @NonNull - public Map<String, String> getPackageToSharedUidAllowList() { + public ArrayMap<String, String> getPackageToSharedUidAllowList() { return mPackageToSharedUidAllowList; } @@ -720,6 +720,9 @@ public class SystemConfig { } // Read configuration of features, libs and priv-app permissions from apex module. int apexPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS; + if (android.permission.flags.Flags.apexSignaturePermissionAllowlistEnabled()) { + apexPermissionFlag |= ALLOW_SIGNATURE_PERMISSIONS; + } // TODO: Use a solid way to filter apex module folders? for (File f: FileUtils.listFilesOrEmpty(Environment.getApexDirectory())) { if (f.isFile() || f.getPath().contains("@")) { @@ -1322,6 +1325,8 @@ public class SystemConfig { Environment.getProductDirectory().toPath() + "/"); boolean systemExt = permFile.toPath().startsWith( Environment.getSystemExtDirectory().toPath() + "/"); + boolean apex = permFile.toPath().startsWith( + Environment.getApexDirectory().toPath() + "/"); if (vendor) { readSignatureAppPermissions(parser, mPermissionAllowlist.getVendorSignatureAppAllowlist()); @@ -1331,6 +1336,9 @@ public class SystemConfig { } else if (systemExt) { readSignatureAppPermissions(parser, mPermissionAllowlist.getSystemExtSignatureAppAllowlist()); + } else if (apex) { + readSignatureAppPermissions(parser, + mPermissionAllowlist.getApexSignatureAppAllowlist()); } else { readSignatureAppPermissions(parser, mPermissionAllowlist.getSignatureAppAllowlist()); diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index f1d358486333..1c13ad5b3ceb 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -32,6 +32,7 @@ import static android.app.UiModeManager.PROJECTION_TYPE_AUTOMOTIVE; import static android.app.UiModeManager.PROJECTION_TYPE_NONE; import static android.os.UserHandle.USER_SYSTEM; import static android.os.UserHandle.getCallingUserId; +import static android.os.UserManager.isVisibleBackgroundUsersEnabled; import static android.provider.Settings.Secure.CONTRAST_LEVEL; import static android.util.TimeUtils.isTimeBetween; @@ -99,6 +100,7 @@ import com.android.internal.app.DisableCarModeActivity; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.util.DumpUtils; +import com.android.server.pm.UserManagerService; import com.android.server.twilight.TwilightListener; import com.android.server.twilight.TwilightManager; import com.android.server.twilight.TwilightState; @@ -848,6 +850,8 @@ final class UiModeManagerService extends SystemService { } final int user = UserHandle.getCallingUserId(); + enforceValidCallingUser(user); + final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { @@ -910,6 +914,8 @@ final class UiModeManagerService extends SystemService { @AttentionModeThemeOverlayType int attentionModeThemeOverlayType) { setAttentionModeThemeOverlay_enforcePermission(); + enforceValidCallingUser(UserHandle.getCallingUserId()); + synchronized (mLock) { if (mAttentionModeThemeOverlay != attentionModeThemeOverlayType) { mAttentionModeThemeOverlay = attentionModeThemeOverlayType; @@ -999,6 +1005,8 @@ final class UiModeManagerService extends SystemService { return false; } final int user = Binder.getCallingUserHandle().getIdentifier(); + enforceValidCallingUser(user); + if (user != mCurrentUser && getContext().checkCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) { @@ -1056,6 +1064,8 @@ final class UiModeManagerService extends SystemService { return; } final int user = UserHandle.getCallingUserId(); + enforceValidCallingUser(user); + final long ident = Binder.clearCallingIdentity(); try { LocalTime newTime = LocalTime.ofNanoOfDay(time * 1000); @@ -1084,6 +1094,8 @@ final class UiModeManagerService extends SystemService { return; } final int user = UserHandle.getCallingUserId(); + enforceValidCallingUser(user); + final long ident = Binder.clearCallingIdentity(); try { LocalTime newTime = LocalTime.ofNanoOfDay(time * 1000); @@ -1104,6 +1116,8 @@ final class UiModeManagerService extends SystemService { assertLegit(callingPackage); assertSingleProjectionType(projectionType); enforceProjectionTypePermissions(projectionType); + enforceValidCallingUser(getCallingUserId()); + synchronized (mLock) { if (mProjectionHolders == null) { mProjectionHolders = new SparseArray<>(1); @@ -1148,6 +1162,8 @@ final class UiModeManagerService extends SystemService { assertLegit(callingPackage); assertSingleProjectionType(projectionType); enforceProjectionTypePermissions(projectionType); + enforceValidCallingUser(getCallingUserId()); + return releaseProjectionUnchecked(projectionType, callingPackage); } @@ -1187,6 +1203,9 @@ final class UiModeManagerService extends SystemService { if (projectionType == PROJECTION_TYPE_NONE) { return; } + + enforceValidCallingUser(getCallingUserId()); + synchronized (mLock) { if (mProjectionListeners == null) { mProjectionListeners = new SparseArray<>(1); @@ -1234,6 +1253,32 @@ final class UiModeManagerService extends SystemService { } }; + // This method validates whether calling user is valid in visible background users + // feature. Valid user is the current user or the system or in the same profile group as + // the current user. + private void enforceValidCallingUser(int userId) { + if (!isVisibleBackgroundUsersEnabled()) { + return; + } + if (LOG) { + Slog.d(TAG, "enforceValidCallingUser: userId=" + userId + + " isSystemUser=" + (userId == USER_SYSTEM) + " current user=" + mCurrentUser + + " callingPid=" + Binder.getCallingPid() + + " callingUid=" + mInjector.getCallingUid()); + } + long ident = Binder.clearCallingIdentity(); + try { + if (userId != USER_SYSTEM && userId != mCurrentUser + && !UserManagerService.getInstance().isSameProfileGroup(userId, mCurrentUser)) { + throw new SecurityException( + "Calling user is not valid for level-1 compatibility in MUMD. " + + "callingUserId=" + userId + " currentUserId=" + mCurrentUser); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + private void enforceProjectionTypePermissions(@UiModeManager.ProjectionType int p) { if ((p & PROJECTION_TYPE_AUTOMOTIVE) != 0) { getContext().enforceCallingPermission( diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 59ebc6e98842..0c1d0fb27288 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -830,7 +830,8 @@ public final class ActiveServices { for (int i = 0; i < smap.mServicesByInstanceName.size(); i++) { final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i); if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) { - if (Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) { + if (sr.foregroundNoti != null + && Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) { if (DEBUG_FOREGROUND_SERVICE) { Slog.d(TAG_SERVICE, "Channel u" + userId + "/pkg=" + pkg + "/channelId=" + channelId @@ -4862,7 +4863,7 @@ public final class ActiveServices { } // TODO: come back and remove this assumption to triage all services ResolveInfo rInfo = mAm.getPackageManagerInternal().resolveService(service, - resolvedType, flags, userId, callingUid); + resolvedType, flags, userId, callingUid, callingPid); ServiceInfo sInfo = rInfo != null ? rInfo.serviceInfo : null; if (sInfo == null) { Slog.w(TAG_SERVICE, "Unable to start service " + service + " U=" + userId + @@ -4982,7 +4983,7 @@ public final class ActiveServices { try { ResolveInfo rInfoForUserId0 = mAm.getPackageManagerInternal().resolveService(service, - resolvedType, flags, userId, callingUid); + resolvedType, flags, userId, callingUid, callingPid); if (rInfoForUserId0 == null) { Slog.w(TAG_SERVICE, "Unable to resolve service " + service + " U=" + userId diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index f7278e9f986d..d79d198b554e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -137,7 +137,6 @@ import static android.util.FeatureFlagUtils.SETTINGS_ENABLE_MONITOR_PHANTOM_PROC import static android.view.Display.INVALID_DISPLAY; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; -import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH; import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NEW_MUTABLE_IMPLICIT_PENDING_INTENT_RETRIEVED; import static com.android.sdksandbox.flags.Flags.sdkSandboxInstrumentationInfo; import static com.android.server.am.ActiveServices.FGS_SAW_RESTRICTIONS; @@ -268,9 +267,7 @@ import android.app.usage.UsageStatsManagerInternal; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetManagerInternal; import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledAfter; import android.compat.annotation.EnabledSince; -import android.compat.annotation.Overridable; import android.content.AttributionSource; import android.content.AutofillOptions; import android.content.BroadcastReceiver; @@ -467,7 +464,7 @@ import com.android.server.net.NetworkManagementInternal; import com.android.server.os.NativeTombstoneManager; import com.android.server.pm.Computer; import com.android.server.pm.Installer; -import com.android.server.pm.PackageManagerServiceUtils; +import com.android.server.pm.SaferIntentUtils; import com.android.server.pm.UserManagerInternal; import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.android.server.pm.pkg.AndroidPackage; @@ -666,18 +663,6 @@ public class ActivityManagerService extends IActivityManager.Stub private static final long DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED = 161145287L; /** - * Apps targeting Android U and above will need to export components in order to invoke them - * through implicit intents. - * - * If a component is not exported and invoked, it will be removed from the list of receivers. - * This applies specifically to activities and broadcasts. - */ - @ChangeId - @Overridable - @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) - public static final long IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS = 229362273; - - /** * The maximum number of bytes that {@link #setProcessStateSummary} accepts. * * @see {@link android.app.ActivityManager#setProcessStateSummary(byte[])} @@ -5551,9 +5536,10 @@ public class ActivityManagerService extends IActivityManager.Stub packageName, UserHandle.of(userId)); String resolvedType = resolvedTypes == null || i >= resolvedTypes.length ? null : resolvedTypes[i]; - ActivityManagerUtils.logUnsafeIntentEvent( + SaferIntentUtils.reportUnsafeIntentEvent( UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NEW_MUTABLE_IMPLICIT_PENDING_INTENT_RETRIEVED, - owningUid, intent, resolvedType, isChangeEnabled); + owningUid, Process.INVALID_PID, + intent, resolvedType, isChangeEnabled); if (isChangeEnabled) { String msg = packageName + ": Targeting U+ (version " + Build.VERSION_CODES.UPSIDE_DOWN_CAKE + " and above) disallows" @@ -5813,7 +5799,7 @@ public class ActivityManagerService extends IActivityManager.Stub intent, matchFlags, uid, userId)); case ActivityManager.INTENT_SENDER_BROADCAST: return new ParceledListSlice<>(mPackageManagerInt.queryIntentReceivers( - intent, resolvedType, matchFlags, uid, userId, false)); + intent, resolvedType, matchFlags, uid, Process.INVALID_PID, userId, false)); default: // ActivityManager.INTENT_SENDER_ACTIVITY_RESULT throw new IllegalStateException("Unsupported intent sender type: " + res.key.type); } @@ -9521,14 +9507,13 @@ public class ActivityManagerService extends IActivityManager.Stub * @param callback The binder used to communicate the violations. */ @Override - public void registerStrictModeCallback(IBinder callback) { + public synchronized void registerStrictModeCallback(IBinder callback) { int callingPid = Binder.getCallingPid(); mStrictModeCallbacks.put(callingPid, IUnsafeIntentStrictModeCallback.Stub.asInterface(callback)); try { - callback.linkToDeath(new DeathRecipient() { - @Override - public void binderDied() { + callback.linkToDeath(() -> { + synchronized (ActivityManagerService.this) { mStrictModeCallbacks.remove(callingPid); } }, 0); @@ -10222,6 +10207,19 @@ public class ActivityManagerService extends IActivityManager.Stub addStartInfoTimestampInternal(key, timestampNs, userId, callingUid); } + @Override + public void reportStartInfoViewTimestamps(long renderThreadDrawStartTimeNs, + long framePresentedTimeNs) { + int callingUid = Binder.getCallingUid(); + int userId = UserHandle.getUserId(callingUid); + addStartInfoTimestampInternal( + ApplicationStartInfo.START_TIMESTAMP_INITIAL_RENDERTHREAD_FRAME, + renderThreadDrawStartTimeNs, userId, callingUid); + addStartInfoTimestampInternal( + ApplicationStartInfo.START_TIMESTAMP_SURFACEFLINGER_COMPOSITION_COMPLETE, + framePresentedTimeNs, userId, callingUid); + } + private void addStartInfoTimestampInternal(int key, long timestampNs, int userId, int uid) { mProcessList.getAppStartInfoTracker().addTimestampToStart( Settings.getPackageNameForUid(mContext, uid), @@ -10439,11 +10437,6 @@ public class ActivityManagerService extends IActivityManager.Stub public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver) { - final int callingUid = Binder.getCallingUid(); - if (callingUid != ROOT_UID && callingUid != Process.SHELL_UID) { - resultReceiver.send(-1, null); - throw new SecurityException("Shell commands are only callable by root or shell"); - } (new ActivityManagerShellCommand(this, false)).exec( this, in, out, err, args, callback, resultReceiver); } @@ -13731,64 +13724,6 @@ public class ActivityManagerService extends IActivityManager.Stub } /** - * Filters out non-exported components in a given list of broadcast filters - * @param intent the original intent - * @param callingUid the calling UID - * @param query the list of broadcast filters - * @param platformCompat the instance of platform compat - */ - private void filterNonExportedComponents(Intent intent, int callingUid, int callingPid, - List query, PlatformCompat platformCompat, String callerPackage, String resolvedType) { - if (query == null - || intent.getPackage() != null - || intent.getComponent() != null - || ActivityManager.canAccessUnexportedComponents(callingUid)) { - return; - } - IUnsafeIntentStrictModeCallback callback = mStrictModeCallbacks.get(callingPid); - for (int i = query.size() - 1; i >= 0; i--) { - String componentInfo; - ResolveInfo resolveInfo; - BroadcastFilter broadcastFilter; - if (query.get(i) instanceof ResolveInfo) { - resolveInfo = (ResolveInfo) query.get(i); - if (resolveInfo.getComponentInfo().exported) { - continue; - } - componentInfo = resolveInfo.getComponentInfo() - .getComponentName().flattenToShortString(); - } else if (query.get(i) instanceof BroadcastFilter) { - broadcastFilter = (BroadcastFilter) query.get(i); - if (broadcastFilter.exported) { - continue; - } - componentInfo = broadcastFilter.packageName; - } else { - continue; - } - if (callback != null) { - mHandler.post(() -> { - try { - callback.onImplicitIntentMatchedInternalComponent(intent.cloneFilter()); - } catch (RemoteException e) { - mStrictModeCallbacks.remove(callingPid); - } - }); - } - boolean hasToBeExportedToMatch = platformCompat.isChangeEnabledByUid( - ActivityManagerService.IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS, - callingUid); - ActivityManagerUtils.logUnsafeIntentEvent( - UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH, - callingUid, intent, resolvedType, hasToBeExportedToMatch); - if (!hasToBeExportedToMatch) { - return; - } - query.remove(i); - } - } - - /** * Main code for cleaning up a process when it has gone away. This is * called both as a result of the process dying, or directly when stopping * a process when running in single process mode. @@ -15101,8 +15036,9 @@ public class ActivityManagerService extends IActivityManager.Stub mProcessList.sendPackageBroadcastLocked(cmd, packages, userId); } - private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType, - int callingUid, int[] users, int[] broadcastAllowList) { + private List<ResolveInfo> collectReceiverComponents( + Intent intent, String resolvedType, int callingUid, int callingPid, + int[] users, int[] broadcastAllowList) { // TODO: come back and remove this assumption to triage all broadcasts long pmFlags = STOCK_PM_FLAGS | MATCH_DEBUG_TRIAGED_MISSING; @@ -15117,7 +15053,7 @@ public class ActivityManagerService extends IActivityManager.Stub continue; } List<ResolveInfo> newReceivers = mPackageManagerInt.queryIntentReceivers( - intent, resolvedType, pmFlags, callingUid, user, true /* forSend */); + intent, resolvedType, pmFlags, callingUid, callingPid, user, /* forSend */true); if (user != UserHandle.USER_SYSTEM && newReceivers != null) { // If this is not the system user, we need to check for // any receivers that should be filtered out. @@ -15135,7 +15071,7 @@ public class ActivityManagerService extends IActivityManager.Stub final ResolveInfo ri = newReceivers.get(i); final Resolution<ResolveInfo> resolution = mComponentAliasResolver.resolveReceiver(intent, ri, resolvedType, - pmFlags, user, callingUid, true /* forSend */); + pmFlags, user, callingUid, callingPid); if (resolution == null) { // It was an alias, but the target was not found. newReceivers.remove(i); @@ -15338,15 +15274,50 @@ public class ActivityManagerService extends IActivityManager.Stub BackgroundStartPrivileges backgroundStartPrivileges, @Nullable int[] broadcastAllowList, @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) { - final int cookie = BroadcastQueue.traceBegin("broadcastIntentLockedTraced"); - final int res = broadcastIntentLockedTraced(callerApp, callerPackage, callerFeatureId, - intent, resolvedType, resultToApp, resultTo, resultCode, resultData, resultExtras, - requiredPermissions, excludedPermissions, excludedPackages, appOp, - BroadcastOptions.fromBundleNullable(bOptions), ordered, sticky, - callingPid, callingUid, realCallingUid, realCallingPid, userId, - backgroundStartPrivileges, broadcastAllowList, filterExtrasForReceiver); - BroadcastQueue.traceEnd(cookie); - return res; + final int cookie = traceBroadcastIntentBegin(intent, resultTo, ordered, sticky, + callingUid, realCallingUid, userId); + try { + final int res = broadcastIntentLockedTraced(callerApp, callerPackage, callerFeatureId, + intent, resolvedType, resultToApp, resultTo, resultCode, resultData, + resultExtras, requiredPermissions, excludedPermissions, excludedPackages, + appOp, BroadcastOptions.fromBundleNullable(bOptions), ordered, sticky, + callingPid, callingUid, realCallingUid, realCallingPid, userId, + backgroundStartPrivileges, broadcastAllowList, filterExtrasForReceiver); + return res; + } finally { + traceBroadcastIntentEnd(cookie); + } + } + + private static int traceBroadcastIntentBegin(Intent intent, IIntentReceiver resultTo, + boolean ordered, boolean sticky, int callingUid, int realCallingUid, int userId) { + if (!Flags.traceReceiverRegistration()) { + return BroadcastQueue.traceBegin("broadcastIntentLockedTraced"); + } + if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) { + final StringBuilder sb = new StringBuilder("broadcastIntent: "); + sb.append(callingUid); sb.append('/'); + final String action = intent.getAction(); + sb.append(action == null ? null : action); sb.append('/'); + sb.append("0x"); sb.append(Integer.toHexString(intent.getFlags())); sb.append('/'); + sb.append(ordered ? "O" : "_"); + sb.append(sticky ? "S" : "_"); + sb.append(resultTo != null ? "C" : "_"); + sb.append('/'); + sb.append('u'); sb.append(userId); + if (callingUid != realCallingUid) { + sb.append('/'); + sb.append("sender="); sb.append(realCallingUid); + } + return BroadcastQueue.traceBegin(sb.toString()); + } + return 0; + } + + private static void traceBroadcastIntentEnd(int cookie) { + if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) { + BroadcastQueue.traceEnd(cookie); + } } @GuardedBy("this") @@ -15977,6 +15948,10 @@ public class ActivityManagerService extends IActivityManager.Stub users = new int[] {userId}; } + var args = new SaferIntentUtils.IntentArgs(intent, resolvedType, + true /* isReceiver */, true /* resolveForStart */, callingUid, callingPid); + args.platformCompat = mPlatformCompat; + // Figure out who all will receive this broadcast. final int cookie = BroadcastQueue.traceBegin("queryReceivers"); List receivers = null; @@ -15984,7 +15959,7 @@ public class ActivityManagerService extends IActivityManager.Stub // Need to resolve the intent to interested receivers... if ((intent.getFlags() & Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { receivers = collectReceiverComponents( - intent, resolvedType, callingUid, users, broadcastAllowList); + intent, resolvedType, callingUid, callingPid, users, broadcastAllowList); } if (intent.getComponent() == null) { final PackageDataSnapshot snapshot = getPackageManagerInternal().snapshot(); @@ -16009,9 +15984,7 @@ public class ActivityManagerService extends IActivityManager.Stub resolvedType, false /*defaultOnly*/, userId); } if (registeredReceivers != null) { - PackageManagerServiceUtils.applyNullActionBlocking( - mPlatformCompat, snapshot, registeredReceivers, - true, intent, callingUid); + SaferIntentUtils.blockNullAction(args, registeredReceivers); } } BroadcastQueue.traceEnd(cookie); @@ -16033,8 +16006,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - filterNonExportedComponents(intent, callingUid, callingPid, registeredReceivers, - mPlatformCompat, callerPackage, resolvedType); int NR = registeredReceivers != null ? registeredReceivers.size() : 0; // Merge into one list. @@ -16117,8 +16088,7 @@ public class ActivityManagerService extends IActivityManager.Stub if ((receivers != null && receivers.size() > 0) || resultTo != null) { BroadcastQueue queue = mBroadcastQueue; - filterNonExportedComponents(intent, callingUid, callingPid, receivers, - mPlatformCompat, callerPackage, resolvedType); + SaferIntentUtils.filterNonExportedComponents(args, receivers); BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType, requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions, @@ -19926,13 +19896,23 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public IUnsafeIntentStrictModeCallback getRegisteredStrictModeCallback(int callingPid) { - return mStrictModeCallbacks.get(callingPid); - } - - @Override - public void unregisterStrictModeCallback(int callingPid) { - mStrictModeCallbacks.remove(callingPid); + public void triggerUnsafeIntentStrictMode(int callingPid, int type, Intent intent) { + final IUnsafeIntentStrictModeCallback callback; + final Intent i = intent.cloneFilter(); + synchronized (ActivityManagerService.this) { + callback = mStrictModeCallbacks.get(callingPid); + } + if (callback != null) { + BackgroundThread.getExecutor().execute(() -> { + try { + callback.onUnsafeIntent(type, i); + } catch (RemoteException e) { + synchronized (ActivityManagerService.this) { + mStrictModeCallbacks.remove(callingPid); + } + } + }); + } } @Override diff --git a/services/core/java/com/android/server/am/ActivityManagerUtils.java b/services/core/java/com/android/server/am/ActivityManagerUtils.java index 78a2ecb8fba1..3e43a82b4abf 100644 --- a/services/core/java/com/android/server/am/ActivityManagerUtils.java +++ b/services/core/java/com/android/server/am/ActivityManagerUtils.java @@ -17,13 +17,11 @@ package com.android.server.am; import android.app.ActivityThread; import android.content.ContentResolver; -import android.content.Intent; import android.provider.Settings; import android.util.ArrayMap; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.FrameworkStatsLog; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -127,25 +125,4 @@ public class ActivityManagerUtils { return (((double) hash) / Integer.MAX_VALUE) <= rate; } - - /** - * Helper method to log an unsafe intent event. - */ - public static void logUnsafeIntentEvent(int event, int callingUid, - Intent intent, String resolvedType, boolean blocked) { - String[] categories = intent.getCategories() == null ? new String[0] - : intent.getCategories().toArray(String[]::new); - String component = intent.getComponent() == null ? null - : intent.getComponent().flattenToString(); - FrameworkStatsLog.write(FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED, - event, - callingUid, - component, - intent.getPackage(), - intent.getAction(), - categories, - resolvedType, - intent.getScheme(), - blocked); - } } diff --git a/services/core/java/com/android/server/am/AppStartInfoTracker.java b/services/core/java/com/android/server/am/AppStartInfoTracker.java index a8227fa8e38b..dc6e2fa39b65 100644 --- a/services/core/java/com/android/server/am/AppStartInfoTracker.java +++ b/services/core/java/com/android/server/am/AppStartInfoTracker.java @@ -1128,21 +1128,8 @@ public final class AppStartInfoTracker { // Records are sorted newest to oldest, grab record at index 0. ApplicationStartInfo startInfo = mInfos.get(0); - int startupState = startInfo.getStartupState(); - // If startup state is error then don't accept any further timestamps. - if (startupState == ApplicationStartInfo.STARTUP_STATE_ERROR) { - if (DEBUG) Slog.d(TAG, "Startup state is error, not accepting new timestamps."); - return; - } - - // If startup state is first frame drawn then only accept fully drawn timestamp. - if (startupState == ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN - && key != ApplicationStartInfo.START_TIMESTAMP_FULLY_DRAWN) { - if (DEBUG) { - Slog.d(TAG, "Startup state is first frame drawn and timestamp is not fully " - + "drawn, not accepting new timestamps."); - } + if (!isAddTimestampAllowed(startInfo, key, timestampNs)) { return; } @@ -1155,6 +1142,55 @@ public final class AppStartInfoTracker { } } + private boolean isAddTimestampAllowed(ApplicationStartInfo startInfo, int key, + long timestampNs) { + int startupState = startInfo.getStartupState(); + + // If startup state is error then don't accept any further timestamps. + if (startupState == ApplicationStartInfo.STARTUP_STATE_ERROR) { + if (DEBUG) Slog.d(TAG, "Startup state is error, not accepting new timestamps."); + return false; + } + + Map<Integer, Long> timestamps = startInfo.getStartupTimestamps(); + + if (startupState == ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN) { + switch (key) { + case ApplicationStartInfo.START_TIMESTAMP_FULLY_DRAWN: + // Allowed, continue to confirm it's not already added. + break; + case ApplicationStartInfo.START_TIMESTAMP_INITIAL_RENDERTHREAD_FRAME: + Long firstFrameTimeNs = timestamps + .get(ApplicationStartInfo.START_TIMESTAMP_FIRST_FRAME); + if (firstFrameTimeNs == null) { + // This should never happen. State can't be first frame drawn if first + // frame timestamp was not provided. + return false; + } + + if (timestampNs > firstFrameTimeNs) { + // Initial renderthread frame has to occur before first frame. + return false; + } + + // Allowed, continue to confirm it's not already added. + break; + case ApplicationStartInfo.START_TIMESTAMP_SURFACEFLINGER_COMPOSITION_COMPLETE: + // Allowed, continue to confirm it's not already added. + break; + default: + return false; + } + } + + if (timestamps.get(key) != null) { + // Timestamp should not occur more than once for a given start. + return false; + } + + return true; + } + @GuardedBy("mLock") void dumpLocked(PrintWriter pw, String prefix, SimpleDateFormat sdf) { if (mMonitoringModeEnabled) { diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index d642b02e23ea..29e0f7ae6f01 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -122,12 +122,14 @@ import com.android.server.net.BaseNetworkObserver; import com.android.server.pm.UserManagerInternal; import com.android.server.power.optimization.Flags; import com.android.server.power.stats.AggregatedPowerStatsConfig; +import com.android.server.power.stats.AudioPowerStatsProcessor; import com.android.server.power.stats.BatteryExternalStatsWorker; import com.android.server.power.stats.BatteryStatsDumpHelperImpl; import com.android.server.power.stats.BatteryStatsImpl; import com.android.server.power.stats.BatteryUsageStatsProvider; import com.android.server.power.stats.BluetoothPowerStatsProcessor; import com.android.server.power.stats.CpuPowerStatsProcessor; +import com.android.server.power.stats.FlashlightPowerStatsProcessor; import com.android.server.power.stats.MobileRadioPowerStatsProcessor; import com.android.server.power.stats.PhoneCallPowerStatsProcessor; import com.android.server.power.stats.PowerStatsAggregator; @@ -136,6 +138,7 @@ import com.android.server.power.stats.PowerStatsScheduler; import com.android.server.power.stats.PowerStatsStore; import com.android.server.power.stats.PowerStatsUidResolver; import com.android.server.power.stats.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes; +import com.android.server.power.stats.VideoPowerStatsProcessor; import com.android.server.power.stats.WifiPowerStatsProcessor; import com.android.server.power.stats.wakeups.CpuWakeupStats; @@ -194,7 +197,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub private final BatteryUsageStatsProvider mBatteryUsageStatsProvider; private final AtomicFile mConfigFile; private final BatteryStats.BatteryStatsDumpHelper mDumpHelper; - private final PowerStatsUidResolver mPowerStatsUidResolver; + private final PowerStatsUidResolver mPowerStatsUidResolver = new PowerStatsUidResolver(); private final AggregatedPowerStatsConfig mAggregatedPowerStatsConfig; private volatile boolean mMonitorEnabled = true; @@ -422,7 +425,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub setPowerStatsThrottlePeriods(batteryStatsConfigBuilder, context.getResources().getString( com.android.internal.R.string.config_powerStatsThrottlePeriods)); mBatteryStatsConfig = batteryStatsConfigBuilder.build(); - mPowerStatsUidResolver = new PowerStatsUidResolver(); mStats = new BatteryStatsImpl(mBatteryStatsConfig, Clock.SYSTEM_CLOCK, mMonotonicClock, systemDir, mHandler, this, this, mUserManagerUserInfoProvider, mPowerProfile, mCpuScalingPolicies, mPowerStatsUidResolver); @@ -516,6 +518,42 @@ public final class BatteryStatsService extends IBatteryStats.Stub AggregatedPowerStatsConfig.STATE_PROCESS_STATE) .setProcessor( new BluetoothPowerStatsProcessor(mPowerProfile)); + + config.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_AUDIO) + .trackDeviceStates( + AggregatedPowerStatsConfig.STATE_POWER, + AggregatedPowerStatsConfig.STATE_SCREEN) + .trackUidStates( + AggregatedPowerStatsConfig.STATE_POWER, + AggregatedPowerStatsConfig.STATE_SCREEN, + AggregatedPowerStatsConfig.STATE_PROCESS_STATE) + .setProcessor( + new AudioPowerStatsProcessor(mPowerProfile, + mPowerStatsUidResolver)); + + config.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_VIDEO) + .trackDeviceStates( + AggregatedPowerStatsConfig.STATE_POWER, + AggregatedPowerStatsConfig.STATE_SCREEN) + .trackUidStates( + AggregatedPowerStatsConfig.STATE_POWER, + AggregatedPowerStatsConfig.STATE_SCREEN, + AggregatedPowerStatsConfig.STATE_PROCESS_STATE) + .setProcessor( + new VideoPowerStatsProcessor(mPowerProfile, + mPowerStatsUidResolver)); + + config.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT) + .trackDeviceStates( + AggregatedPowerStatsConfig.STATE_POWER, + AggregatedPowerStatsConfig.STATE_SCREEN) + .trackUidStates( + AggregatedPowerStatsConfig.STATE_POWER, + AggregatedPowerStatsConfig.STATE_SCREEN, + AggregatedPowerStatsConfig.STATE_PROCESS_STATE) + .setProcessor( + new FlashlightPowerStatsProcessor(mPowerProfile, + mPowerStatsUidResolver)); return config; } @@ -583,6 +621,24 @@ public final class BatteryStatsService extends IBatteryStats.Stub BatteryConsumer.POWER_COMPONENT_BLUETOOTH, Flags.streamlinedConnectivityBatteryStats()); + mStats.setPowerStatsCollectorEnabled(BatteryConsumer.POWER_COMPONENT_AUDIO, + Flags.streamlinedMiscBatteryStats()); + mBatteryUsageStatsProvider.setPowerStatsExporterEnabled( + BatteryConsumer.POWER_COMPONENT_AUDIO, + Flags.streamlinedMiscBatteryStats()); + + mStats.setPowerStatsCollectorEnabled(BatteryConsumer.POWER_COMPONENT_VIDEO, + Flags.streamlinedMiscBatteryStats()); + mBatteryUsageStatsProvider.setPowerStatsExporterEnabled( + BatteryConsumer.POWER_COMPONENT_VIDEO, + Flags.streamlinedMiscBatteryStats()); + + mStats.setPowerStatsCollectorEnabled(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT, + Flags.streamlinedMiscBatteryStats()); + mBatteryUsageStatsProvider.setPowerStatsExporterEnabled( + BatteryConsumer.POWER_COMPONENT_FLASHLIGHT, + Flags.streamlinedMiscBatteryStats()); + mWorker.systemServicesReady(); mStats.systemServicesReady(mContext); mCpuWakeupStats.systemServicesReady(); diff --git a/services/core/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java index 749427730ca0..adb2392a8484 100644 --- a/services/core/java/com/android/server/am/BroadcastFilter.java +++ b/services/core/java/com/android/server/am/BroadcastFilter.java @@ -26,7 +26,7 @@ import dalvik.annotation.optimization.NeverCompile; import java.io.PrintWriter; -final class BroadcastFilter extends IntentFilter { +public final class BroadcastFilter extends IntentFilter { // Back-pointer to the list this filter is in. final ReceiverList receiverList; final String packageName; @@ -37,7 +37,7 @@ final class BroadcastFilter extends IntentFilter { final int owningUserId; final boolean instantApp; final boolean visibleToInstantApp; - final boolean exported; + public final boolean exported; BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList, String _packageName, String _featureId, String _receiverId, String _requiredPermission, diff --git a/services/core/java/com/android/server/am/ComponentAliasResolver.java b/services/core/java/com/android/server/am/ComponentAliasResolver.java index 3fa6102b64e0..5d84fd925356 100644 --- a/services/core/java/com/android/server/am/ComponentAliasResolver.java +++ b/services/core/java/com/android/server/am/ComponentAliasResolver.java @@ -455,9 +455,9 @@ public class ComponentAliasResolver { } @Nullable - public Resolution<ResolveInfo> resolveReceiver(@NonNull Intent intent, - @NonNull ResolveInfo receiver, @Nullable String resolvedType, - long packageFlags, int userId, int callingUid, boolean forSend) { + public Resolution<ResolveInfo> resolveReceiver( + @NonNull Intent intent, @NonNull ResolveInfo receiver, @Nullable String resolvedType, + long packageFlags, int userId, int callingUid, int callingPid) { // Resolve this alias. final Resolution<ComponentName> resolution = resolveComponentAlias(() -> receiver.activityInfo.getComponentName()); @@ -481,7 +481,7 @@ public class ComponentAliasResolver { i.setComponent(resolution.getTarget()); List<ResolveInfo> resolved = pmi.queryIntentReceivers( - i, resolvedType, packageFlags, callingUid, userId, forSend); + i, resolvedType, packageFlags, callingUid, callingPid, userId, /*forSend*/ true); if (resolved == null || resolved.size() == 0) { // Target component not found. Slog.w(TAG, "Alias target " + target.flattenToShortString() + " not found"); diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index 032093b91746..9a3b575bbaaf 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -141,6 +141,7 @@ public class SettingsToPropertiesMapper { "app_widgets", "arc_next", "art_mainline", + "art_performance", "avic", "biometrics", "biometrics_framework", diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java index f9f56ee4d134..266093229186 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java @@ -316,6 +316,8 @@ public class FingerprintAuthenticationClient if (getBiometricContext().isAwake()) { mALSProbeCallback.getProbe().enable(); + } else { + mALSProbeCallback.getProbe().disable(); } } catch (RemoteException e) { Slog.e(TAG, "Remote exception", e); diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index 4c3020f58870..0afca92d78f7 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -30,7 +30,6 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.app.ActivityManagerInternal; -import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.IUriGrantsManager; import android.app.KeyguardManager; @@ -48,9 +47,8 @@ import android.content.IClipboard; import android.content.IOnPrimaryClipChangedListener; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.IPackageManager; -import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.UserInfo; import android.graphics.drawable.Drawable; import android.hardware.display.DisplayManager; @@ -1247,20 +1245,13 @@ public class ClipboardService extends SystemService { @GuardedBy("mLock") private void addActiveOwnerLocked(int uid, int deviceId, String pkg) { - final IPackageManager pm = AppGlobals.getPackageManager(); + final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class); final int targetUserHandle = UserHandle.getCallingUserId(); final long oldIdentity = Binder.clearCallingIdentity(); try { - PackageInfo pi = pm.getPackageInfo(pkg, 0, targetUserHandle); - if (pi == null) { - throw new IllegalArgumentException("Unknown package " + pkg); + if (!pm.isSameApp(pkg, 0, uid, targetUserHandle)) { + throw new SecurityException("Calling uid " + uid + " does not own package " + pkg); } - if (!UserHandle.isSameApp(pi.applicationInfo.uid, uid)) { - throw new SecurityException("Calling uid " + uid - + " does not own package " + pkg); - } - } catch (RemoteException e) { - // Can't happen; the package manager is in the same process } finally { Binder.restoreCallingIdentity(oldIdentity); } diff --git a/services/core/java/com/android/server/criticalevents/OWNERS b/services/core/java/com/android/server/criticalevents/OWNERS index 9c3136c592f1..7935bedbbb7a 100644 --- a/services/core/java/com/android/server/criticalevents/OWNERS +++ b/services/core/java/com/android/server/criticalevents/OWNERS @@ -1,2 +1 @@ benmiles@google.com -gaillard@google.com diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index eeacc53f0fd4..e4db634c0e26 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java +++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java @@ -230,6 +230,16 @@ import javax.xml.datatype.DatatypeConfigurationException; * <nits>55.2</nits> * </displayBrightnessPoint> * </blockingZoneThreshold> + * <supportedModes> + * <point> + * <first>60</first> // refresh rate + * <second>60</second> // vsync + * </point> + * <point> + * <first>120</first> // refresh rate + * <second>120</second> // vsync + * </point> + * </supportedModes> * </lowerBlockingZoneConfigs> * <higherBlockingZoneConfigs> * <defaultRefreshRate>90</defaultRefreshRate> @@ -244,6 +254,16 @@ import javax.xml.datatype.DatatypeConfigurationException; * </displayBrightnessPoint> * </blockingZoneThreshold> * </higherBlockingZoneConfigs> + * <lowPowerSupportedModes> + * <point> + * <first>60</first> // refresh rate + * <second>60</second> // vsync + * </point> + * <point> + * <first>60</first> // refresh rate + * <second>240</second> // vsync + * </point> + * </lowPowerSupportedModes> * </refreshRate> * * <highBrightnessMode enabled="true"> diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 8d71c701cf87..195a516b663c 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -159,7 +159,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private static final int MSG_STATSD_HBM_BRIGHTNESS = 11; private static final int MSG_SWITCH_USER = 12; private static final int MSG_BOOT_COMPLETED = 13; - private static final int MSG_SET_DWBC_STRONG_MODE = 14; + private static final int MSG_SWITCH_AUTOBRIGHTNESS_MODE = 14; private static final int MSG_SET_DWBC_COLOR_OVERRIDE = 15; private static final int MSG_SET_DWBC_LOGGING_ENABLED = 16; private static final int MSG_SET_BRIGHTNESS_FROM_OFFLOAD = 17; @@ -1184,15 +1184,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call @Override public void setAutomaticScreenBrightnessMode( @AutomaticBrightnessController.AutomaticBrightnessMode int mode) { - boolean isIdle = mode == AUTO_BRIGHTNESS_MODE_IDLE; - if (mAutomaticBrightnessController != null) { - // Set sendUpdate to true to make sure that updatePowerState() gets called - mAutomaticBrightnessController.switchMode(mode, /* sendUpdate= */ true); - setAnimatorRampSpeeds(isIdle); - } Message msg = mHandler.obtainMessage(); - msg.what = MSG_SET_DWBC_STRONG_MODE; - msg.arg1 = isIdle ? 1 : 0; + msg.what = MSG_SWITCH_AUTOBRIGHTNESS_MODE; + msg.arg1 = mode; mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); } @@ -1361,7 +1355,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call state = mPowerState.getScreenState(); DisplayBrightnessState displayBrightnessState = mDisplayBrightnessController - .updateBrightness(mPowerRequest, state); + .updateBrightness(mPowerRequest, state, mDisplayOffloadSession); float brightnessState = displayBrightnessState.getBrightness(); float rawBrightnessState = displayBrightnessState.getBrightness(); mBrightnessReasonTemp.set(displayBrightnessState.getBrightnessReason()); @@ -1374,6 +1368,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (displayBrightnessState.getBrightnessEvent() != null) { mTempBrightnessEvent.copyFrom(displayBrightnessState.getBrightnessEvent()); } + + boolean allowAutoBrightnessWhileDozing = + mDisplayBrightnessController.isAllowAutoBrightnessWhileDozing(); + if (!mFlags.isRefactorDisplayPowerControllerEnabled()) { // Set up the ScreenOff controller used when coming out of SCREEN_OFF and the ALS sensor // doesn't yet have a valid lux value to use with auto-brightness. @@ -1381,8 +1379,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mScreenOffBrightnessSensorController .setLightSensorEnabled(displayBrightnessState.getShouldUseAutoBrightness() && mIsEnabled && (state == Display.STATE_OFF - || (state == Display.STATE_DOZE - && !mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig())) + || (state == Display.STATE_DOZE && !allowAutoBrightnessWhileDozing)) && mLeadDisplayId == Layout.NO_LEAD_DISPLAY); } } @@ -1392,12 +1389,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call final boolean wasShortTermModelActive = mAutomaticBrightnessStrategy.isShortTermModelActive(); boolean userInitiatedChange = displayBrightnessState.isUserInitiatedChange(); - boolean allowAutoBrightnessWhileDozing = - mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig(); - if (mFlags.offloadControlsDozeAutoBrightness() && mFlags.isDisplayOffloadEnabled() - && mDisplayOffloadSession != null) { - allowAutoBrightnessWhileDozing &= mDisplayOffloadSession.allowAutoBrightnessInDoze(); - } + if (!mFlags.isRefactorDisplayPowerControllerEnabled()) { // Switch to doze auto-brightness mode if needed if (mFlags.areAutoBrightnessModesEnabled() && mAutomaticBrightnessController != null @@ -1868,7 +1860,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private void setDwbcStrongMode(int arg) { if (mDisplayWhiteBalanceController != null) { - final boolean isIdle = (arg == 1); + final boolean isIdle = (arg == AUTO_BRIGHTNESS_MODE_IDLE); mDisplayWhiteBalanceController.setStrongModeEnabled(isIdle); } } @@ -3034,7 +3026,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call updatePowerState(); break; - case MSG_SET_DWBC_STRONG_MODE: + case MSG_SWITCH_AUTOBRIGHTNESS_MODE: + boolean isIdle = msg.arg1 == AUTO_BRIGHTNESS_MODE_IDLE; + if (mAutomaticBrightnessController != null) { + mAutomaticBrightnessController.switchMode(msg.arg1, /* sendUpdate= */ true); + setAnimatorRampSpeeds(isIdle); + } setDwbcStrongMode(msg.arg1); break; diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java index d567331a59ce..4982a0b0b836 100644 --- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java +++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java @@ -146,11 +146,13 @@ public final class DisplayBrightnessController { */ public DisplayBrightnessState updateBrightness( DisplayManagerInternal.DisplayPowerRequest displayPowerRequest, - int targetDisplayState) { + int targetDisplayState, + DisplayManagerInternal.DisplayOffloadSession displayOffloadSession) { DisplayBrightnessState state; synchronized (mLock) { mDisplayBrightnessStrategy = mDisplayBrightnessStrategySelector.selectStrategy( - constructStrategySelectionRequest(displayPowerRequest, targetDisplayState)); + constructStrategySelectionRequest(displayPowerRequest, targetDisplayState, + displayOffloadSession)); state = mDisplayBrightnessStrategy .updateBrightness(constructStrategyExecutionRequest(displayPowerRequest)); } @@ -204,6 +206,16 @@ public final class DisplayBrightnessController { * Returns a boolean flag indicating if the light sensor is to be used to decide the screen * brightness when dozing */ + public boolean isAllowAutoBrightnessWhileDozing() { + synchronized (mLock) { + return mDisplayBrightnessStrategySelector.isAllowAutoBrightnessWhileDozing(); + } + } + + /** + * Returns the config value indicating the auto brightness while dozing is to be + * allowed ot not. Note that this is a config value, but the actual status can differ from this. + */ public boolean isAllowAutoBrightnessWhileDozingConfig() { synchronized (mLock) { return mDisplayBrightnessStrategySelector.isAllowAutoBrightnessWhileDozingConfig(); @@ -587,14 +599,15 @@ public final class DisplayBrightnessController { private StrategySelectionRequest constructStrategySelectionRequest( DisplayManagerInternal.DisplayPowerRequest displayPowerRequest, - int targetDisplayState) { + int targetDisplayState, + DisplayManagerInternal.DisplayOffloadSession displayOffloadSession) { boolean userSetBrightnessChanged = updateUserSetScreenBrightness(); float lastUserSetScreenBrightness; synchronized (mLock) { lastUserSetScreenBrightness = mLastUserSetScreenBrightness; } return new StrategySelectionRequest(displayPowerRequest, targetDisplayState, - lastUserSetScreenBrightness, userSetBrightnessChanged); + lastUserSetScreenBrightness, userSetBrightnessChanged, displayOffloadSession); } private StrategyExecutionRequest constructStrategyExecutionRequest( diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java index feec4e6b2259..7835220d5c13 100644 --- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java +++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java @@ -48,9 +48,14 @@ import java.io.PrintWriter; */ public class DisplayBrightnessStrategySelector { private static final String TAG = "DisplayBrightnessStrategySelector"; - // True if light sensor is to be used to automatically determine doze screen brightness. + // True if the config to use the light sensor to automatically determine doze screen brightness + // is enabled. Note that the actual value representing if the auto-brightness is to be kept + // enabled while dozing can differ, but is dependent on this private final boolean mAllowAutoBrightnessWhileDozingConfig; + // True if light sensor is to be used to automatically determine doze screen brightness. + private boolean mAllowAutoBrightnessWhileDozing; + // The brightness strategy used to manage the brightness state when the display is dozing. private final DozeBrightnessStrategy mDozeBrightnessStrategy; // The brightness strategy used to manage the brightness state when the display is in @@ -149,6 +154,7 @@ public class DisplayBrightnessStrategySelector { mAutoBrightnessFallbackStrategy, mFallbackBrightnessStrategy}; mAllowAutoBrightnessWhileDozingConfig = context.getResources().getBoolean( R.bool.config_allowAutoBrightnessWhileDozing); + mAllowAutoBrightnessWhileDozing = mAllowAutoBrightnessWhileDozingConfig; mOldBrightnessStrategyName = mInvalidBrightnessStrategy.getName(); } @@ -163,6 +169,7 @@ public class DisplayBrightnessStrategySelector { int targetDisplayState = strategySelectionRequest.getTargetDisplayState(); DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = strategySelectionRequest .getDisplayPowerRequest(); + setAllowAutoBrightnessWhileDozing(strategySelectionRequest.getDisplayOffloadSession()); if (targetDisplayState == Display.STATE_OFF) { displayBrightnessStrategy = mScreenOffBrightnessStrategy; } else if (shouldUseDozeBrightnessStrategy(displayPowerRequest)) { @@ -231,6 +238,14 @@ public class DisplayBrightnessStrategySelector { * Returns a boolean flag indicating if the light sensor is to be used to decide the screen * brightness when dozing */ + public boolean isAllowAutoBrightnessWhileDozing() { + return mAllowAutoBrightnessWhileDozing; + } + + /** + * Returns the config value indicating whether auto brightness while dozing is to be + * allowed ot not + */ public boolean isAllowAutoBrightnessWhileDozingConfig() { return mAllowAutoBrightnessWhileDozingConfig; } @@ -251,6 +266,8 @@ public class DisplayBrightnessStrategySelector { writer.println( " mAllowAutoBrightnessWhileDozingConfig= " + mAllowAutoBrightnessWhileDozingConfig); + writer.println( + " mAllowAutoBrightnessWhileDozing= " + mAllowAutoBrightnessWhileDozing); IndentingPrintWriter ipw = new IndentingPrintWriter(writer, " "); for (DisplayBrightnessStrategy displayBrightnessStrategy : mDisplayBrightnessStrategies) { if (displayBrightnessStrategy != null) { @@ -259,6 +276,17 @@ public class DisplayBrightnessStrategySelector { } } + @VisibleForTesting + void setAllowAutoBrightnessWhileDozing( + DisplayManagerInternal.DisplayOffloadSession displayOffloadSession) { + mAllowAutoBrightnessWhileDozing = mAllowAutoBrightnessWhileDozingConfig; + if (mDisplayManagerFlags.offloadControlsDozeAutoBrightness() + && mDisplayManagerFlags.isDisplayOffloadEnabled() + && displayOffloadSession != null) { + mAllowAutoBrightnessWhileDozing &= displayOffloadSession.allowAutoBrightnessInDoze(); + } + } + private boolean isAutoBrightnessFallbackStrategyValid() { return mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled() && mAutoBrightnessFallbackStrategy != null @@ -270,7 +298,7 @@ public class DisplayBrightnessStrategySelector { StrategySelectionRequest strategySelectionRequest) { mAutomaticBrightnessStrategy1.setAutoBrightnessState( strategySelectionRequest.getTargetDisplayState(), - mAllowAutoBrightnessWhileDozingConfig, + mAllowAutoBrightnessWhileDozing, BrightnessReason.REASON_UNKNOWN, strategySelectionRequest.getDisplayPowerRequest().policy, strategySelectionRequest.getLastUserSetScreenBrightness(), @@ -287,7 +315,7 @@ public class DisplayBrightnessStrategySelector { selectedDisplayBrightnessStrategy, strategySelectionRequest.getLastUserSetScreenBrightness(), strategySelectionRequest.isUserSetBrightnessChanged(), - isAllowAutoBrightnessWhileDozingConfig(), + mAllowAutoBrightnessWhileDozing, getAutomaticBrightnessStrategy().shouldUseAutoBrightness()); } @@ -309,7 +337,7 @@ public class DisplayBrightnessStrategySelector { // a user can define a different display state(displayPowerRequest.dozeScreenState) too // in the request with the Doze policy return displayPowerRequest.policy == DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE - && !mAllowAutoBrightnessWhileDozingConfig + && !mAllowAutoBrightnessWhileDozing && BrightnessUtils.isValidBrightnessValue(displayPowerRequest.dozeScreenBrightness); } diff --git a/services/core/java/com/android/server/display/brightness/StrategySelectionRequest.java b/services/core/java/com/android/server/display/brightness/StrategySelectionRequest.java index ae745efc8683..aa2f23ef9ec1 100644 --- a/services/core/java/com/android/server/display/brightness/StrategySelectionRequest.java +++ b/services/core/java/com/android/server/display/brightness/StrategySelectionRequest.java @@ -38,13 +38,17 @@ public final class StrategySelectionRequest { // Represents if the user set screen brightness was changed or not. private boolean mUserSetBrightnessChanged; + private DisplayManagerInternal.DisplayOffloadSession mDisplayOffloadSession; + public StrategySelectionRequest(DisplayManagerInternal.DisplayPowerRequest displayPowerRequest, int targetDisplayState, float lastUserSetScreenBrightness, - boolean userSetBrightnessChanged) { + boolean userSetBrightnessChanged, + DisplayManagerInternal.DisplayOffloadSession displayOffloadSession) { mDisplayPowerRequest = displayPowerRequest; mTargetDisplayState = targetDisplayState; mLastUserSetScreenBrightness = lastUserSetScreenBrightness; mUserSetBrightnessChanged = userSetBrightnessChanged; + mDisplayOffloadSession = displayOffloadSession; } public DisplayManagerInternal.DisplayPowerRequest getDisplayPowerRequest() { @@ -64,6 +68,10 @@ public final class StrategySelectionRequest { return mUserSetBrightnessChanged; } + public DisplayManagerInternal.DisplayOffloadSession getDisplayOffloadSession() { + return mDisplayOffloadSession; + } + @Override public boolean equals(Object obj) { if (!(obj instanceof StrategySelectionRequest)) { @@ -73,12 +81,13 @@ public final class StrategySelectionRequest { return Objects.equals(mDisplayPowerRequest, other.getDisplayPowerRequest()) && mTargetDisplayState == other.getTargetDisplayState() && mLastUserSetScreenBrightness == other.getLastUserSetScreenBrightness() - && mUserSetBrightnessChanged == other.isUserSetBrightnessChanged(); + && mUserSetBrightnessChanged == other.isUserSetBrightnessChanged() + && mDisplayOffloadSession.equals(other.getDisplayOffloadSession()); } @Override public int hashCode() { return Objects.hash(mDisplayPowerRequest, mTargetDisplayState, - mLastUserSetScreenBrightness, mUserSetBrightnessChanged); + mLastUserSetScreenBrightness, mUserSetBrightnessChanged, mDisplayOffloadSession); } } diff --git a/services/core/java/com/android/server/display/config/RefreshRateData.java b/services/core/java/com/android/server/display/config/RefreshRateData.java index d7ed904e398d..f769a89551c7 100644 --- a/services/core/java/com/android/server/display/config/RefreshRateData.java +++ b/services/core/java/com/android/server/display/config/RefreshRateData.java @@ -64,18 +64,22 @@ public class RefreshRateData { public final List<SupportedModeData> lowPowerSupportedModes; + public final List<SupportedModeData> lowLightBlockingZoneSupportedModes; + @VisibleForTesting public RefreshRateData(int defaultRefreshRate, int defaultPeakRefreshRate, int defaultRefreshRateInHbmHdr, int defaultRefreshRateInHbmSunlight, - List<SupportedModeData> lowPowerSupportedModes) { + List<SupportedModeData> lowPowerSupportedModes, + List<SupportedModeData> lowLightBlockingZoneSupportedModes) { this.defaultRefreshRate = defaultRefreshRate; this.defaultPeakRefreshRate = defaultPeakRefreshRate; this.defaultRefreshRateInHbmHdr = defaultRefreshRateInHbmHdr; this.defaultRefreshRateInHbmSunlight = defaultRefreshRateInHbmSunlight; this.lowPowerSupportedModes = Collections.unmodifiableList(lowPowerSupportedModes); + this.lowLightBlockingZoneSupportedModes = + Collections.unmodifiableList(lowLightBlockingZoneSupportedModes); } - @Override public String toString() { return "RefreshRateData {" @@ -84,6 +88,7 @@ public class RefreshRateData { + ", defaultRefreshRateInHbmHdr: " + defaultRefreshRateInHbmHdr + ", defaultRefreshRateInHbmSunlight: " + defaultRefreshRateInHbmSunlight + ", lowPowerSupportedModes=" + lowPowerSupportedModes + + ", lowLightBlockingZoneSupportedModes=" + lowLightBlockingZoneSupportedModes + "} "; } @@ -100,13 +105,19 @@ public class RefreshRateData { int defaultRefreshRateInHbmSunlight = loadDefaultRefreshRateInHbmSunlight( refreshRateConfigs, resources); - NonNegativeFloatToFloatMap modes = + NonNegativeFloatToFloatMap lowPowerModes = refreshRateConfigs == null ? null : refreshRateConfigs.getLowPowerSupportedModes(); - List<SupportedModeData> lowPowerSupportedModes = SupportedModeData.load(modes); + List<SupportedModeData> lowPowerSupportedModes = SupportedModeData.load(lowPowerModes); + + BlockingZoneConfig lowerZoneConfig = refreshRateConfigs == null ? null + : refreshRateConfigs.getLowerBlockingZoneConfigs(); + NonNegativeFloatToFloatMap lowerZoneModes = + lowerZoneConfig == null ? null : lowerZoneConfig.getSupportedModes(); + List<SupportedModeData> lowLightSupportedModes = SupportedModeData.load(lowerZoneModes); return new RefreshRateData(defaultRefreshRate, defaultPeakRefreshRate, defaultRefreshRateInHbmHdr, defaultRefreshRateInHbmSunlight, - lowPowerSupportedModes); + lowPowerSupportedModes, lowLightSupportedModes); } private static int loadDefaultRefreshRate( diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java index d519748929bf..d610f086b3b5 100644 --- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java @@ -2157,8 +2157,19 @@ public class DisplayModeDirector { } } + private boolean hasLowLightVrrConfig() { + DisplayDeviceConfig config; + synchronized (mLock) { + config = mDefaultDisplayDeviceConfig; + } + return mVsyncLowLightBlockingVoteEnabled + && config != null + && config.isVrrSupportEnabled() + && !config.getRefreshRateData().lowLightBlockingZoneSupportedModes.isEmpty(); + } + private void restartObserver() { - if (mRefreshRateInLowZone > 0) { + if (mRefreshRateInLowZone > 0 || hasLowLightVrrConfig()) { mShouldObserveDisplayLowChange = hasValidThreshold( mLowDisplayBrightnessThresholds); mShouldObserveAmbientLowChange = hasValidThreshold( @@ -2300,6 +2311,7 @@ public class DisplayModeDirector { return false; } + @GuardedBy("mLock") private void onBrightnessChangedLocked() { if (!mRefreshRateChangeable || mLowPowerModeEnabled) { return; @@ -2315,8 +2327,14 @@ public class DisplayModeDirector { boolean insideLowZone = hasValidLowZone() && isInsideLowZone(mBrightness, mAmbientLux); if (insideLowZone) { - refreshRateVote = - Vote.forPhysicalRefreshRates(mRefreshRateInLowZone, mRefreshRateInLowZone); + if (hasLowLightVrrConfig()) { + refreshRateVote = Vote.forSupportedRefreshRates(mDefaultDisplayDeviceConfig + .getRefreshRateData().lowLightBlockingZoneSupportedModes); + } else { + refreshRateVote = Vote.forPhysicalRefreshRates( + mRefreshRateInLowZone, mRefreshRateInLowZone); + refreshRateSwitchingVote = Vote.forDisableRefreshRateSwitching(); + } if (mLowZoneRefreshRateForThermals != null) { RefreshRateRange range = SkinThermalStatusObserver .findBestMatchingRefreshRateRange(mThermalStatus, @@ -2326,18 +2344,6 @@ public class DisplayModeDirector { Vote.forPhysicalRefreshRates(range.min, range.max); } } - - if (mVsyncLowLightBlockingVoteEnabled - && isVrrSupportedLocked(Display.DEFAULT_DISPLAY)) { - refreshRateSwitchingVote = Vote.forSupportedRefreshRatesAndDisableSwitching( - List.of( - new SupportedRefreshRatesVote.RefreshRates( - /* peakRefreshRate= */ 60f, /* vsyncRate= */ 60f), - new SupportedRefreshRatesVote.RefreshRates( - /* peakRefreshRate= */120f, /* vsyncRate= */ 120f))); - } else { - refreshRateSwitchingVote = Vote.forDisableRefreshRateSwitching(); - } } boolean insideHighZone = hasValidHighZone() @@ -2368,7 +2374,7 @@ public class DisplayModeDirector { } private boolean hasValidLowZone() { - return mRefreshRateInLowZone > 0 + return (mRefreshRateInLowZone > 0 || hasLowLightVrrConfig()) && (mShouldObserveDisplayLowChange || mShouldObserveAmbientLowChange); } diff --git a/services/core/java/com/android/server/display/mode/Vote.java b/services/core/java/com/android/server/display/mode/Vote.java index 1ec469c21f7b..7cbdd13152b5 100644 --- a/services/core/java/com/android/server/display/mode/Vote.java +++ b/services/core/java/com/android/server/display/mode/Vote.java @@ -16,10 +16,13 @@ package com.android.server.display.mode; +import android.annotation.IntDef; import android.annotation.NonNull; import com.android.server.display.config.SupportedModeData; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; @@ -132,15 +135,40 @@ interface Vote { // to function, so this needs to be the highest priority of all votes. int PRIORITY_UDFPS = 20; + @IntDef(prefix = { "PRIORITY_" }, value = { + PRIORITY_DEFAULT_RENDER_FRAME_RATE, + PRIORITY_FLICKER_REFRESH_RATE, + PRIORITY_HIGH_BRIGHTNESS_MODE, + PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE, + PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE, + PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE, + PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE, + PRIORITY_APP_REQUEST_SIZE, + PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, + PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE, + PRIORITY_SYNCHRONIZED_REFRESH_RATE, + PRIORITY_LIMIT_MODE, + PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE, + PRIORITY_LAYOUT_LIMITED_FRAME_RATE, + PRIORITY_SYSTEM_REQUESTED_MODES, + PRIORITY_LOW_POWER_MODE_MODES, + PRIORITY_LOW_POWER_MODE_RENDER_RATE, + PRIORITY_FLICKER_REFRESH_RATE_SWITCH, + PRIORITY_SKIN_TEMPERATURE, + PRIORITY_PROXIMITY, + PRIORITY_UDFPS + }) + @Retention(RetentionPolicy.SOURCE) + @interface Priority {} + // Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and // APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString. - - int MIN_PRIORITY = PRIORITY_DEFAULT_RENDER_FRAME_RATE; - int MAX_PRIORITY = PRIORITY_UDFPS; + @Priority int MIN_PRIORITY = PRIORITY_DEFAULT_RENDER_FRAME_RATE; + @Priority int MAX_PRIORITY = PRIORITY_UDFPS; // The cutoff for the app request refresh rate range. Votes with priorities lower than this // value will not be considered when constructing the app request refresh rate range. - int APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF = + @Priority int APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF = PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE; /** @@ -205,13 +233,6 @@ interface Vote { return new SupportedModesVote(modeIds); } - static Vote forSupportedRefreshRatesAndDisableSwitching( - List<SupportedRefreshRatesVote.RefreshRates> supportedRefreshRates) { - return new CombinedVote( - List.of(forDisableRefreshRateSwitching(), - new SupportedRefreshRatesVote(supportedRefreshRates))); - } - static String priorityToString(int priority) { switch (priority) { case PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE: diff --git a/services/core/java/com/android/server/display/mode/VotesStorage.java b/services/core/java/com/android/server/display/mode/VotesStorage.java index 6becf1c46d05..d41ef6546bc3 100644 --- a/services/core/java/com/android/server/display/mode/VotesStorage.java +++ b/services/core/java/com/android/server/display/mode/VotesStorage.java @@ -79,12 +79,12 @@ class VotesStorage { } /** updates vote storage for all displays */ - void updateGlobalVote(int priority, @Nullable Vote vote) { + void updateGlobalVote(@Vote.Priority int priority, @Nullable Vote vote) { updateVote(GLOBAL_ID, priority, vote); } /** updates vote storage */ - void updateVote(int displayId, int priority, @Nullable Vote vote) { + void updateVote(int displayId, @Vote.Priority int priority, @Nullable Vote vote) { if (mLoggingEnabled) { Slog.i(TAG, "updateVoteLocked(displayId=" + displayId + ", priority=" + Vote.priorityToString(priority) @@ -126,7 +126,7 @@ class VotesStorage { } /** removes all votes with certain priority from vote storage */ - void removeAllVotesForPriority(int priority) { + void removeAllVotesForPriority(@Vote.Priority int priority) { if (mLoggingEnabled) { Slog.i(TAG, "removeAllVotesForPriority(priority=" + Vote.priorityToString(priority) + ")"); diff --git a/services/core/java/com/android/server/dreams/OWNERS b/services/core/java/com/android/server/dreams/OWNERS index 7302f6e38af2..b9286f864031 100644 --- a/services/core/java/com/android/server/dreams/OWNERS +++ b/services/core/java/com/android/server/dreams/OWNERS @@ -1,4 +1,3 @@ -brycelee@google.com -dsandler@android.com -michaelwr@google.com -roosa@google.com +# Bug component: 66910 +include /core/java/android/service/dreams/OWNERS + diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 48cccd5b5b39..0bd40d16ba4c 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -3348,6 +3348,10 @@ public class InputManagerService extends IInputManager.Stub mPointerIconCache.setUseLargePointerIcons(useLargeIcons); } + void setPointerFillStyle(@PointerIcon.PointerIconVectorStyleFill int fillStyle) { + mPointerIconCache.setPointerFillStyle(fillStyle); + } + interface KeyboardBacklightControllerInterface { default void incrementKeyboardBacklight(int deviceId) {} default void decrementKeyboardBacklight(int deviceId) {} diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java index a1341b771eb7..9585b49be3a9 100644 --- a/services/core/java/com/android/server/input/InputSettingsObserver.java +++ b/services/core/java/com/android/server/input/InputSettingsObserver.java @@ -16,6 +16,9 @@ package com.android.server.input; +import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BLACK; +import static android.view.flags.Flags.enableVectorCursorA11ySettings; + import static com.android.input.flags.Flags.rateLimitUserActivityPokeInDispatcher; import android.content.BroadcastReceiver; @@ -96,7 +99,9 @@ class InputSettingsObserver extends ContentObserver { Map.entry(Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_STICKY_KEYS), (reason) -> updateAccessibilityStickyKeys()), Map.entry(Settings.Secure.getUriFor(Settings.Secure.STYLUS_POINTER_ICON_ENABLED), - (reason) -> updateStylusPointerIconEnabled())); + (reason) -> updateStylusPointerIconEnabled()), + Map.entry(Settings.System.getUriFor(Settings.System.POINTER_FILL_STYLE), + (reason) -> updatePointerFillStyleFromSettings())); } /** @@ -261,4 +266,15 @@ class InputSettingsObserver extends ContentObserver { mNative.setStylusPointerIconEnabled( InputSettings.isStylusPointerIconEnabled(mContext, true /* forceReloadSetting */)); } + + private void updatePointerFillStyleFromSettings() { + if (!enableVectorCursorA11ySettings()) { + return; + } + final int pointerFillStyle = Settings.System.getIntForUser( + mContext.getContentResolver(), Settings.System.POINTER_FILL_STYLE, + POINTER_ICON_VECTOR_STYLE_FILL_BLACK, + UserHandle.USER_CURRENT); + mService.setPointerFillStyle(pointerFillStyle); + } } diff --git a/services/core/java/com/android/server/input/PointerIconCache.java b/services/core/java/com/android/server/input/PointerIconCache.java index 233b865c69a6..936e17f51919 100644 --- a/services/core/java/com/android/server/input/PointerIconCache.java +++ b/services/core/java/com/android/server/input/PointerIconCache.java @@ -16,13 +16,17 @@ package com.android.server.input; +import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BLACK; + import android.annotation.NonNull; import android.content.Context; +import android.content.res.Resources; import android.hardware.display.DisplayManager; import android.os.Handler; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; +import android.view.ContextThemeWrapper; import android.view.Display; import android.view.DisplayInfo; import android.view.PointerIcon; @@ -56,6 +60,9 @@ final class PointerIconCache { private final SparseArray<Context> mDisplayContexts = new SparseArray<>(); @GuardedBy("mLoadedPointerIconsByDisplayAndType") private final SparseIntArray mDisplayDensities = new SparseIntArray(); + @GuardedBy("mLoadedPointerIconsByDisplayAndType") + private @PointerIcon.PointerIconVectorStyleFill int mPointerIconFillStyle = + POINTER_ICON_VECTOR_STYLE_FILL_BLACK; private final DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() { @@ -105,6 +112,11 @@ final class PointerIconCache { mUiThreadHandler.post(() -> handleSetUseLargePointerIcons(useLargeIcons)); } + /** Set the fill style for vector pointer icons. */ + public void setPointerFillStyle(@PointerIcon.PointerIconVectorStyleFill int fillStyle) { + mUiThreadHandler.post(() -> handleSetPointerFillStyle(fillStyle)); + } + /** * Get a loaded system pointer icon. This will fetch the icon from the cache, or load it if * it isn't already cached. @@ -119,8 +131,13 @@ final class PointerIconCache { } PointerIcon icon = iconsByType.get(type); if (icon == null) { - icon = PointerIcon.getLoadedSystemIcon(getContextForDisplayLocked(displayId), type, - mUseLargePointerIcons); + Context context = getContextForDisplayLocked(displayId); + Resources.Theme theme = context.getResources().newTheme(); + theme.setTo(context.getTheme()); + theme.applyStyle(PointerIcon.vectorFillStyleToResource(mPointerIconFillStyle), + /* force= */ true); + icon = PointerIcon.getLoadedSystemIcon(new ContextThemeWrapper(context, theme), + type, mUseLargePointerIcons); iconsByType.put(type, icon); } return Objects.requireNonNull(icon); @@ -185,6 +202,19 @@ final class PointerIconCache { mNative.reloadPointerIcons(); } + @android.annotation.UiThread + private void handleSetPointerFillStyle(@PointerIcon.PointerIconVectorStyleFill int fillStyle) { + synchronized (mLoadedPointerIconsByDisplayAndType) { + if (mPointerIconFillStyle == fillStyle) { + return; + } + mPointerIconFillStyle = fillStyle; + // Clear all cached icons on all displays. + mLoadedPointerIconsByDisplayAndType.clear(); + } + mNative.reloadPointerIcons(); + } + // Updates the cached display density for the given displayId, and returns true if // the cached density changed. @GuardedBy("mLoadedPointerIconsByDisplayAndType") diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index ffffb7bd6352..8665a396c32b 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2327,10 +2327,12 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. @NonNull InputMethodBindingController bindingController, @NonNull ClientState cs) { if (bindingController.hasMainConnection()) { if (getCurMethodLocked() != null) { - // Return to client, and we will get back with it when - // we have had a session made for it. - requestClientSessionLocked(cs); - requestClientSessionForAccessibilityLocked(cs); + if (!Flags.useZeroJankProxy()) { + // Return to client, and we will get back with it when + // we have had a session made for it. + requestClientSessionLocked(cs); + requestClientSessionForAccessibilityLocked(cs); + } return new InputBindResult( InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION, null, null, null, @@ -2693,25 +2695,27 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. final boolean canImeDrawsImeNavBar = mImeDrawsImeNavBarRes != null && mImeDrawsImeNavBarRes.get() && hasNavigationBar; final boolean shouldShowImeSwitcherWhenImeIsShown = shouldShowImeSwitcherLocked( - InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE); + InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE, + mCurrentUserId); return (canImeDrawsImeNavBar ? InputMethodNavButtonFlags.IME_DRAWS_IME_NAV_BAR : 0) | (shouldShowImeSwitcherWhenImeIsShown ? InputMethodNavButtonFlags.SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN : 0); } @GuardedBy("ImfLock.class") - private boolean shouldShowImeSwitcherLocked(int visibility) { + private boolean shouldShowImeSwitcherLocked(int visibility, @UserIdInt int userId) { if (!mShowOngoingImeSwitcherForPhones) return false; // When the IME switcher dialog is shown, the IME switcher button should be hidden. + // TODO(b/305849394): Make mMenuController multi-user aware. if (mMenuController.getSwitchingDialogLocked() != null) return false; // When we are switching IMEs, the IME switcher button should be hidden. - final var bindingController = getInputMethodBindingController(mCurrentUserId); + final var bindingController = getInputMethodBindingController(userId); if (!Objects.equals(bindingController.getCurId(), bindingController.getSelectedMethodId())) { return false; } if (mWindowManagerInternal.isKeyguardShowingAndNotOccluded() - && mWindowManagerInternal.isKeyguardSecure(mCurrentUserId)) { + && mWindowManagerInternal.isKeyguardSecure(userId)) { return false; } if ((visibility & InputMethodService.IME_ACTIVE) == 0 @@ -2728,7 +2732,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. return false; } - final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId); + final InputMethodSettings settings = InputMethodSettingsRepository.get(userId); List<InputMethodInfo> imes = settings.getEnabledInputMethodListWithFilter( InputMethodInfo::shouldShowInInputMethodPicker); final int numImes = imes.size(); @@ -2843,14 +2847,22 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. // Caution! This method is called in this class. Handle multi-user carefully @GuardedBy("ImfLock.class") private void updateSystemUiLocked(int vis, int backDisposition) { - if (getCurTokenLocked() == null) { + updateSystemUiLocked(vis, backDisposition, mCurrentUserId); + } + + @GuardedBy("ImfLock.class") + private void updateSystemUiLocked(int vis, int backDisposition, @UserIdInt int userId) { + final var bindingController = getInputMethodBindingController(userId); + final var curToken = bindingController.getCurToken(); + if (curToken == null) { return; } + final int curTokenDisplayId = bindingController.getCurTokenDisplayId(); if (DEBUG) { Slog.d(TAG, "IME window vis: " + vis + " active: " + (vis & InputMethodService.IME_ACTIVE) + " inv: " + (vis & InputMethodService.IME_INVISIBLE) - + " displayId: " + getCurTokenDisplayIdLocked()); + + " displayId: " + curTokenDisplayId); } final IBinder focusedWindowToken = mImeBindingState != null ? mImeBindingState.mFocusedWindow : null; @@ -2869,17 +2881,18 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. } else { vis &= ~InputMethodService.IME_VISIBLE_IMPERCEPTIBLE; } - final var curId = getInputMethodBindingController(mCurrentUserId).getCurId(); + final var curId = bindingController.getCurId(); + // TODO(b/305849394): Make mMenuController multi-user aware. if (mMenuController.getSwitchingDialogLocked() != null - || !Objects.equals(curId, getSelectedMethodIdLocked())) { + || !Objects.equals(curId, bindingController.getSelectedMethodId())) { // When the IME switcher dialog is shown, or we are switching IMEs, // the back button should be in the default state (as if the IME is not shown). backDisposition = InputMethodService.BACK_DISPOSITION_ADJUST_NOTHING; } - final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis); + final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis, userId); if (mStatusBarManagerInternal != null) { - mStatusBarManagerInternal.setImeWindowStatus(getCurTokenDisplayIdLocked(), - getCurTokenLocked(), vis, backDisposition, needsToShowImeSwitcher); + mStatusBarManagerInternal.setImeWindowStatus(curTokenDisplayId, + curToken, vis, backDisposition, needsToShowImeSwitcher); } } finally { Binder.restoreCallingIdentity(ident); diff --git a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java index 189c1a7eb7a0..757c07c0b683 100644 --- a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java +++ b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java @@ -248,6 +248,17 @@ final class ZeroJankProxy implements IInputMethodManagerImpl.Callback { unverifiedTargetSdkVersion, userId, imeDispatcher); sendOnStartInputResult(client, result, startInputSeq); + // For first-time client bind, MSG_BIND should arrive after MSG_START_INPUT_RESULT. + if (result.result == InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION) { + InputMethodManagerService imms = ((InputMethodManagerService) mInner); + synchronized (ImfLock.class) { + ClientState cs = imms.getClientStateLocked(client); + if (cs != null) { + imms.requestClientSessionLocked(cs); + imms.requestClientSessionForAccessibilityLocked(cs); + } + } + } }); } diff --git a/services/core/java/com/android/server/locales/OWNERS b/services/core/java/com/android/server/locales/OWNERS index e1e946b1c51d..7e35dacd758e 100644 --- a/services/core/java/com/android/server/locales/OWNERS +++ b/services/core/java/com/android/server/locales/OWNERS @@ -1,5 +1,4 @@ roosa@google.com -pratyushmore@google.com goldmanj@google.com ankitavyas@google.com allenwtsu@google.com diff --git a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java index f572845dc214..966be5318973 100644 --- a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java +++ b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java @@ -32,6 +32,7 @@ import android.util.ArraySet; import android.util.Slog; import com.android.internal.widget.VerifyCredentialResponse; +import com.android.server.biometrics.BiometricHandlerProvider; import java.util.ArrayList; import java.util.List; @@ -132,9 +133,11 @@ public class BiometricDeferredQueue { mFaceResetLockoutTask = null; }; - BiometricDeferredQueue(@NonNull SyntheticPasswordManager spManager, @NonNull Handler handler) { + BiometricDeferredQueue(@NonNull SyntheticPasswordManager spManager) { mSpManager = spManager; - mHandler = handler; + + //Using a higher priority thread to avoid any delays and interruption of clients + mHandler = BiometricHandlerProvider.getInstance().getBiometricCallbackHandler(); mPendingResetLockoutsForFingerprint = new ArrayList<>(); mPendingResetLockoutsForFace = new ArrayList<>(); mPendingResetLockouts = new ArrayList<>(); diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index ae3d36acdb7f..22b33ddcfa2b 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -687,7 +687,7 @@ public class LockSettingsService extends ILockSettings.Stub { mSpManager = injector.getSyntheticPasswordManager(mStorage); mUnifiedProfilePasswordCache = injector.getUnifiedProfilePasswordCache(mKeyStore); - mBiometricDeferredQueue = new BiometricDeferredQueue(mSpManager, mHandler); + mBiometricDeferredQueue = new BiometricDeferredQueue(mSpManager); mRebootEscrowManager = injector.getRebootEscrowManager(new RebootEscrowCallbacks(), mStorage); diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java index 09605fefe80e..b0fa523da959 100644 --- a/services/core/java/com/android/server/media/MediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java @@ -22,6 +22,7 @@ import android.content.ComponentName; import android.media.MediaRoute2Info; import android.media.MediaRoute2ProviderInfo; import android.media.MediaRouter2; +import android.media.MediaRouter2Utils; import android.media.RouteDiscoveryPreference; import android.media.RoutingSessionInfo; import android.os.Bundle; @@ -226,8 +227,23 @@ abstract class MediaRoute2Provider { return route2Info != null && mTargetOriginalRouteId.equals(route2Info.getOriginalId()); } - public boolean isTargetRouteIdInList(@NonNull List<String> routeOriginalIdList) { - return routeOriginalIdList.stream().anyMatch(mTargetOriginalRouteId::equals); + /** + * Returns whether the given list of {@link MediaRoute2Info#getOriginalId() original ids} + * contains the {@link #mTargetOriginalRouteId target route id}. + */ + public boolean isTargetRouteIdInRouteOriginalIdList( + @NonNull List<String> originalRouteIdList) { + return originalRouteIdList.stream().anyMatch(mTargetOriginalRouteId::equals); + } + + /** + * Returns whether the given list of {@link MediaRoute2Info#getId() unique ids} contains the + * {@link #mTargetOriginalRouteId target route id}. + */ + public boolean isTargetRouteIdInRouteUniqueIdList(@NonNull List<String> uniqueRouteIdList) { + return uniqueRouteIdList.stream() + .map(MediaRouter2Utils::getOriginalId) + .anyMatch(mTargetOriginalRouteId::equals); } } } diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java index 71cbcb91100f..d5e85dae1336 100644 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java @@ -21,6 +21,7 @@ import static android.media.MediaRoute2ProviderService.REQUEST_ID_NONE; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -41,6 +42,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; +import android.util.LongSparseArray; import android.util.Slog; import com.android.internal.annotations.GuardedBy; @@ -49,7 +51,9 @@ import com.android.media.flags.Flags; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; @@ -77,7 +81,16 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider private boolean mLastDiscoveryPreferenceIncludesThisPackage = false; @GuardedBy("mLock") - final List<RoutingSessionInfo> mReleasingSessions = new ArrayList<>(); + private final List<RoutingSessionInfo> mReleasingSessions = new ArrayList<>(); + + // We keep pending requests for transfers and sessions creation separately because transfers + // don't have an associated request id and session creations don't have a session id. + @GuardedBy("mLock") + private final LongSparseArray<SessionCreationOrTransferRequest> + mRequestIdToSessionCreationRequest; + + @GuardedBy("mLock") + private final Map<String, SessionCreationOrTransferRequest> mSessionOriginalIdToTransferRequest; MediaRoute2ProviderServiceProxy( @NonNull Context context, @@ -87,6 +100,8 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider int userId) { super(componentName); mContext = Objects.requireNonNull(context, "Context must not be null."); + mRequestIdToSessionCreationRequest = new LongSparseArray<>(); + mSessionOriginalIdToTransferRequest = new HashMap<>(); mIsSelfScanOnlyProvider = isSelfScanOnlyProvider; mUserId = userId; mHandler = new Handler(looper); @@ -109,6 +124,18 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider @NonNull UserHandle transferInitiatorUserHandle, @NonNull String transferInitiatorPackageName) { if (mConnectionReady) { + if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) { + synchronized (mLock) { + mRequestIdToSessionCreationRequest.put( + requestId, + new SessionCreationOrTransferRequest( + requestId, + routeOriginalId, + transferReason, + transferInitiatorUserHandle, + transferInitiatorPackageName)); + } + } mActiveConnection.requestCreateSession( requestId, packageName, routeOriginalId, sessionHints); updateBinding(); @@ -118,6 +145,11 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider @Override public void releaseSession(long requestId, String sessionId) { if (mConnectionReady) { + if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) { + synchronized (mLock) { + mSessionOriginalIdToTransferRequest.remove(sessionId); + } + } mActiveConnection.releaseSession(requestId, sessionId); updateBinding(); } @@ -158,6 +190,18 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider String routeOriginalId, @RoutingSessionInfo.TransferReason int transferReason) { if (mConnectionReady) { + if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) { + synchronized (mLock) { + mSessionOriginalIdToTransferRequest.put( + sessionOriginalId, + new SessionCreationOrTransferRequest( + requestId, + routeOriginalId, + transferReason, + transferInitiatorUserHandle, + transferInitiatorPackageName)); + } + } mActiveConnection.transferToRoute(requestId, sessionOriginalId, routeOriginalId); } } @@ -384,6 +428,11 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider String newSessionId = newSession.getId(); synchronized (mLock) { + if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) { + newSession = + createSessionWithPopulatedTransferInitiationDataLocked( + requestId, /* oldSessionInfo= */ null, newSession); + } if (mSessionInfos.stream() .anyMatch(session -> TextUtils.equals(session.getId(), newSessionId)) || mReleasingSessions.stream() @@ -397,6 +446,7 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider mCallback.onSessionCreated(this, requestId, newSession); } + @GuardedBy("mLock") private int findSessionByIdLocked(RoutingSessionInfo session) { for (int i = 0; i < mSessionInfos.size(); i++) { if (TextUtils.equals(mSessionInfos.get(i).getId(), session.getId())) { @@ -417,7 +467,6 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider for (RoutingSessionInfo session : sessions) { if (session == null) continue; session = assignProviderIdForSession(session); - int sourceIndex = findSessionByIdLocked(session); if (sourceIndex < 0) { mSessionInfos.add(targetIndex++, session); @@ -425,6 +474,12 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider } else if (sourceIndex < targetIndex) { Slog.w(TAG, "Ignoring duplicate session ID: " + session.getId()); } else { + if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) { + RoutingSessionInfo oldSessionInfo = mSessionInfos.get(sourceIndex); + session = + createSessionWithPopulatedTransferInitiationDataLocked( + REQUEST_ID_NONE, oldSessionInfo, session); + } mSessionInfos.set(sourceIndex, session); Collections.swap(mSessionInfos, sourceIndex, targetIndex++); dispatchSessionUpdated(session); @@ -432,11 +487,65 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider } for (int i = mSessionInfos.size() - 1; i >= targetIndex; i--) { RoutingSessionInfo releasedSession = mSessionInfos.remove(i); + mSessionOriginalIdToTransferRequest.remove(releasedSession.getId()); dispatchSessionReleased(releasedSession); } } } + /** + * Returns a {@link RoutingSessionInfo} with transfer initiation data from the given {@code + * oldSessionInfo}, and any pending transfer or session creation requests. + */ + @GuardedBy("mLock") + private RoutingSessionInfo createSessionWithPopulatedTransferInitiationDataLocked( + long requestId, + @Nullable RoutingSessionInfo oldSessionInfo, + @NonNull RoutingSessionInfo newSessionInfo) { + SessionCreationOrTransferRequest pendingRequest = + oldSessionInfo != null + ? mSessionOriginalIdToTransferRequest.get(newSessionInfo.getOriginalId()) + : mRequestIdToSessionCreationRequest.get(requestId); + boolean pendingTargetRouteInSelectedRoutes = + pendingRequest != null + && pendingRequest.isTargetRouteIdInRouteUniqueIdList( + newSessionInfo.getSelectedRoutes()); + boolean pendingTargetRouteInTransferableRoutes = + pendingRequest != null + && pendingRequest.isTargetRouteIdInRouteUniqueIdList( + newSessionInfo.getTransferableRoutes()); + + int transferReason; + UserHandle transferInitiatorUserHandle; + String transferInitiatorPackageName; + if (pendingTargetRouteInSelectedRoutes) { // The pending request has been satisfied. + transferReason = pendingRequest.mTransferReason; + transferInitiatorUserHandle = pendingRequest.mTransferInitiatorUserHandle; + transferInitiatorPackageName = pendingRequest.mTransferInitiatorPackageName; + } else if (oldSessionInfo != null) { + // No pending request, we copy the values from the old session object. + transferReason = oldSessionInfo.getTransferReason(); + transferInitiatorUserHandle = oldSessionInfo.getTransferInitiatorUserHandle(); + transferInitiatorPackageName = oldSessionInfo.getTransferInitiatorPackageName(); + } else { // There's a new session with no associated creation request, we use defaults. + transferReason = RoutingSessionInfo.TRANSFER_REASON_FALLBACK; + transferInitiatorUserHandle = UserHandle.of(mUserId); + transferInitiatorPackageName = newSessionInfo.getClientPackageName(); + } + if (pendingTargetRouteInSelectedRoutes || !pendingTargetRouteInTransferableRoutes) { + // The pending request has been satisfied, or the target route is no longer available. + if (oldSessionInfo != null) { + mSessionOriginalIdToTransferRequest.remove(newSessionInfo.getId()); + } else if (pendingRequest != null) { + mRequestIdToSessionCreationRequest.remove(pendingRequest.mRequestId); + } + } + return new RoutingSessionInfo.Builder(newSessionInfo) + .setTransferInitiator(transferInitiatorUserHandle, transferInitiatorPackageName) + .setTransferReason(transferReason) + .build(); + } + private void onSessionReleased(Connection connection, RoutingSessionInfo releasedSession) { if (mActiveConnection != connection) { return; @@ -450,6 +559,7 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider boolean found = false; synchronized (mLock) { + mSessionOriginalIdToTransferRequest.remove(releasedSession.getId()); for (RoutingSessionInfo session : mSessionInfos) { if (TextUtils.equals(session.getId(), releasedSession.getId())) { mSessionInfos.remove(session); @@ -498,6 +608,11 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider } private void onRequestFailed(Connection connection, long requestId, int reason) { + if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) { + synchronized (mLock) { + mRequestIdToSessionCreationRequest.remove(requestId); + } + } if (mActiveConnection != connection) { return; } @@ -522,18 +637,29 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider } mSessionInfos.clear(); mReleasingSessions.clear(); + mRequestIdToSessionCreationRequest.clear(); + mSessionOriginalIdToTransferRequest.clear(); } } } @Override protected String getDebugString() { + int pendingSessionCreationCount; + int pendingTransferCount; + synchronized (mLock) { + pendingSessionCreationCount = mRequestIdToSessionCreationRequest.size(); + pendingTransferCount = mSessionOriginalIdToTransferRequest.size(); + } return TextUtils.formatSimple( - "ProviderServiceProxy - package: %s, bound: %b, connection (active:%b, ready:%b)", + "ProviderServiceProxy - package: %s, bound: %b, connection (active:%b, ready:%b), " + + "pending (session creations: %d, transfers: %d)", mComponentName.getPackageName(), mBound, mActiveConnection != null, - mConnectionReady); + mConnectionReady, + pendingSessionCreationCount, + pendingTransferCount); } private final class Connection implements DeathRecipient { diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index c03497e629f0..ba7d3b8c76d2 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -70,6 +70,7 @@ import com.android.internal.util.function.pooled.PooledLambda; import com.android.media.flags.Flags; import com.android.server.LocalServices; import com.android.server.pm.UserManagerInternal; +import com.android.server.statusbar.StatusBarManagerInternal; import java.io.PrintWriter; import java.lang.ref.WeakReference; @@ -118,6 +119,7 @@ class MediaRouter2ServiceImpl { private final UserManagerInternal mUserManagerInternal; private final Object mLock = new Object(); private final AppOpsManager mAppOpsManager; + private final StatusBarManagerInternal mStatusBarManagerInternal; final AtomicInteger mNextRouterOrManagerId = new AtomicInteger(1); final ActivityManager mActivityManager; final PowerManager mPowerManager; @@ -188,6 +190,7 @@ class MediaRouter2ServiceImpl { mPowerManager = mContext.getSystemService(PowerManager.class); mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); mAppOpsManager = mContext.getSystemService(AppOpsManager.class); + mStatusBarManagerInternal = LocalServices.getService(StatusBarManagerInternal.class); IntentFilter screenOnOffIntentFilter = new IntentFilter(); screenOnOffIntentFilter.addAction(ACTION_SCREEN_ON); @@ -260,6 +263,17 @@ class MediaRouter2ServiceImpl { } } + @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS) + public boolean showMediaOutputSwitcherWithRouter2(@NonNull String packageName) { + UserHandle userHandle = Binder.getCallingUserHandle(); + final long token = Binder.clearCallingIdentity(); + try { + return showOutputSwitcher(packageName, userHandle); + } finally { + Binder.restoreCallingIdentity(token); + } + } + public void registerRouter2(@NonNull IMediaRouter2 router, @NonNull String packageName) { Objects.requireNonNull(router, "router must not be null"); if (TextUtils.isEmpty(packageName)) { @@ -778,6 +792,31 @@ class MediaRouter2ServiceImpl { } } + @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS) + public boolean showMediaOutputSwitcherWithProxyRouter( + @NonNull IMediaRouter2Manager proxyRouter) { + Objects.requireNonNull(proxyRouter, "Proxy router must not be null"); + + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + final IBinder binder = proxyRouter.asBinder(); + ManagerRecord proxyRouterRecord = mAllManagerRecords.get(binder); + + if (proxyRouterRecord.mTargetPackageName == null) { + throw new UnsupportedOperationException( + "Only proxy routers can show the Output Switcher."); + } + + return showOutputSwitcher( + proxyRouterRecord.mTargetPackageName, + UserHandle.of(proxyRouterRecord.mUserRecord.mUserId)); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + // End of methods that implement MediaRouter2Manager operations. // Start of methods that implements operations for both MediaRouter2 and MediaRouter2Manager. @@ -934,6 +973,19 @@ class MediaRouter2ServiceImpl { } } + @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS) + private boolean showOutputSwitcher( + @NonNull String packageName, @NonNull UserHandle userHandle) { + if (mActivityManager.getPackageImportance(packageName) > IMPORTANCE_FOREGROUND) { + Slog.w(TAG, "showMediaOutputSwitcher only works when called from foreground"); + return false; + } + synchronized (mLock) { + mStatusBarManagerInternal.showMediaOutputSwitcher(packageName, userHandle); + } + return true; + } + // End of methods that implements operations for both MediaRouter2 and MediaRouter2Manager. public void dump(@NonNull PrintWriter pw, @NonNull String prefix) { diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index 192ac6287884..1188a0764051 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -16,7 +16,6 @@ package com.android.server.media; -import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; import android.Manifest; import android.annotation.NonNull; @@ -75,7 +74,6 @@ import com.android.media.flags.Flags; import com.android.server.LocalServices; import com.android.server.Watchdog; import com.android.server.pm.UserManagerInternal; -import com.android.server.statusbar.StatusBarManagerInternal; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -266,32 +264,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub // Binder call @Override - public boolean showMediaOutputSwitcher(String packageName) { - int uid = Binder.getCallingUid(); - if (!validatePackageName(uid, packageName)) { - throw new SecurityException("packageName must match the calling identity"); - } - UserHandle userHandle = UserHandle.getUserHandleForUid(uid); - final long token = Binder.clearCallingIdentity(); - try { - if (mContext.getSystemService(ActivityManager.class).getPackageImportance(packageName) - > IMPORTANCE_FOREGROUND) { - Slog.w(TAG, "showMediaOutputSwitcher only works when called from foreground"); - return false; - } - synchronized (mLock) { - StatusBarManagerInternal statusBar = - LocalServices.getService(StatusBarManagerInternal.class); - statusBar.showMediaOutputSwitcher(packageName, userHandle); - } - } finally { - Binder.restoreCallingIdentity(token); - } - return true; - } - - // Binder call - @Override public MediaRouterClientState getState(IMediaRouterClient client) { final long token = Binder.clearCallingIdentity(); try { @@ -443,6 +415,17 @@ public final class MediaRouterService extends IMediaRouterService.Stub } // Binder call + @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS) + @Override + public boolean showMediaOutputSwitcherWithRouter2(@NonNull String packageName) { + int uid = Binder.getCallingUid(); + if (!validatePackageName(uid, packageName)) { + throw new SecurityException("packageName must match the calling identity"); + } + return mService2.showMediaOutputSwitcherWithRouter2(packageName); + } + + // Binder call @Override public void registerRouter2(IMediaRouter2 router, String packageName) { final int uid = Binder.getCallingUid(); @@ -676,6 +659,13 @@ public final class MediaRouterService extends IMediaRouterService.Stub mService2.releaseSessionWithManager(manager, requestId, sessionId); } + @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS) + @Override + public boolean showMediaOutputSwitcherWithProxyRouter( + @NonNull IMediaRouter2Manager proxyRouter) { + return mService2.showMediaOutputSwitcherWithProxyRouter(proxyRouter); + } + void restoreBluetoothA2dp() { try { boolean a2dpOn; diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java index dfb2b0a750e3..89555a9f1de4 100644 --- a/services/core/java/com/android/server/media/MediaSession2Record.java +++ b/services/core/java/com/android/server/media/MediaSession2Record.java @@ -67,7 +67,6 @@ public class MediaSession2Record extends MediaSessionRecordImpl { // The lock is required to prevent `Controller2Callback` from using partially initialized // `MediaSession2Record.this`. synchronized (mLock) { - mUniqueId = sNextMediaSessionRecordId.getAndIncrement(); mSessionToken = sessionToken; mService = service; mHandlerExecutor = new HandlerExecutor(new Handler(handlerLooper)); diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 69f07d5c5f7b..0a9109b3e98c 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -81,6 +81,8 @@ import android.util.Log; import android.util.Slog; import android.view.KeyEvent; +import com.android.internal.annotations.GuardedBy; +import com.android.media.flags.Flags; import com.android.server.LocalServices; import com.android.server.uri.UriGrantsManagerInternal; @@ -229,6 +231,14 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde private int mPolicies; + private final Runnable mUserEngagementTimeoutExpirationRunnable = + () -> { + synchronized (mLock) { + updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ true); + } + }; + + @GuardedBy("mLock") private @UserEngagementState int mUserEngagementState = USER_DISENGAGED; @IntDef({USER_PERMANENTLY_ENGAGED, USER_TEMPORARY_ENGAGED, USER_DISENGAGED}) @@ -238,26 +248,26 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde /** * Indicates that the session is active and in one of the user engaged states. * - * @see #updateUserEngagedStateIfNeededLocked(boolean) () + * @see #updateUserEngagedStateIfNeededLocked(boolean) */ private static final int USER_PERMANENTLY_ENGAGED = 0; /** * Indicates that the session is active and in {@link PlaybackState#STATE_PAUSED} state. * - * @see #updateUserEngagedStateIfNeededLocked(boolean) () + * @see #updateUserEngagedStateIfNeededLocked(boolean) */ private static final int USER_TEMPORARY_ENGAGED = 1; /** * Indicates that the session is either not active or in one of the user disengaged states * - * @see #updateUserEngagedStateIfNeededLocked(boolean) () + * @see #updateUserEngagedStateIfNeededLocked(boolean) */ private static final int USER_DISENGAGED = 2; /** - * Indicates the duration of the temporary engaged states. + * Indicates the duration of the temporary engaged states, in milliseconds. * * <p>Some {@link MediaSession} states like {@link PlaybackState#STATE_PAUSED} are temporarily * engaged, meaning the corresponding session is only considered in an engaged state for the @@ -270,7 +280,7 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde * user-engaged state is not considered user-engaged when transitioning from a non-user engaged * state {@link PlaybackState#STATE_STOPPED}. */ - private static final int TEMP_USER_ENGAGED_TIMEOUT = 600000; + private static final int TEMP_USER_ENGAGED_TIMEOUT_MS = 600000; public MediaSessionRecord( int ownerPid, @@ -284,7 +294,6 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde Looper handlerLooper, int policies) throws RemoteException { - mUniqueId = sNextMediaSessionRecordId.getAndIncrement(); mOwnerPid = ownerPid; mOwnerUid = ownerUid; mUserId = userId; @@ -609,8 +618,7 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde @Override public void expireTempEngaged() { - mHandler.removeCallbacks(mHandleTempEngagedSessionTimeout); - updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ true); + mHandler.post(mUserEngagementTimeoutExpirationRunnable); } /** @@ -1086,11 +1094,6 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde } }; - private final Runnable mHandleTempEngagedSessionTimeout = - () -> { - updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ true); - }; - @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS) private static boolean componentNameExists( @NonNull ComponentName componentName, @NonNull Context context, int userId) { @@ -1107,10 +1110,14 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde return !resolveInfos.isEmpty(); } + @GuardedBy("mLock") private void updateUserEngagedStateIfNeededLocked(boolean isTimeoutExpired) { + if (!Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange()) { + return; + } int oldUserEngagedState = mUserEngagementState; int newUserEngagedState; - if (!isActive() || mPlaybackState == null) { + if (!isActive() || mPlaybackState == null || mDestroyed) { newUserEngagedState = USER_DISENGAGED; } else if (isActive() && mPlaybackState.isActive()) { newUserEngagedState = USER_PERMANENTLY_ENGAGED; @@ -1126,18 +1133,22 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde return; } + mUserEngagementState = newUserEngagedState; if (newUserEngagedState == USER_TEMPORARY_ENGAGED) { - mHandler.postDelayed(mHandleTempEngagedSessionTimeout, TEMP_USER_ENGAGED_TIMEOUT); - } else if (oldUserEngagedState == USER_TEMPORARY_ENGAGED) { - mHandler.removeCallbacks(mHandleTempEngagedSessionTimeout); + mHandler.postDelayed( + mUserEngagementTimeoutExpirationRunnable, TEMP_USER_ENGAGED_TIMEOUT_MS); + } else { + mHandler.removeCallbacks(mUserEngagementTimeoutExpirationRunnable); } boolean wasUserEngaged = oldUserEngagedState != USER_DISENGAGED; boolean isNowUserEngaged = newUserEngagedState != USER_DISENGAGED; - mUserEngagementState = newUserEngagedState; if (wasUserEngaged != isNowUserEngaged) { - mService.onSessionUserEngagementStateChange( - /* mediaSessionRecord= */ this, /* isUserEngaged= */ isNowUserEngaged); + mHandler.post( + () -> + mService.onSessionUserEngagementStateChange( + /* mediaSessionRecord= */ this, + /* isUserEngaged= */ isNowUserEngaged)); } } diff --git a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java index b57b14835987..15f90d4fdd0e 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java +++ b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java @@ -34,8 +34,12 @@ import java.util.concurrent.atomic.AtomicInteger; */ public abstract class MediaSessionRecordImpl { - static final AtomicInteger sNextMediaSessionRecordId = new AtomicInteger(1); - int mUniqueId; + private static final AtomicInteger sNextMediaSessionRecordId = new AtomicInteger(1); + private final int mUniqueId; + + protected MediaSessionRecordImpl() { + mUniqueId = sNextMediaSessionRecordId.getAndIncrement(); + } /** * Get the info for this session. diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index 399866728770..1ebc856af2d8 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -197,6 +197,16 @@ public class MediaSessionService extends SystemService implements Monitor { @GuardedBy("mLock") private final Map<Integer, Set<Notification>> mMediaNotifications = new HashMap<>(); + /** + * Holds all {@link MediaSessionRecordImpl} which we've reported as being {@link + * ActivityManagerInternal#startForegroundServiceDelegate user engaged}. + * + * <p>This map simply prevents invoking {@link + * ActivityManagerInternal#startForegroundServiceDelegate} more than once per session. + */ + @GuardedBy("mLock") + private final Set<MediaSessionRecordImpl> mFgsAllowedMediaSessionRecords = new HashSet<>(); + // The FullUserRecord of the current users. (i.e. The foreground user that isn't a profile) // It's always not null after the MediaSessionService is started. private FullUserRecord mCurrentFullUserRecord; @@ -704,17 +714,31 @@ public class MediaSessionService extends SystemService implements Monitor { int uid = mediaSessionRecord.getUid(); for (Notification mediaNotification : mMediaNotifications.getOrDefault(uid, Set.of())) { if (mediaSessionRecord.isLinkedToNotification(mediaNotification)) { - startFgsDelegate(mediaSessionRecord.getForegroundServiceDelegationOptions()); + startFgsDelegateLocked(mediaSessionRecord); return; } } } } - private void startFgsDelegate( - ForegroundServiceDelegationOptions foregroundServiceDelegationOptions) { + @GuardedBy("mLock") + private void startFgsDelegateLocked(MediaSessionRecordImpl mediaSessionRecord) { + ForegroundServiceDelegationOptions foregroundServiceDelegationOptions = + mediaSessionRecord.getForegroundServiceDelegationOptions(); + if (foregroundServiceDelegationOptions == null) { + return; // This record doesn't support FGS. Typically a MediaSession2 record. + } + if (!mFgsAllowedMediaSessionRecords.add(mediaSessionRecord)) { + return; // This record is already FGS-started. + } final long token = Binder.clearCallingIdentity(); try { + Log.i( + TAG, + TextUtils.formatSimple( + "startFgsDelegate: pkg=%s uid=%d", + foregroundServiceDelegationOptions.mClientPackageName, + foregroundServiceDelegationOptions.mClientUid)); mActivityManagerInternal.startForegroundServiceDelegate( foregroundServiceDelegationOptions, /* connection= */ null); } finally { @@ -748,14 +772,29 @@ public class MediaSessionService extends SystemService implements Monitor { } } - stopFgsDelegate(foregroundServiceDelegationOptions); + stopFgsDelegateLocked(mediaSessionRecord); } } - private void stopFgsDelegate( - ForegroundServiceDelegationOptions foregroundServiceDelegationOptions) { + @GuardedBy("mLock") + private void stopFgsDelegateLocked(MediaSessionRecordImpl mediaSessionRecord) { + ForegroundServiceDelegationOptions foregroundServiceDelegationOptions = + mediaSessionRecord.getForegroundServiceDelegationOptions(); + if (foregroundServiceDelegationOptions == null) { + return; // This record doesn't support FGS. Typically a MediaSession2 record. + } + if (!mFgsAllowedMediaSessionRecords.remove(mediaSessionRecord)) { + return; // This record is not FGS-started. No need to stop it. + } + final long token = Binder.clearCallingIdentity(); try { + Log.i( + TAG, + TextUtils.formatSimple( + "stopFgsDelegate: pkg=%s uid=%d", + foregroundServiceDelegationOptions.mClientPackageName, + foregroundServiceDelegationOptions.mClientUid)); mActivityManagerInternal.stopForegroundServiceDelegate( foregroundServiceDelegationOptions); } finally { @@ -2679,6 +2718,9 @@ public class MediaSessionService extends SystemService implements Monitor { @Override public void expireTempEngagedSessions() { + if (!Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange()) { + return; + } synchronized (mLock) { for (Set<MediaSessionRecordImpl> uidSessions : mUserEngagedSessionsForFgs.values()) { @@ -3194,11 +3236,8 @@ public class MediaSessionService extends SystemService implements Monitor { mMediaNotifications.get(uid).add(postedNotification); for (MediaSessionRecordImpl mediaSessionRecord : mUserEngagedSessionsForFgs.getOrDefault(uid, Set.of())) { - ForegroundServiceDelegationOptions foregroundServiceDelegationOptions = - mediaSessionRecord.getForegroundServiceDelegationOptions(); - if (foregroundServiceDelegationOptions != null - && mediaSessionRecord.isLinkedToNotification(postedNotification)) { - startFgsDelegate(foregroundServiceDelegationOptions); + if (mediaSessionRecord.isLinkedToNotification(postedNotification)) { + startFgsDelegateLocked(mediaSessionRecord); return; } } diff --git a/services/core/java/com/android/server/media/MediaShellCommand.java b/services/core/java/com/android/server/media/MediaShellCommand.java index bea71dc5cedb..19f16cc38000 100644 --- a/services/core/java/com/android/server/media/MediaShellCommand.java +++ b/services/core/java/com/android/server/media/MediaShellCommand.java @@ -113,6 +113,7 @@ public class MediaShellCommand extends ShellCommand { mWriter.println(" media_session list-sessions"); mWriter.println(" media_session monitor <tag>"); mWriter.println(" media_session volume [options]"); + mWriter.println(" media_session expire-temp-engaged-sessions"); mWriter.println(); mWriter.println("media_session dispatch: dispatch a media key to the system."); mWriter.println(" KEY may be: play, pause, play-pause, mute, headsethook,"); @@ -121,6 +122,9 @@ public class MediaShellCommand extends ShellCommand { mWriter.println("media_session monitor: monitor updates to the specified session."); mWriter.println(" Use the tag from list-sessions."); mWriter.println("media_session volume: " + VolumeCtrl.USAGE); + mWriter.println("media_session expire-temp-engaged-sessions: Expires any ongoing"); + mWriter.println(" timers for media sessions in a temporary user-engaged"); + mWriter.println(" state."); mWriter.println(); } diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java index 6b409ee6f482..8c6273ce959f 100644 --- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java @@ -443,7 +443,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { boolean isTransferringToTheSelectedRoute = mPendingTransferRequest.isTargetRoute(selectedRoute); boolean canBePotentiallyTransferred = - mPendingTransferRequest.isTargetRouteIdInList(transferableRoutes); + mPendingTransferRequest.isTargetRouteIdInRouteOriginalIdList( + transferableRoutes); if (isTransferringToTheSelectedRoute) { transferReason = mPendingTransferRequest.mTransferReason; diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index c60ac3a74ebd..f03c639c103c 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -3965,8 +3965,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // allow override without having plans defined. synchronized (mNetworkPoliciesSecondLock) { final SubscriptionPlan plan = getPrimarySubscriptionPlanLocked(subId); - if (overrideMask != SUBSCRIPTION_OVERRIDE_UNMETERED && plan == null - || plan.getDataLimitBehavior() == SubscriptionPlan.LIMIT_BEHAVIOR_UNKNOWN) { + if (overrideMask != SUBSCRIPTION_OVERRIDE_UNMETERED && (plan == null + || plan.getDataLimitBehavior() == SubscriptionPlan.LIMIT_BEHAVIOR_UNKNOWN)) { throw new IllegalStateException( "Must provide valid SubscriptionPlan to enable overriding"); } diff --git a/services/core/java/com/android/server/net/OWNERS b/services/core/java/com/android/server/net/OWNERS index 669cdaaf3ab5..bbc7c013f170 100644 --- a/services/core/java/com/android/server/net/OWNERS +++ b/services/core/java/com/android/server/net/OWNERS @@ -1,5 +1,6 @@ set noparent file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking +per-file NetworkPolicyManagerService.java=jackyu@google.com, sarahchin@google.com jsharkey@android.com sudheersai@google.com diff --git a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerInternal.java b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerInternal.java index 81f11b52dcb7..07af8d042420 100644 --- a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerInternal.java +++ b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerInternal.java @@ -17,5 +17,5 @@ package com.android.server.ondeviceintelligence; public interface OnDeviceIntelligenceManagerInternal { - String getRemoteServicePackageName(); + int getInferenceServiceUid(); }
\ No newline at end of file diff --git a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java index f540f1db6952..59964e0e6e87 100644 --- a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java +++ b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java @@ -56,6 +56,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.ICancellationSignal; +import android.os.IRemoteCallback; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; @@ -143,6 +144,9 @@ public class OnDeviceIntelligenceManagerService extends SystemService { volatile boolean mIsServiceEnabled; @GuardedBy("mLock") + private int remoteInferenceServiceUid = -1; + + @GuardedBy("mLock") private String[] mTemporaryServiceNames; @GuardedBy("mLock") private String[] mTemporaryBroadcastKeys; @@ -174,7 +178,7 @@ public class OnDeviceIntelligenceManagerService extends SystemService { Context.ON_DEVICE_INTELLIGENCE_SERVICE, getOnDeviceIntelligenceManagerService(), /* allowIsolated = */true); LocalServices.addService(OnDeviceIntelligenceManagerInternal.class, - OnDeviceIntelligenceManagerService.this::getRemoteConfiguredPackageName); + this::getRemoteInferenceServiceUid); } @Override @@ -603,7 +607,13 @@ public class OnDeviceIntelligenceManagerService extends SystemService { try { ensureRemoteIntelligenceServiceInitialized(); service.registerRemoteStorageService( - getIRemoteStorageService()); + getIRemoteStorageService(), new IRemoteCallback.Stub() { + @Override + public void sendResult(Bundle bundle) { + final int uid = Binder.getCallingUid(); + setRemoteInferenceServiceUid(uid); + } + }); mRemoteOnDeviceIntelligenceService.run( IOnDeviceIntelligenceService::notifyInferenceServiceConnected); broadcastExecutor.execute( @@ -1038,4 +1048,16 @@ public class OnDeviceIntelligenceManagerService extends SystemService { Settings.Secure.ON_DEVICE_INTELLIGENCE_IDLE_TIMEOUT_MS, TimeUnit.HOURS.toMillis(1), mContext.getUserId()); } + + private int getRemoteInferenceServiceUid() { + synchronized (mLock) { + return remoteInferenceServiceUid; + } + } + + private void setRemoteInferenceServiceUid(int remoteInferenceServiceUid) { + synchronized (mLock){ + this.remoteInferenceServiceUid = remoteInferenceServiceUid; + } + } } diff --git a/services/core/java/com/android/server/os/OWNERS b/services/core/java/com/android/server/os/OWNERS index 70be161ba9a8..e130d9c0344a 100644 --- a/services/core/java/com/android/server/os/OWNERS +++ b/services/core/java/com/android/server/os/OWNERS @@ -2,4 +2,4 @@ per-file Bugreport* = file:/platform/frameworks/native:/cmds/dumpstate/OWNERS # NativeTombstone -per-file NativeTombstone* = gaillard@google.com +per-file NativeTombstone* = benmiles@google.com diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java index 482807c397ea..3528d3d96c2b 100644 --- a/services/core/java/com/android/server/pm/Computer.java +++ b/services/core/java/com/android/server/pm/Computer.java @@ -108,16 +108,20 @@ public interface Computer extends PackageDataSnapshot { default int getUsed() { return 0; } - @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, + @NonNull List<ResolveInfo> queryIntentActivitiesInternal( + Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, - int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits); + int filterCallingUid, int callingPid, int userId, + boolean resolveForStart, boolean allowDynamicSplits); @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, long flags, int filterCallingUid, int userId); @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, long flags, int userId); - @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent, String resolvedType, - long flags, int userId, int callingUid, boolean includeInstantApps); + @NonNull List<ResolveInfo> queryIntentServicesInternal( + Intent intent, String resolvedType, long flags, + int userId, int callingUid, int callingPid, + boolean includeInstantApps, boolean resolveForStart); @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(Intent intent, String resolvedType, long flags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits, String pkgName, diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java index 6a25f64b697d..f59ae168bdc3 100644 --- a/services/core/java/com/android/server/pm/ComputerEngine.java +++ b/services/core/java/com/android/server/pm/ComputerEngine.java @@ -500,10 +500,10 @@ public class ComputerEngine implements Computer { return mUsed; } - public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, - String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, + public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal( + Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, - int filterCallingUid, int userId, boolean resolveForStart, + int filterCallingUid, int callingPid, int userId, boolean resolveForStart, boolean allowDynamicSplits) { if (!mUserManager.exists(userId)) return Collections.emptyList(); @@ -530,6 +530,11 @@ public class ComputerEngine implements Computer { isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId, resolvedType, flags)); + var args = new SaferIntentUtils.IntentArgs(intent, resolvedType, + false /* isReceiver */, resolveForStart, filterCallingUid, callingPid); + args.platformCompat = mInjector.getCompatibility(); + args.snapshot = this; + List<ResolveInfo> list = Collections.emptyList(); boolean skipPostResolution = false; if (comp != null) { @@ -583,9 +588,7 @@ public class ComputerEngine implements Computer { ri.userHandle = UserHandle.of(userId); list = new ArrayList<>(1); list.add(ri); - PackageManagerServiceUtils.applyEnforceIntentFilterMatching( - mInjector.getCompatibility(), this, list, false, intent, - resolvedType, filterCallingUid); + SaferIntentUtils.enforceIntentFilterMatching(args, list); } } } else { @@ -609,15 +612,13 @@ public class ComputerEngine implements Computer { } list = lockedResult.result; } - PackageManagerServiceUtils.applyNullActionBlocking( - mInjector.getCompatibility(), this, list, false, intent, filterCallingUid); + SaferIntentUtils.blockNullAction(args, list); } if (originalIntent != null) { // We also have to ensure all components match the original intent - PackageManagerServiceUtils.applyEnforceIntentFilterMatching( - mInjector.getCompatibility(), this, list, false, originalIntent, - resolvedType, filterCallingUid); + args.intent = originalIntent; + SaferIntentUtils.enforceIntentFilterMatching(args, list); } return skipPostResolution ? list : applyPostResolutionFilter( @@ -631,19 +632,22 @@ public class ComputerEngine implements Computer { @PackageManager.ResolveInfoFlagsBits long flags, int filterCallingUid, int userId) { return queryIntentActivitiesInternal( intent, resolvedType, flags, 0 /*privateResolveFlags*/, filterCallingUid, - userId, false /*resolveForStart*/, true /*allowDynamicSplits*/); + Process.INVALID_PID, userId, + /*resolveForStart*/ false, /*allowDynamicSplits*/ true); } public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) { return queryIntentActivitiesInternal( - intent, resolvedType, flags, 0 /*privateResolveFlags*/, Binder.getCallingUid(), - userId, false /*resolveForStart*/, true /*allowDynamicSplits*/); + intent, resolvedType, flags, 0 /*privateResolveFlags*/, + Binder.getCallingUid(), Process.INVALID_PID, userId, + /*resolveForStart*/ false, /*allowDynamicSplits*/ true); } - public final @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent, - String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId, - int callingUid, boolean includeInstantApps) { + public final @NonNull List<ResolveInfo> queryIntentServicesInternal( + Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, + int userId, int callingUid, int callingPid, + boolean includeInstantApps, boolean resolveForStart) { if (!mUserManager.exists(userId)) return Collections.emptyList(); enforceCrossUserOrProfilePermission(callingUid, userId, @@ -654,6 +658,11 @@ public class ComputerEngine implements Computer { flags = updateFlagsForResolve(flags, userId, callingUid, includeInstantApps, false /* isImplicitImageCaptureIntentAndNotSetByDpc */); + var args = new SaferIntentUtils.IntentArgs(intent, resolvedType, + false /* isReceiver */, resolveForStart, callingUid, callingPid); + args.platformCompat = mInjector.getCompatibility(); + args.snapshot = this; + Intent originalIntent = null; ComponentName comp = intent.getComponent(); if (comp == null) { @@ -699,23 +708,19 @@ public class ComputerEngine implements Computer { ri.serviceInfo = si; list = new ArrayList<>(1); list.add(ri); - PackageManagerServiceUtils.applyEnforceIntentFilterMatching( - mInjector.getCompatibility(), this, list, false, intent, - resolvedType, callingUid); + SaferIntentUtils.enforceIntentFilterMatching(args, list); } } } else { list = queryIntentServicesInternalBody(intent, resolvedType, flags, userId, callingUid, instantAppPkgName); - PackageManagerServiceUtils.applyNullActionBlocking( - mInjector.getCompatibility(), this, list, false, intent, callingUid); + SaferIntentUtils.blockNullAction(args, list); } if (originalIntent != null) { // We also have to ensure all components match the original intent - PackageManagerServiceUtils.applyEnforceIntentFilterMatching( - mInjector.getCompatibility(), this, list, false, originalIntent, - resolvedType, callingUid); + args.intent = originalIntent; + SaferIntentUtils.enforceIntentFilterMatching(args, list); } return list; @@ -847,8 +852,8 @@ public class ComputerEngine implements Computer { // IMPORTANT: disallow dynamic splits to avoid an infinite loop final List<ResolveInfo> result = queryIntentActivitiesInternal( failureActivityIntent, null /*resolvedType*/, 0 /*flags*/, - 0 /*privateResolveFlags*/, filterCallingUid, userId, false /*resolveForStart*/, - false /*allowDynamicSplits*/); + 0 /*privateResolveFlags*/, filterCallingUid, Process.INVALID_PID, userId, + /*resolveForStart*/ false, /*allowDynamicSplits*/ false); final int numResults = result.size(); if (numResults > 0) { for (int i = 0; i < numResults; i++) { @@ -4359,7 +4364,7 @@ public class ComputerEngine implements Computer { uid = getBaseSdkSandboxUid(); } final int callingUserId = UserHandle.getUserId(callingUid); - if (isKnownIsolatedComputeApp(uid, callingUserId)) { + if (isKnownIsolatedComputeApp(uid)) { try { uid = getIsolatedOwner(uid); } catch (IllegalStateException e) { @@ -4402,7 +4407,7 @@ public class ComputerEngine implements Computer { if (Process.isSdkSandboxUid(uid)) { uid = getBaseSdkSandboxUid(); } - if (isKnownIsolatedComputeApp(uid, callingUserId)) { + if (isKnownIsolatedComputeApp(uid)) { try { uid = getIsolatedOwner(uid); } catch (IllegalStateException e) { @@ -5804,7 +5809,7 @@ public class ComputerEngine implements Computer { } - private boolean isKnownIsolatedComputeApp(int uid, int callingUserId) { + private boolean isKnownIsolatedComputeApp(int uid) { if (!Process.isIsolatedUid(uid)) { return false; } @@ -5817,27 +5822,8 @@ public class ComputerEngine implements Computer { } OnDeviceIntelligenceManagerInternal onDeviceIntelligenceManagerInternal = mInjector.getLocalService(OnDeviceIntelligenceManagerInternal.class); - if (onDeviceIntelligenceManagerInternal == null) { - return false; - } - - String onDeviceIntelligencePackage = - onDeviceIntelligenceManagerInternal.getRemoteServicePackageName(); - if (onDeviceIntelligencePackage == null) { - return false; - } - - try { - if (getIsolatedOwner(uid) == getPackageUid(onDeviceIntelligencePackage, 0, - callingUserId)) { - return true; - } - } catch (IllegalStateException e) { - // If the owner uid doesn't exist, just use the current uid - Slog.wtf(TAG, "Expected isolated uid " + uid + " to have an owner", e); - } - - return false; + return onDeviceIntelligenceManagerInternal != null + && uid == onDeviceIntelligenceManagerInternal.getInferenceServiceUid(); } @Nullable diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java index f987d4ae8999..f05c54d666df 100644 --- a/services/core/java/com/android/server/pm/IPackageManagerBase.java +++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java @@ -1095,7 +1095,8 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub { String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) { final int callingUid = Binder.getCallingUid(); return new ParceledListSlice<>(snapshot().queryIntentServicesInternal( - intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/)); + intent, resolvedType, flags, userId, callingUid, Process.INVALID_PID, + /*includeInstantApps*/ false, /*resolveForStart*/ false)); } @Override @@ -1139,7 +1140,7 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub { @PackageManager.ResolveInfoFlagsBits long flags, int userId) { return mResolveIntentHelper.resolveIntentInternal(snapshot(), intent, resolvedType, flags, 0 /*privateResolveFlags*/, userId, false, - Binder.getCallingUid()); + Binder.getCallingUid(), Binder.getCallingPid()); } @Override @@ -1148,7 +1149,8 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub { @PackageManager.ResolveInfoFlagsBits long flags, int userId) { final int callingUid = Binder.getCallingUid(); return mResolveIntentHelper.resolveServiceInternal(snapshot(), intent, - resolvedType, flags, userId, callingUid); + resolvedType, flags, userId, callingUid, Process.INVALID_PID, + /*resolveForStart*/ false); } @Override diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS index 85aee8606bc2..c10dfcb5e9bf 100644 --- a/services/core/java/com/android/server/pm/OWNERS +++ b/services/core/java/com/android/server/pm/OWNERS @@ -34,6 +34,7 @@ per-file KeySetManagerService.java = cbrubaker@google.com, nnk@google.com per-file PackageKeySetData.java = cbrubaker@google.com, nnk@google.com per-file PackageSignatures.java = cbrubaker@google.com, nnk@google.com per-file SELinuxMMAC* = alanstokes@google.com, cbrubaker@google.com, jeffv@google.com +per-file SaferIntentUtils.java = topjohnwu@google.com # shortcuts per-file LauncherAppsService.java = omakoto@google.com, yamasani@google.com, sunnygoyal@google.com, mett@google.com, pinyaoting@google.com diff --git a/services/core/java/com/android/server/pm/PackageHandler.java b/services/core/java/com/android/server/pm/PackageHandler.java index 68f6ca1c019f..0a0882d80cc1 100644 --- a/services/core/java/com/android/server/pm/PackageHandler.java +++ b/services/core/java/com/android/server/pm/PackageHandler.java @@ -123,19 +123,10 @@ final class PackageHandler extends Handler { } } break; case WRITE_SETTINGS: { - if (!mPm.tryWriteSettings(/*sync=*/false)) { - // Failed to write. - this.removeMessages(WRITE_SETTINGS); - mPm.scheduleWriteSettings(); - } + mPm.writeSettings(/*sync=*/false); } break; case WRITE_PACKAGE_LIST: { - int userId = msg.arg1; - if (!mPm.tryWritePackageList(userId)) { - // Failed to write. - this.removeMessages(WRITE_PACKAGE_LIST); - mPm.scheduleWritePackageList(userId); - } + mPm.writePackageList(msg.arg1); } break; case CHECK_PENDING_VERIFICATION: { final int verificationId = msg.arg1; diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java index d2b60a489de3..ed568b823159 100644 --- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java +++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java @@ -327,11 +327,11 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal { @Override @Deprecated - public final List<ResolveInfo> queryIntentReceivers(Intent intent, - String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, - int filterCallingUid, int userId, boolean forSend) { + public final List<ResolveInfo> queryIntentReceivers( + Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, + int filterCallingUid, int callingPid, int userId, boolean forSend) { return getResolveIntentHelper().queryIntentReceiversInternal(snapshot(), intent, - resolvedType, flags, userId, filterCallingUid, forSend); + resolvedType, flags, userId, filterCallingUid, callingPid, forSend); } @Override @@ -341,7 +341,7 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal { int userId) { final String resolvedType = intent.resolveTypeIfNeeded(getContext().getContentResolver()); return snapshot().queryIntentServicesInternal(intent, resolvedType, flags, userId, - callingUid, false); + callingUid, Process.INVALID_PID, false, /*resolveForStart*/ false); } @Override @@ -472,32 +472,29 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal { public final ResolveInfo resolveIntent(Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId, - boolean resolveForStart, int filterCallingUid) { + boolean resolveForStart, int filterCallingUid, int callingPid) { return getResolveIntentHelper().resolveIntentInternal(snapshot(), intent, resolvedType, flags, privateResolveFlags, userId, resolveForStart, - filterCallingUid); + filterCallingUid, callingPid); } - /** - * @deprecated similar to {@link resolveIntent} but limits the matches to exported components. - */ @Override @Deprecated - public final ResolveInfo resolveIntentExported(Intent intent, String resolvedType, - @PackageManager.ResolveInfoFlagsBits long flags, - @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId, - boolean resolveForStart, int filterCallingUid, int callingPid) { - return getResolveIntentHelper().resolveIntentInternal(snapshot(), - intent, resolvedType, flags, privateResolveFlags, userId, resolveForStart, - filterCallingUid, true, callingPid); + public final ResolveInfo resolveService(Intent intent, String resolvedType, + @PackageManager.ResolveInfoFlagsBits long flags, int userId, int callingUid) { + return getResolveIntentHelper().resolveServiceInternal(snapshot(), intent, + resolvedType, flags, userId, callingUid, Process.INVALID_PID, + /*resolveForStart*/ false); } @Override @Deprecated - public final ResolveInfo resolveService(Intent intent, String resolvedType, - @PackageManager.ResolveInfoFlagsBits long flags, int userId, int callingUid) { + public final ResolveInfo resolveService( + Intent intent, String resolvedType, + @PackageManager.ResolveInfoFlagsBits long flags, int userId, + int callingUid, int callingPid) { return getResolveIntentHelper().resolveServiceInternal(snapshot(), intent, - resolvedType, flags, userId, callingUid); + resolvedType, flags, userId, callingUid, callingPid, /*resolveForStart*/ true); } @Override diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 0925271ab5a3..ca84d68cd9bb 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -485,9 +485,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService */ static final long WATCHDOG_TIMEOUT = 1000*60*10; // ten minutes - // How long to wait for Lock in async writeSettings and writePackageList. - private static final long WRITE_LOCK_TIMEOUT_MS = 1000 * 10; // 10 seconds - /** * Default IncFs timeouts. Maximum values in IncFs is 1hr. * @@ -1576,7 +1573,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService } } - void scheduleWritePackageList(int userId) { + void scheduleWritePackageListLocked(int userId) { invalidatePackageInfoCache(); if (!mHandler.hasMessages(WRITE_PACKAGE_LIST)) { Message msg = mHandler.obtainMessage(WRITE_PACKAGE_LIST); @@ -1628,42 +1625,22 @@ public class PackageManagerService implements PackageSender, TestUtilityService mSettings.writePackageRestrictions(dirtyUsers); } - private boolean tryUnderLock(boolean sync, long timeoutMs, Runnable runnable) { - try { - PackageManagerTracedLock.RawLock lock = mLock.getRawLock(); - if (sync) { - lock.lock(); - } else if (!lock.tryLock(timeoutMs, TimeUnit.MILLISECONDS)) { - return false; - } - try { - runnable.run(); - return true; - } finally { - lock.unlock(); - } - } catch (InterruptedException e) { - Slog.e(TAG, "Failed to obtain mLock", e); - } - return false; - } - - boolean tryWriteSettings(boolean sync) { - return tryUnderLock(sync, WRITE_LOCK_TIMEOUT_MS, () -> { + void writeSettings(boolean sync) { + synchronized (mLock) { mHandler.removeMessages(WRITE_SETTINGS); mBackgroundHandler.removeMessages(WRITE_DIRTY_PACKAGE_RESTRICTIONS); writeSettingsLPrTEMP(sync); synchronized (mDirtyUsers) { mDirtyUsers.clear(); } - }); + } } - boolean tryWritePackageList(int userId) { - return tryUnderLock(/*sync=*/false, WRITE_LOCK_TIMEOUT_MS, () -> { + void writePackageList(int userId) { + synchronized (mLock) { mHandler.removeMessages(WRITE_PACKAGE_LIST); mSettings.writePackageListLPr(userId); - }); + } } private static final Handler.Callback BACKGROUND_HANDLER_CALLBACK = new Handler.Callback() { @@ -2140,8 +2117,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService mPreferredActivityHelper = new PreferredActivityHelper(this, mBroadcastHelper); mResolveIntentHelper = new ResolveIntentHelper(mContext, mPreferredActivityHelper, injector.getCompatibility(), mUserManager, mDomainVerificationManager, - mUserNeedsBadging, () -> mResolveInfo, () -> mInstantAppInstallerActivity, - injector.getBackgroundHandler()); + mUserNeedsBadging, () -> mResolveInfo, () -> mInstantAppInstallerActivity); mDexOptHelper = new DexOptHelper(this); mSuspendPackageHelper = new SuspendPackageHelper(this, mInjector, mBroadcastHelper, mProtectedPackages); @@ -2696,7 +2672,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService final ResolveInfo resolveInfo = mResolveIntentHelper.resolveIntentInternal(computer, intent, null, MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, - 0 /*privateResolveFlags*/, UserHandle.USER_SYSTEM, false, Binder.getCallingUid()); + 0 /*privateResolveFlags*/, UserHandle.USER_SYSTEM, false, + Binder.getCallingUid(), Binder.getCallingPid()); if (resolveInfo == null || mResolveActivity.name.equals(resolveInfo.getComponentInfo().name)) { throw new RuntimeException("There must be exactly one uninstaller; found " @@ -2811,7 +2788,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService | (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0); final Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE); List<ResolveInfo> resolvers = snapshot.queryIntentServicesInternal(resolverIntent, null, - resolveFlags, UserHandle.USER_SYSTEM, callingUid, false /*includeInstantApps*/); + resolveFlags, UserHandle.USER_SYSTEM, callingUid, Process.INVALID_PID, + /*includeInstantApps*/ false, /*resolveForStart*/ false); final int N = resolvers.size(); if (N == 0) { if (DEBUG_INSTANT) { @@ -3067,9 +3045,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService if (mHandler.hasMessages(WRITE_SETTINGS) || mBackgroundHandler.hasMessages(WRITE_DIRTY_PACKAGE_RESTRICTIONS) || mHandler.hasMessages(WRITE_PACKAGE_LIST)) { - while (!tryWriteSettings(/*sync=*/true)) { - Slog.wtf(TAG, "Failed to write settings on shutdown"); - } + writeSettings(/*sync=*/true); } } } @@ -3669,7 +3645,9 @@ public class PackageManagerService implements PackageSender, TestUtilityService MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, UserHandle.USER_SYSTEM, /* callingUid= */ Process.myUid(), - /* includeInstantApps= */ false); + Process.INVALID_PID, + /* includeInstantApps= */ false, + /* resolveForStart */ false); if (matches.size() == 1) { return matches.get(0).getComponentInfo().packageName; } else { @@ -4429,7 +4407,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService } synchronized (mLock) { scheduleWritePackageRestrictions(userId); - scheduleWritePackageList(userId); + scheduleWritePackageListLocked(userId); mAppsFilter.onUserCreated(snapshotComputer(), userId); } } diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 6700f00a8856..ff8abf879487 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -26,14 +26,11 @@ import static android.system.OsConstants.O_RDWR; import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME; import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME; -import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH; -import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NULL_ACTION_MATCH; import static com.android.server.LocalManagerRegistry.ManagerNotFoundException; import static com.android.server.pm.PackageInstallerSession.APP_METADATA_FILE_ACCESS_MODE; import static com.android.server.pm.PackageInstallerSession.getAppMetadataSizeLimit; import static com.android.server.pm.PackageManagerService.COMPRESSED_EXTENSION; import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION; -import static com.android.server.pm.PackageManagerService.DEBUG_INTENT_MATCHING; import static com.android.server.pm.PackageManagerService.DEBUG_PREFERRED; import static com.android.server.pm.PackageManagerService.DEFAULT_FILE_ACCESS_MODE; import static com.android.server.pm.PackageManagerService.DEFAULT_NATIVE_LIBRARY_FILE_ACCESS_MODE; @@ -48,23 +45,15 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; -import android.app.ActivityManager; -import android.compat.annotation.ChangeId; -import android.compat.annotation.Disabled; -import android.compat.annotation.Overridable; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; -import android.content.pm.ComponentInfo; import android.content.pm.PackageInfoLite; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.PackageManager.Property; import android.content.pm.PackagePartitions; import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; import android.content.pm.Signature; import android.content.pm.SigningDetails; import android.content.pm.parsing.ApkLiteParseUtils; @@ -83,7 +72,6 @@ import android.os.FileUtils; import android.os.Process; import android.os.SELinux; import android.os.SystemProperties; -import android.os.UserHandle; import android.os.incremental.IncrementalManager; import android.os.incremental.IncrementalStorage; import android.os.incremental.V4Signature; @@ -99,29 +87,21 @@ import android.util.AtomicFile; import android.util.Base64; import android.util.DisplayMetrics; import android.util.Log; -import android.util.LogPrinter; -import android.util.Printer; import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.internal.content.InstallLocationUtils; import com.android.internal.content.NativeLibraryHelper; -import com.android.internal.pm.pkg.component.ParsedMainComponent; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastPrintWriter; import com.android.internal.util.HexDump; import com.android.server.EventLogTags; -import com.android.server.IntentResolver; import com.android.server.LocalManagerRegistry; import com.android.server.Watchdog; -import com.android.server.am.ActivityManagerUtils; -import com.android.server.compat.PlatformCompat; import com.android.server.pm.dex.PackageDexUsage; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.AndroidPackageSplit; import com.android.server.pm.pkg.PackageStateInternal; -import com.android.server.pm.resolution.ComponentResolverApi; -import com.android.server.pm.snapshot.PackageDataSnapshot; import com.android.server.pm.verify.domain.DomainVerificationManagerInternal; import dalvik.system.VMRuntime; @@ -173,11 +153,6 @@ public class PackageManagerServiceUtils { public static final Predicate<PackageStateInternal> REMOVE_IF_NULL_PKG = pkgSetting -> pkgSetting.getPkg() == null; - // This is a horrible hack to workaround b/240373119, specifically for fixing the T branch. - // A proper fix should be implemented in master instead. - public static final ThreadLocal<Boolean> DISABLE_ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS = - ThreadLocal.withInitial(() -> false); - /** * Type used with {@link #canJoinSharedUserId(String, SigningDetails, SharedUserSetting, int)} * when the package attempting to join the sharedUserId is a new install. @@ -202,22 +177,6 @@ public class PackageManagerServiceUtils { public @interface SharedUserIdJoinType {} /** - * Intents sent from apps targeting Android V and above will stop resolving to components with - * non matching intent filters, even when explicitly setting a component name, unless the - * target components are in the same app as the calling app. - * - * When an app registers an exported component in its manifest and adds an <intent-filter>, - * the component can be started by any intent - even those that do not match the intent filter. - * This has proven to be something that many developers find counterintuitive. - * Without checking the intent when the component is started, in some circumstances this can - * allow 3P apps to trigger internal-only functionality. - */ - @Overridable - @ChangeId - @Disabled - private static final long ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS = 161252188; - - /** * The initial enabled state of the cache before other checks are done. */ private static final boolean DEFAULT_PACKAGE_PARSER_CACHE_ENABLED = true; @@ -1204,166 +1163,6 @@ public class PackageManagerServiceUtils { return (ps.getFlags() & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; } - private static ParsedMainComponent componentInfoToComponent( - ComponentInfo info, ComponentResolverApi resolver, boolean isReceiver) { - if (info instanceof ActivityInfo) { - if (isReceiver) { - return resolver.getReceiver(info.getComponentName()); - } else { - return resolver.getActivity(info.getComponentName()); - } - } else if (info instanceof ServiceInfo) { - return resolver.getService(info.getComponentName()); - } else { - // This shall never happen - throw new IllegalArgumentException("Unsupported component type"); - } - } - - /** - * Under the correct conditions, remove components if the intent has null action. - * - * `compat` and `snapshot` may be null when this method is called in ActivityManagerService - * CTS tests. The code in this method will properly avoid control flows using these arguments. - */ - public static void applyNullActionBlocking( - @Nullable PlatformCompat compat, @Nullable PackageDataSnapshot snapshot, - List componentList, boolean isReceiver, Intent intent, int filterCallingUid) { - if (ActivityManager.canAccessUnexportedComponents(filterCallingUid)) return; - - final Computer computer = (Computer) snapshot; - ComponentResolverApi resolver = null; - - final boolean enforce = android.security.Flags.blockNullActionIntents() - && (compat == null || compat.isChangeEnabledByUidInternal( - IntentFilter.BLOCK_NULL_ACTION_INTENTS, filterCallingUid)); - - for (int i = componentList.size() - 1; i >= 0; --i) { - boolean match = true; - - Object c = componentList.get(i); - if (c instanceof ResolveInfo resolveInfo) { - if (computer == null) { - // PackageManagerService is not started - return; - } - if (resolver == null) { - resolver = computer.getComponentResolver(); - } - final ParsedMainComponent comp = componentInfoToComponent( - resolveInfo.getComponentInfo(), resolver, isReceiver); - if (comp != null && !comp.getIntents().isEmpty() && intent.getAction() == null) { - match = false; - } - } else if (c instanceof IntentFilter) { - if (intent.getAction() == null) { - match = false; - } - } - - if (!match) { - ActivityManagerUtils.logUnsafeIntentEvent( - UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NULL_ACTION_MATCH, - filterCallingUid, intent, null, enforce); - if (enforce) { - Slog.w(TAG, "Blocking intent with null action: " + intent); - componentList.remove(i); - } - } - } - } - - public static void applyEnforceIntentFilterMatching( - PlatformCompat compat, PackageDataSnapshot snapshot, - List<ResolveInfo> resolveInfos, boolean isReceiver, - Intent intent, String resolvedType, int filterCallingUid) { - if (DISABLE_ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS.get()) return; - - // Do not enforce filter matching when the caller is system or root - if (ActivityManager.canAccessUnexportedComponents(filterCallingUid)) return; - - final Computer computer = (Computer) snapshot; - final ComponentResolverApi resolver = computer.getComponentResolver(); - - final Printer logPrinter = DEBUG_INTENT_MATCHING - ? new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM) - : null; - - final boolean enforceMatch = android.security.Flags.enforceIntentFilterMatch() - && compat.isChangeEnabledByUidInternal( - ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS, filterCallingUid); - final boolean blockNullAction = android.security.Flags.blockNullActionIntents() - && compat.isChangeEnabledByUidInternal( - IntentFilter.BLOCK_NULL_ACTION_INTENTS, filterCallingUid); - - for (int i = resolveInfos.size() - 1; i >= 0; --i) { - final ComponentInfo info = resolveInfos.get(i).getComponentInfo(); - - // Skip filter matching when the caller is targeting the same app - if (UserHandle.isSameApp(filterCallingUid, info.applicationInfo.uid)) { - continue; - } - - final ParsedMainComponent comp = componentInfoToComponent(info, resolver, isReceiver); - - if (comp == null || comp.getIntents().isEmpty()) { - continue; - } - - Boolean match = null; - - if (intent.getAction() == null) { - ActivityManagerUtils.logUnsafeIntentEvent( - UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NULL_ACTION_MATCH, - filterCallingUid, intent, resolvedType, enforceMatch && blockNullAction); - if (blockNullAction) { - // Skip intent filter matching if blocking null action - match = false; - } - } - - if (match == null) { - // Check if any intent filter matches - for (int j = 0, size = comp.getIntents().size(); j < size; ++j) { - IntentFilter intentFilter = comp.getIntents().get(j).getIntentFilter(); - if (IntentResolver.intentMatchesFilter(intentFilter, intent, resolvedType)) { - match = true; - break; - } - } - } - - // At this point, the value `match` has the following states: - // null : Intent does not match any intent filter - // false: Null action intent detected AND blockNullAction == true - // true : The intent matches at least one intent filter - - if (match == null) { - ActivityManagerUtils.logUnsafeIntentEvent( - UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH, - filterCallingUid, intent, resolvedType, enforceMatch); - match = false; - } - - if (!match) { - // All non-matching intents has to be marked accordingly - if (android.security.Flags.enforceIntentFilterMatch()) { - intent.addExtendedFlags(Intent.EXTENDED_FLAG_FILTER_MISMATCH); - } - if (enforceMatch) { - Slog.w(TAG, "Intent does not match component's intent filter: " + intent); - Slog.w(TAG, "Access blocked: " + comp.getComponentName()); - if (DEBUG_INTENT_MATCHING) { - Slog.v(TAG, "Component intent filters:"); - comp.getIntents().forEach(f -> f.getIntentFilter().dump(logPrinter, " ")); - Slog.v(TAG, "-----------------------------"); - } - resolveInfos.remove(i); - } - } - } - } - /** * Do NOT use for intent resolution filtering. That should be done with * {@link DomainVerificationManagerInternal#filterToApprovedApp(Intent, List, int, Function)}. diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index c40563f2abeb..a8766163297b 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -330,6 +330,8 @@ class PackageManagerShellCommand extends ShellCommand { return runGetOemPermissions(); case "get-signature-permission-allowlist": return runGetSignaturePermissionAllowlist(); + case "get-shared-uid-allowlist": + return runGetSharedUidAllowlist(); case "trim-caches": return runTrimCaches(); case "create-user": @@ -2944,6 +2946,9 @@ class PackageManagerShellCommand extends ShellCommand { case "system-ext": allowlist = permissionAllowlist.getSystemExtSignatureAppAllowlist(); break; + case "apex": + allowlist = permissionAllowlist.getApexSignatureAppAllowlist(); + break; default: getErrPrintWriter().println("Error: unknown partition: " + partition); return 1; @@ -2970,6 +2975,20 @@ class PackageManagerShellCommand extends ShellCommand { return 0; } + private int runGetSharedUidAllowlist() { + final var allowlist = SystemConfig.getInstance().getPackageToSharedUidAllowList(); + final var pw = getOutPrintWriter(); + final var allowlistSize = allowlist.size(); + for (var allowlistIndex = 0; allowlistIndex < allowlistSize; allowlistIndex++) { + final var packageName = allowlist.keyAt(allowlistIndex); + final var sharedUserName = allowlist.valueAt(allowlistIndex); + pw.print(packageName); + pw.print(" "); + pw.println(sharedUserName); + } + return 0; + } + private int runTrimCaches() throws RemoteException { String size = getNextArg(); if (size == null) { @@ -4907,7 +4926,10 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(""); pw.println(" get-signature-permission-allowlist PARTITION"); pw.println(" Prints the signature permission allowlist for a partition."); - pw.println(" PARTITION is one of system, vendor, product and system-ext"); + pw.println(" PARTITION is one of system, vendor, product, system-ext and apex"); + pw.println(""); + pw.println(" get-shared-uid-allowlist"); + pw.println(" Prints the shared UID allowlist."); pw.println(""); pw.println(" trim-caches DESIRED_FREE_SPACE [internal|UUID]"); pw.println(" Trim cache files to reach the given free space."); diff --git a/services/core/java/com/android/server/pm/ResolveIntentHelper.java b/services/core/java/com/android/server/pm/ResolveIntentHelper.java index 309a4481e9de..69490a81fc86 100644 --- a/services/core/java/com/android/server/pm/ResolveIntentHelper.java +++ b/services/core/java/com/android/server/pm/ResolveIntentHelper.java @@ -18,7 +18,6 @@ package com.android.server.pm; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; -import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH; import static com.android.server.pm.PackageManagerService.DEBUG_INSTANT; import static com.android.server.pm.PackageManagerService.DEBUG_INTENT_MATCHING; import static com.android.server.pm.PackageManagerService.TAG; @@ -26,8 +25,6 @@ import static com.android.server.pm.PackageManagerService.TAG; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.ActivityManager; -import android.app.ActivityManagerInternal; -import android.app.IUnsafeIntentStrictModeCallback; import android.app.PendingIntent; import android.content.ComponentName; import android.content.ContentResolver; @@ -45,7 +42,6 @@ import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.os.Binder; import android.os.Bundle; -import android.os.Handler; import android.os.Process; import android.os.RemoteException; import android.os.Trace; @@ -56,9 +52,6 @@ import android.util.Slog; import com.android.internal.app.ResolverActivity; import com.android.internal.util.ArrayUtils; -import com.android.server.LocalServices; -import com.android.server.am.ActivityManagerService; -import com.android.server.am.ActivityManagerUtils; import com.android.server.compat.PlatformCompat; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageStateInternal; @@ -89,8 +82,6 @@ final class ResolveIntentHelper { private final Supplier<ResolveInfo> mResolveInfoSupplier; @NonNull private final Supplier<ActivityInfo> mInstantAppInstallerActivitySupplier; - @NonNull - private final Handler mHandler; ResolveIntentHelper(@NonNull Context context, @NonNull PreferredActivityHelper preferredActivityHelper, @@ -98,8 +89,7 @@ final class ResolveIntentHelper { @NonNull DomainVerificationManagerInternal domainVerificationManager, @NonNull UserNeedsBadgingCache userNeedsBadgingCache, @NonNull Supplier<ResolveInfo> resolveInfoSupplier, - @NonNull Supplier<ActivityInfo> instantAppInstallerActivitySupplier, - @NonNull Handler handler) { + @NonNull Supplier<ActivityInfo> instantAppInstallerActivitySupplier) { mContext = context; mPreferredActivityHelper = preferredActivityHelper; mPlatformCompat = platformCompat; @@ -108,47 +98,6 @@ final class ResolveIntentHelper { mUserNeedsBadging = userNeedsBadgingCache; mResolveInfoSupplier = resolveInfoSupplier; mInstantAppInstallerActivitySupplier = instantAppInstallerActivitySupplier; - mHandler = handler; - } - - private static void filterNonExportedComponents(Intent intent, int filterCallingUid, - int callingPid, List<ResolveInfo> query, PlatformCompat platformCompat, - String resolvedType, Computer computer, Handler handler) { - if (query == null - || intent.getPackage() != null - || intent.getComponent() != null - || ActivityManager.canAccessUnexportedComponents(filterCallingUid)) { - return; - } - AndroidPackage caller = computer.getPackage(filterCallingUid); - String callerPackage = caller == null ? "Not specified" : caller.getPackageName(); - ActivityManagerInternal activityManagerInternal = LocalServices - .getService(ActivityManagerInternal.class); - final IUnsafeIntentStrictModeCallback callback = activityManagerInternal - .getRegisteredStrictModeCallback(callingPid); - for (int i = query.size() - 1; i >= 0; i--) { - if (!query.get(i).getComponentInfo().exported) { - boolean hasToBeExportedToMatch = platformCompat.isChangeEnabledByUid( - ActivityManagerService.IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS, - filterCallingUid); - ActivityManagerUtils.logUnsafeIntentEvent( - UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH, - filterCallingUid, intent, resolvedType, hasToBeExportedToMatch); - if (callback != null) { - handler.post(() -> { - try { - callback.onImplicitIntentMatchedInternalComponent(intent.cloneFilter()); - } catch (RemoteException e) { - activityManagerInternal.unregisterStrictModeCallback(callingPid); - } - }); - } - if (!hasToBeExportedToMatch) { - return; - } - query.remove(i); - } - } } /** @@ -159,22 +108,7 @@ final class ResolveIntentHelper { public ResolveInfo resolveIntentInternal(Computer computer, Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId, - boolean resolveForStart, int filterCallingUid) { - return resolveIntentInternal(computer, intent, resolvedType, flags, - privateResolveFlags, userId, resolveForStart, filterCallingUid, false, 0); - } - - /** - * Normally instant apps can only be resolved when they're visible to the caller. - * However, if {@code resolveForStart} is {@code true}, all instant apps are visible - * since we need to allow the system to start any installed application. - * Allows picking exported components only. - */ - public ResolveInfo resolveIntentInternal(Computer computer, Intent intent, String resolvedType, - @PackageManager.ResolveInfoFlagsBits long flags, - @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId, - boolean resolveForStart, int filterCallingUid, boolean exportedComponentsOnly, - int callingPid) { + boolean resolveForStart, int filterCallingUid, int callingPid) { try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent"); @@ -188,14 +122,15 @@ final class ResolveIntentHelper { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities"); final List<ResolveInfo> query = computer.queryIntentActivitiesInternal(intent, - resolvedType, flags, privateResolveFlags, filterCallingUid, userId, - resolveForStart, true /*allowDynamicSplits*/); - if (exportedComponentsOnly) { - filterNonExportedComponents(intent, filterCallingUid, callingPid, query, - mPlatformCompat, resolvedType, computer, mHandler); - } + resolvedType, flags, privateResolveFlags, filterCallingUid, callingPid, + userId, resolveForStart, /*allowDynamicSplits*/ true); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + var args = new SaferIntentUtils.IntentArgs(intent, resolvedType, + false /* isReceiver */, resolveForStart, filterCallingUid, callingPid); + args.platformCompat = mPlatformCompat; + SaferIntentUtils.filterNonExportedComponents(args, query); + final boolean queryMayBeFiltered = UserHandle.getAppId(filterCallingUid) >= Process.FIRST_APPLICATION_UID && !resolveForStart; @@ -331,6 +266,7 @@ final class ResolveIntentHelper { throws RemoteException { Objects.requireNonNull(packageName); final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); computer.enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, "get launch intent sender for package"); final int packageUid = computer.getPackageUid(callingPackage, 0 /* flags */, userId); @@ -346,17 +282,17 @@ final class ResolveIntentHelper { intentToResolve.setPackage(packageName); final ContentResolver contentResolver = mContext.getContentResolver(); String resolvedType = intentToResolve.resolveTypeIfNeeded(contentResolver); - List<ResolveInfo> ris = computer.queryIntentActivitiesInternal(intentToResolve, resolvedType, - 0 /* flags */, 0 /* privateResolveFlags */, callingUid, userId, - true /* resolveForStart */, false /* allowDynamicSplits */); + List<ResolveInfo> ris = computer.queryIntentActivitiesInternal(intentToResolve, + resolvedType, 0 /* flags */, 0 /* privateResolveFlags */, callingUid, callingPid, + userId, /* resolveForStart */ true, /* allowDynamicSplits */false); if (ris == null || ris.size() <= 0) { intentToResolve.removeCategory(Intent.CATEGORY_INFO); intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER); intentToResolve.setPackage(packageName); resolvedType = intentToResolve.resolveTypeIfNeeded(contentResolver); ris = computer.queryIntentActivitiesInternal(intentToResolve, resolvedType, - 0 /* flags */, 0 /* privateResolveFlags */, callingUid, userId, - true /* resolveForStart */, false /* allowDynamicSplits */); + 0 /* flags */, 0 /* privateResolveFlags */, callingUid, callingPid, + userId, /* resolveForStart */ true, /* allowDynamicSplits */false); } final Intent intent = new Intent(intentToResolve); @@ -390,16 +326,17 @@ final class ResolveIntentHelper { String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId, int queryingUid) { return queryIntentReceiversInternal(computer, intent, resolvedType, flags, userId, - queryingUid, false); + queryingUid, Process.INVALID_PID, false); } /** - * @see PackageManagerInternal#queryIntentReceivers(Intent, String, long, int, int, boolean) + * @see PackageManagerInternal#queryIntentReceivers */ @NonNull - public List<ResolveInfo> queryIntentReceiversInternal(Computer computer, Intent intent, - String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId, - int filterCallingUid, boolean forSend) { + public List<ResolveInfo> queryIntentReceiversInternal( + Computer computer, Intent intent, String resolvedType, + @PackageManager.ResolveInfoFlagsBits long flags, int userId, + int filterCallingUid, int callingPid, boolean forSend) { if (!mUserManager.exists(userId)) return Collections.emptyList(); // The identity used to filter the receiver components final int queryingUid = forSend ? Process.SYSTEM_UID : filterCallingUid; @@ -421,6 +358,12 @@ final class ResolveIntentHelper { } final ComponentResolverApi componentResolver = computer.getComponentResolver(); List<ResolveInfo> list = Collections.emptyList(); + + var args = new SaferIntentUtils.IntentArgs(intent, resolvedType, + true /* isReceiver */, forSend, filterCallingUid, callingPid); + args.platformCompat = mPlatformCompat; + args.snapshot = computer; + if (comp != null) { final ActivityInfo ai = computer.getReceiverInfo(comp, flags, userId); if (ai != null) { @@ -457,9 +400,7 @@ final class ResolveIntentHelper { ri.activityInfo = ai; list = new ArrayList<>(1); list.add(ri); - PackageManagerServiceUtils.applyEnforceIntentFilterMatching( - mPlatformCompat, computer, list, true, intent, - resolvedType, filterCallingUid); + SaferIntentUtils.enforceIntentFilterMatching(args, list); } } } else { @@ -479,15 +420,13 @@ final class ResolveIntentHelper { list = result; } } - PackageManagerServiceUtils.applyNullActionBlocking( - mPlatformCompat, computer, list, true, intent, filterCallingUid); + SaferIntentUtils.blockNullAction(args, list); } if (originalIntent != null) { // We also have to ensure all components match the original intent - PackageManagerServiceUtils.applyEnforceIntentFilterMatching( - mPlatformCompat, computer, - list, true, originalIntent, resolvedType, filterCallingUid); + args.intent = originalIntent; + SaferIntentUtils.enforceIntentFilterMatching(args, list); } return computer.applyPostResolutionFilter(list, instantAppPkgName, false, queryingUid, @@ -495,14 +434,16 @@ final class ResolveIntentHelper { } - public ResolveInfo resolveServiceInternal(@NonNull Computer computer, Intent intent, + public ResolveInfo resolveServiceInternal( + @NonNull Computer computer, Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId, - int callingUid) { + int callingUid, int callingPid, boolean resolveForStart) { if (!mUserManager.exists(userId)) return null; flags = computer.updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/, false /* isImplicitImageCaptureIntentAndNotSetByDpc */); List<ResolveInfo> query = computer.queryIntentServicesInternal( - intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/); + intent, resolvedType, flags, userId, callingUid, callingPid, + /*includeInstantApps*/ false, resolveForStart); if (query != null) { if (query.size() >= 1) { // If there is more than one service with the same priority, @@ -705,7 +646,8 @@ final class ResolveIntentHelper { if (comp == null) { ri = resolveIntentInternal(computer, sintent, specificTypes != null ? specificTypes[i] : null, flags, - 0 /*privateResolveFlags*/, userId, false, Binder.getCallingUid()); + 0 /*privateResolveFlags*/, userId, false, + Binder.getCallingUid(), Binder.getCallingPid()); if (ri == null) { continue; } diff --git a/services/core/java/com/android/server/pm/SaferIntentUtils.java b/services/core/java/com/android/server/pm/SaferIntentUtils.java new file mode 100644 index 000000000000..8175321ea293 --- /dev/null +++ b/services/core/java/com/android/server/pm/SaferIntentUtils.java @@ -0,0 +1,397 @@ +/* + * 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.server.pm; + +import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH; +import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH; +import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NULL_ACTION_MATCH; +import static com.android.server.pm.PackageManagerService.DEBUG_INTENT_MATCHING; +import static com.android.server.pm.PackageManagerService.TAG; + +import android.annotation.Nullable; +import android.app.ActivityManager; +import android.app.ActivityManagerInternal; +import android.compat.annotation.ChangeId; +import android.compat.annotation.Disabled; +import android.compat.annotation.EnabledAfter; +import android.compat.annotation.Overridable; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ActivityInfo; +import android.content.pm.ComponentInfo; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.os.Build; +import android.os.Process; +import android.os.UserHandle; +import android.security.Flags; +import android.util.Log; +import android.util.LogPrinter; +import android.util.Printer; +import android.util.Slog; + +import com.android.internal.pm.pkg.component.ParsedMainComponent; +import com.android.internal.util.FrameworkStatsLog; +import com.android.server.IntentResolver; +import com.android.server.LocalServices; +import com.android.server.am.BroadcastFilter; +import com.android.server.compat.PlatformCompat; +import com.android.server.pm.resolution.ComponentResolverApi; +import com.android.server.pm.snapshot.PackageDataSnapshot; + +import java.util.List; + +/** + * The way Safer Intent is implemented is to add several "hooks" into PMS's intent + * resolution process, and in some cases, AMS's runtime receiver resolution. Think of + * these methods as resolution "passes", where they post-process the resolved component list. + * <p> + * Here are the 4 main hooking entry points for each component type: + * <ul> + * <li>Activity: {@link ComputerEngine#queryIntentActivitiesInternal} or + * {@link ResolveIntentHelper#resolveIntentInternal}</li> + * <li>Service: {@link Computer#queryIntentServicesInternal}</li> + * <li>Static BroadcastReceivers: {@link ResolveIntentHelper#queryIntentReceiversInternal}</li> + * <li>Runtime BroadcastReceivers: + * {@link com.android.server.am.ActivityManagerService#broadcastIntentLockedTraced}</li> + * </ul> + */ +public class SaferIntentUtils { + + // This is a hack to workaround b/240373119; a proper fix should be implemented instead. + public static final ThreadLocal<Boolean> DISABLE_ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS = + ThreadLocal.withInitial(() -> false); + + /** + * Apps targeting Android U and above will need to export components in order to invoke them + * through implicit intents. + * <p> + * If a component is not exported and invoked, it will be removed from the list of receivers. + * This applies specifically to activities and broadcasts. + */ + @ChangeId + @Overridable + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) + private static final long IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS = 229362273; + + /** + * Intents sent from apps enabling this feature will stop resolving to components with + * non matching intent filters, even when explicitly setting a component name, unless the + * target components are in the same app as the calling app. + * <p> + * When an app registers an exported component in its manifest and adds <intent-filter>s, + * the component can be started by any intent - even those that do not match the intent filter. + * This has proven to be something that many developers find counterintuitive. + * Without checking the intent when the component is started, in some circumstances this can + * allow 3P apps to trigger internal-only functionality. + */ + @ChangeId + @Overridable + @Disabled + private static final long ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS = 161252188; + + private static ParsedMainComponent infoToComponent( + ComponentInfo info, ComponentResolverApi resolver, boolean isReceiver) { + if (info instanceof ActivityInfo) { + if (isReceiver) { + return resolver.getReceiver(info.getComponentName()); + } else { + return resolver.getActivity(info.getComponentName()); + } + } else if (info instanceof ServiceInfo) { + return resolver.getService(info.getComponentName()); + } else { + // This shall never happen + throw new IllegalArgumentException("Unsupported component type"); + } + } + + /** + * Helper method to report an unsafe intent event. + */ + public static void reportUnsafeIntentEvent( + int event, int callingUid, int callingPid, + Intent intent, String resolvedType, boolean blocked) { + String[] categories = intent.getCategories() == null ? new String[0] + : intent.getCategories().toArray(String[]::new); + String component = intent.getComponent() == null ? null + : intent.getComponent().flattenToString(); + FrameworkStatsLog.write(FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED, + event, + callingUid, + component, + intent.getPackage(), + intent.getAction(), + categories, + resolvedType, + intent.getScheme(), + blocked); + LocalServices.getService(ActivityManagerInternal.class) + .triggerUnsafeIntentStrictMode(callingPid, event, intent); + } + + /** + * All the relevant information about an intent resolution transaction. + */ + public static class IntentArgs { + + /* Several system_server components */ + + @Nullable + public PlatformCompat platformCompat; + @Nullable + public PackageDataSnapshot snapshot; + + /* Information about the intent itself */ + + public Intent intent; + public String resolvedType; + public boolean isReceiver; + + /* Information about the caller */ + + // Whether this intent resolution transaction is actually for starting a component and + // not only for querying matching components. + // This information is required because we only want to log and trigger strict mode + // violations on unsafe intent events when the caller actually wants to start something. + public boolean resolveForStart; + public int callingUid; + // When resolveForStart is false, callingPid does not matter as this is only used + // to lookup the strict mode violation callback. + public int callingPid; + + public IntentArgs( + Intent intent, String resolvedType, boolean isReceiver, + boolean resolveForStart, int callingUid, int callingPid) { + this.isReceiver = isReceiver; + this.intent = intent; + this.resolvedType = resolvedType; + this.resolveForStart = resolveForStart; + this.callingUid = callingUid; + this.callingPid = resolveForStart ? callingPid : Process.INVALID_PID; + } + + boolean isChangeEnabled(long changeId) { + return platformCompat == null || platformCompat.isChangeEnabledByUidInternal( + changeId, callingUid); + } + + void reportEvent(int event, boolean blocked) { + if (resolveForStart) { + SaferIntentUtils.reportUnsafeIntentEvent( + event, callingUid, callingPid, intent, resolvedType, blocked); + } + } + } + + /** + * Remove components if the intent has null action. + * <p> + * Because blocking null action applies to all resolution cases, it has to be hooked + * in all 4 locations. Note, for component intent resolution in Activity, Service, + * and static BroadcastReceivers, null action blocking is actually handled within + * {@link #enforceIntentFilterMatching}; we only need to handle it in this method when + * the intent does not specify an explicit component name. + * <p> + * `compat` and `snapshot` may be null when this method is called in ActivityManagerService + * CTS tests. The code in this method shall properly avoid control flows using these arguments. + */ + public static void blockNullAction(IntentArgs args, List componentList) { + if (ActivityManager.canAccessUnexportedComponents(args.callingUid)) return; + + final Computer computer = (Computer) args.snapshot; + ComponentResolverApi resolver = null; + + final boolean enforce = Flags.blockNullActionIntents() + && args.isChangeEnabled(IntentFilter.BLOCK_NULL_ACTION_INTENTS); + + for (int i = componentList.size() - 1; i >= 0; --i) { + boolean match = true; + + Object c = componentList.get(i); + if (c instanceof ResolveInfo resolveInfo) { + if (computer == null) { + // PackageManagerService is not started + return; + } + if (resolver == null) { + resolver = computer.getComponentResolver(); + } + final ParsedMainComponent comp = infoToComponent( + resolveInfo.getComponentInfo(), resolver, args.isReceiver); + if (!comp.getIntents().isEmpty() && args.intent.getAction() == null) { + match = false; + } + } else if (c instanceof IntentFilter) { + if (args.intent.getAction() == null) { + match = false; + } + } + + if (!match) { + args.reportEvent( + UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NULL_ACTION_MATCH, enforce); + if (enforce) { + Slog.w(TAG, "Blocking intent with null action: " + args.intent); + componentList.remove(i); + } + } + } + } + + /** + * Remove ResolveInfos that does not match the provided component intent. + * <p> + * Component intents cannot refer to a runtime registered BroadcastReceiver, so we only + * need to hook into the rest of the 3 entry points. Please note, this method also + * handles null action blocking for all component intents; do not go through an additional + * {@link #blockNullAction} pass! + */ + public static void enforceIntentFilterMatching( + IntentArgs args, List<ResolveInfo> resolveInfos) { + if (DISABLE_ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS.get()) return; + + // Do not enforce filter matching when the caller is system or root + if (ActivityManager.canAccessUnexportedComponents(args.callingUid)) return; + + final Computer computer = (Computer) args.snapshot; + final ComponentResolverApi resolver = computer.getComponentResolver(); + + final Printer logPrinter = DEBUG_INTENT_MATCHING + ? new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM) + : null; + + final boolean enforceMatch = Flags.enforceIntentFilterMatch() + && args.isChangeEnabled(ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS); + final boolean blockNullAction = Flags.blockNullActionIntents() + && args.isChangeEnabled(IntentFilter.BLOCK_NULL_ACTION_INTENTS); + + for (int i = resolveInfos.size() - 1; i >= 0; --i) { + final ComponentInfo info = resolveInfos.get(i).getComponentInfo(); + + // Skip filter matching when the caller is targeting the same app + if (UserHandle.isSameApp(args.callingUid, info.applicationInfo.uid)) { + continue; + } + + final ParsedMainComponent comp = infoToComponent(info, resolver, args.isReceiver); + + if (comp == null || comp.getIntents().isEmpty()) { + continue; + } + + Boolean match = null; + + if (args.intent.getAction() == null) { + args.reportEvent( + UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NULL_ACTION_MATCH, + enforceMatch && blockNullAction); + if (blockNullAction) { + // Skip intent filter matching if blocking null action + match = false; + } + } + + if (match == null) { + // Check if any intent filter matches + for (int j = 0, size = comp.getIntents().size(); j < size; ++j) { + IntentFilter intentFilter = comp.getIntents().get(j).getIntentFilter(); + if (IntentResolver.intentMatchesFilter( + intentFilter, args.intent, args.resolvedType)) { + match = true; + break; + } + } + } + + // At this point, the value `match` has the following states: + // null : Intent does not match any intent filter + // false: Null action intent detected AND blockNullAction == true + // true : The intent matches at least one intent filter + + if (match == null) { + args.reportEvent( + UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH, + enforceMatch); + match = false; + } + + if (!match) { + // All non-matching intents has to be marked accordingly + if (Flags.enforceIntentFilterMatch()) { + args.intent.addExtendedFlags(Intent.EXTENDED_FLAG_FILTER_MISMATCH); + } + if (enforceMatch) { + Slog.w(TAG, "Intent does not match component's intent filter: " + args.intent); + Slog.w(TAG, "Access blocked: " + comp.getComponentName()); + if (DEBUG_INTENT_MATCHING) { + Slog.v(TAG, "Component intent filters:"); + comp.getIntents().forEach(f -> f.getIntentFilter().dump(logPrinter, " ")); + Slog.v(TAG, "-----------------------------"); + } + resolveInfos.remove(i); + } + } + } + } + + /** + * Filter non-exported components from the componentList if intent is implicit. + * <p> + * Implicit intents cannot be used to start Services since API 21+. + * Implicit broadcasts cannot be delivered to static BroadcastReceivers since API 25+. + * So we only need to hook into Activity and runtime BroadcastReceiver intent resolution. + */ + public static void filterNonExportedComponents(IntentArgs args, List componentList) { + if (componentList == null + || args.intent.getPackage() != null + || args.intent.getComponent() != null + || ActivityManager.canAccessUnexportedComponents(args.callingUid)) { + return; + } + + final boolean enforce = + args.isChangeEnabled(IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS); + boolean violated = false; + + for (int i = componentList.size() - 1; i >= 0; i--) { + Object c = componentList.get(i); + if (c instanceof ResolveInfo resolveInfo) { + if (resolveInfo.getComponentInfo().exported) { + continue; + } + } else if (c instanceof BroadcastFilter broadcastFilter) { + if (broadcastFilter.exported) { + continue; + } + } else { + continue; + } + violated = true; + if (!enforce) { + break; + } + componentList.remove(i); + } + + if (violated) { + args.reportEvent( + UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH, + enforce); + } + } +} diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 8d6d774a9959..39565526f33e 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -934,6 +934,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile ret.setTargetSdkVersion(p.getTargetSdkVersion()); ret.setRestrictUpdateHash(p.getRestrictUpdateHash()); ret.setScannedAsStoppedSystemApp(p.isScannedAsStoppedSystemApp()); + ret.setInstallSource(p.getInstallSource()); } mDisabledSysPackages.remove(name); return ret; diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 29acbcda7c4f..db94d0e8b0ba 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -281,6 +281,10 @@ public class UserManagerService extends IUserManager.Stub { private static final String RESTRICTIONS_FILE_PREFIX = "res_"; private static final String XML_SUFFIX = ".xml"; + private static final String CUSTOM_BIOMETRIC_PROMPT_LOGO_RES_ID_KEY = "custom_logo_res_id"; + private static final String CUSTOM_BIOMETRIC_PROMPT_LOGO_DESCRIPTION_KEY = + "custom_logo_description"; + private static final int ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION = UserInfo.FLAG_MANAGED_PROFILE | UserInfo.FLAG_PROFILE @@ -1970,6 +1974,14 @@ public class UserManagerService extends IUserManager.Stub { // intentSender unlockIntent.putExtra(Intent.EXTRA_INTENT, pendingIntent.getIntentSender()); unlockIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + + if (Flags.enablePrivateSpaceFeatures() && Flags.usePrivateSpaceIconInBiometricPrompt() + && getUserInfo(userId).isPrivateProfile()) { + unlockIntent.putExtra(CUSTOM_BIOMETRIC_PROMPT_LOGO_RES_ID_KEY, + com.android.internal.R.drawable.stat_sys_private_profile_status); + unlockIntent.putExtra(CUSTOM_BIOMETRIC_PROMPT_LOGO_DESCRIPTION_KEY, + mContext.getString(R.string.private_space_biometric_prompt_title)); + } mContext.startActivityAsUser( unlockIntent, UserHandle.of(getProfileParentIdUnchecked(userId))); } diff --git a/services/core/java/com/android/server/pm/permission/PermissionAllowlist.java b/services/core/java/com/android/server/pm/permission/PermissionAllowlist.java index d138606369b9..6b99cbb2cba9 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionAllowlist.java +++ b/services/core/java/com/android/server/pm/permission/PermissionAllowlist.java @@ -55,6 +55,9 @@ public final class PermissionAllowlist { @NonNull private final ArrayMap<String, ArrayMap<String, Boolean>> mSystemExtSignatureAppAllowlist = new ArrayMap<>(); + @NonNull + private final ArrayMap<String, ArrayMap<String, Boolean>> mApexSignatureAppAllowlist = + new ArrayMap<>(); @NonNull public ArrayMap<String, ArrayMap<String, Boolean>> getOemAppAllowlist() { @@ -107,6 +110,11 @@ public final class PermissionAllowlist { return mSystemExtSignatureAppAllowlist; } + @NonNull + public ArrayMap<String, ArrayMap<String, Boolean>> getApexSignatureAppAllowlist() { + return mApexSignatureAppAllowlist; + } + @Nullable public Boolean getOemAppAllowlistState(@NonNull String packageName, @NonNull String permissionName) { @@ -211,4 +219,14 @@ public final class PermissionAllowlist { } return permissions.get(permissionName); } + + @Nullable + public Boolean getApexSignatureAppAllowlistState(@NonNull String packageName, + @NonNull String permissionName) { + ArrayMap<String, Boolean> permissions = mApexSignatureAppAllowlist.get(packageName); + if (permissions == null) { + return null; + } + return permissions.get(permissionName); + } } diff --git a/services/core/java/com/android/server/policy/TalkbackShortcutController.java b/services/core/java/com/android/server/policy/TalkbackShortcutController.java index b05a421e6e87..e544ae64521c 100644 --- a/services/core/java/com/android/server/policy/TalkbackShortcutController.java +++ b/services/core/java/com/android/server/policy/TalkbackShortcutController.java @@ -117,6 +117,7 @@ class TalkbackShortcutController { } private boolean isTalkback(ServiceInfo info) { - return TALKBACK_LABEL.equals(info.loadLabel(mPackageManager).toString()); + return TALKBACK_LABEL.equals(info.loadLabel(mPackageManager).toString()) + && (info.applicationInfo.isSystemApp() || info.applicationInfo.isUpdatedSystemApp()); } } diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java index 53607880ff48..0052d4f28b93 100644 --- a/services/core/java/com/android/server/power/ThermalManagerService.java +++ b/services/core/java/com/android/server/power/ThermalManagerService.java @@ -1709,7 +1709,7 @@ public class ThermalManagerService extends SystemService { ArrayList<Sample> samples = mSamples.computeIfAbsent(temperature.getName(), k -> new ArrayList<>(RING_BUFFER_SIZE)); if (samples.size() == RING_BUFFER_SIZE) { - samples.remove(0); + samples.removeFirst(); } samples.add(new Sample(now, temperature.getValue())); } @@ -1806,7 +1806,7 @@ public class ThermalManagerService extends SystemService { continue; } - float currentTemperature = samples.get(0).temperature; + float currentTemperature = samples.getLast().temperature; if (samples.size() < MINIMUM_SAMPLE_COUNT) { // Don't try to forecast, just use the latest one we have diff --git a/services/core/java/com/android/server/power/stats/AudioPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/AudioPowerStatsProcessor.java new file mode 100644 index 000000000000..a48f162321dd --- /dev/null +++ b/services/core/java/com/android/server/power/stats/AudioPowerStatsProcessor.java @@ -0,0 +1,37 @@ +/* + * 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.server.power.stats; + +import android.os.BatteryConsumer; +import android.os.BatteryStats; + +import com.android.internal.os.PowerProfile; + +public class AudioPowerStatsProcessor extends BinaryStatePowerStatsProcessor { + public AudioPowerStatsProcessor(PowerProfile powerProfile, + PowerStatsUidResolver uidResolver) { + super(BatteryConsumer.POWER_COMPONENT_AUDIO, uidResolver, + powerProfile.getAveragePower(PowerProfile.POWER_AUDIO)); + } + + @Override + protected @BinaryState int getBinaryState(BatteryStats.HistoryItem item) { + return (item.states & BatteryStats.HistoryItem.STATE_AUDIO_ON_FLAG) != 0 + ? STATE_ON + : STATE_OFF; + } +} diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java index efaa7a8598c0..5bae5a42d484 100644 --- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java +++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java @@ -6490,12 +6490,14 @@ public class BatteryStatsImpl extends BatteryStats { uid = mapUid(uid); if (mAudioOnNesting == 0) { mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_AUDIO_ON_FLAG); + HistoryItem.STATE_AUDIO_ON_FLAG, uid, "audio"); mAudioOnTimer.startRunningLocked(elapsedRealtimeMs); } mAudioOnNesting++; - getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) - .noteAudioTurnedOnLocked(elapsedRealtimeMs); + if (!mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_AUDIO)) { + getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) + .noteAudioTurnedOnLocked(elapsedRealtimeMs); + } } @GuardedBy("this") @@ -6506,11 +6508,13 @@ public class BatteryStatsImpl extends BatteryStats { uid = mapUid(uid); if (--mAudioOnNesting == 0) { mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_AUDIO_ON_FLAG); + HistoryItem.STATE_AUDIO_ON_FLAG, uid, "audio"); mAudioOnTimer.stopRunningLocked(elapsedRealtimeMs); } - getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) - .noteAudioTurnedOffLocked(elapsedRealtimeMs); + if (!mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_AUDIO)) { + getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) + .noteAudioTurnedOffLocked(elapsedRealtimeMs); + } } @GuardedBy("this") @@ -6518,12 +6522,14 @@ public class BatteryStatsImpl extends BatteryStats { uid = mapUid(uid); if (mVideoOnNesting == 0) { mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_VIDEO_ON_FLAG); + HistoryItem.STATE2_VIDEO_ON_FLAG, uid, "video"); mVideoOnTimer.startRunningLocked(elapsedRealtimeMs); } mVideoOnNesting++; - getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) - .noteVideoTurnedOnLocked(elapsedRealtimeMs); + if (!mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_VIDEO)) { + getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) + .noteVideoTurnedOnLocked(elapsedRealtimeMs); + } } @GuardedBy("this") @@ -6534,11 +6540,13 @@ public class BatteryStatsImpl extends BatteryStats { uid = mapUid(uid); if (--mVideoOnNesting == 0) { mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_VIDEO_ON_FLAG); + HistoryItem.STATE2_VIDEO_ON_FLAG, uid, "video"); mVideoOnTimer.stopRunningLocked(elapsedRealtimeMs); } - getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) - .noteVideoTurnedOffLocked(elapsedRealtimeMs); + if (!mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_VIDEO)) { + getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) + .noteVideoTurnedOffLocked(elapsedRealtimeMs); + } } @GuardedBy("this") @@ -6613,11 +6621,13 @@ public class BatteryStatsImpl extends BatteryStats { uid = mapUid(uid); if (mFlashlightOnNesting++ == 0) { mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_FLASHLIGHT_FLAG); + HistoryItem.STATE2_FLASHLIGHT_FLAG, uid, "flashlight"); mFlashlightOnTimer.startRunningLocked(elapsedRealtimeMs); } - getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) - .noteFlashlightTurnedOnLocked(elapsedRealtimeMs); + if (!mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) { + getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) + .noteFlashlightTurnedOnLocked(elapsedRealtimeMs); + } } @GuardedBy("this") @@ -6628,11 +6638,13 @@ public class BatteryStatsImpl extends BatteryStats { uid = mapUid(uid); if (--mFlashlightOnNesting == 0) { mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_FLASHLIGHT_FLAG); + HistoryItem.STATE2_FLASHLIGHT_FLAG, uid, "flashlight"); mFlashlightOnTimer.stopRunningLocked(elapsedRealtimeMs); } - getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) - .noteFlashlightTurnedOffLocked(elapsedRealtimeMs); + if (!mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) { + getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) + .noteFlashlightTurnedOffLocked(elapsedRealtimeMs); + } } @GuardedBy("this") diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java index b25239574071..ba6e4a96ddc4 100644 --- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java +++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java @@ -97,9 +97,15 @@ public class BatteryUsageStatsProvider { mContext.getSystemService(SensorManager.class))); mPowerCalculators.add(new GnssPowerCalculator(mPowerProfile)); mPowerCalculators.add(new CameraPowerCalculator(mPowerProfile)); - mPowerCalculators.add(new FlashlightPowerCalculator(mPowerProfile)); - mPowerCalculators.add(new AudioPowerCalculator(mPowerProfile)); - mPowerCalculators.add(new VideoPowerCalculator(mPowerProfile)); + if (!mPowerStatsExporterEnabled.get(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) { + mPowerCalculators.add(new FlashlightPowerCalculator(mPowerProfile)); + } + if (!mPowerStatsExporterEnabled.get(BatteryConsumer.POWER_COMPONENT_AUDIO)) { + mPowerCalculators.add(new AudioPowerCalculator(mPowerProfile)); + } + if (!mPowerStatsExporterEnabled.get(BatteryConsumer.POWER_COMPONENT_VIDEO)) { + mPowerCalculators.add(new VideoPowerCalculator(mPowerProfile)); + } mPowerCalculators.add(new ScreenPowerCalculator(mPowerProfile)); mPowerCalculators.add(new AmbientDisplayPowerCalculator(mPowerProfile)); mPowerCalculators.add(new IdlePowerCalculator(mPowerProfile)); diff --git a/services/core/java/com/android/server/power/stats/FlashlightPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/FlashlightPowerStatsProcessor.java new file mode 100644 index 000000000000..f7216c9af9d6 --- /dev/null +++ b/services/core/java/com/android/server/power/stats/FlashlightPowerStatsProcessor.java @@ -0,0 +1,37 @@ +/* + * 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.server.power.stats; + +import android.os.BatteryConsumer; +import android.os.BatteryStats; + +import com.android.internal.os.PowerProfile; + +public class FlashlightPowerStatsProcessor extends BinaryStatePowerStatsProcessor { + public FlashlightPowerStatsProcessor(PowerProfile powerProfile, + PowerStatsUidResolver uidResolver) { + super(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT, uidResolver, + powerProfile.getAveragePower(PowerProfile.POWER_FLASHLIGHT)); + } + + @Override + protected @BinaryState int getBinaryState(BatteryStats.HistoryItem item) { + return (item.states2 & BatteryStats.HistoryItem.STATE2_FLASHLIGHT_FLAG) != 0 + ? STATE_ON + : STATE_OFF; + } +} diff --git a/services/core/java/com/android/server/power/stats/VideoPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/VideoPowerStatsProcessor.java new file mode 100644 index 000000000000..48dac8a8a970 --- /dev/null +++ b/services/core/java/com/android/server/power/stats/VideoPowerStatsProcessor.java @@ -0,0 +1,37 @@ +/* + * 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.server.power.stats; + +import android.os.BatteryConsumer; +import android.os.BatteryStats; + +import com.android.internal.os.PowerProfile; + +public class VideoPowerStatsProcessor extends BinaryStatePowerStatsProcessor { + public VideoPowerStatsProcessor(PowerProfile powerProfile, + PowerStatsUidResolver uidResolver) { + super(BatteryConsumer.POWER_COMPONENT_VIDEO, uidResolver, + powerProfile.getAveragePower(PowerProfile.POWER_VIDEO)); + } + + @Override + protected @BinaryState int getBinaryState(BatteryStats.HistoryItem item) { + return (item.states2 & BatteryStats.HistoryItem.STATE2_VIDEO_ON_FLAG) != 0 + ? STATE_ON + : STATE_OFF; + } +} diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 4264e912f25a..85c8900555d9 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -1296,7 +1296,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D synchronized (mIcons) { StatusBarIcon icon = new StatusBarIcon(iconPackage, UserHandle.SYSTEM, iconId, - iconLevel, 0, contentDescription); + iconLevel, 0, contentDescription, StatusBarIcon.Type.SystemIcon); //Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon); mIcons.put(slot, icon); diff --git a/services/core/java/com/android/server/wallpaper/WallpaperCropper.java b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java index 80f1125a4ecf..f70a3ba107e1 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperCropper.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java @@ -150,7 +150,7 @@ public class WallpaperCropper { Rect landscapeCrop = getCrop(rotatedDisplaySize, bitmapSize, suggestedCrops, rtl); landscapeCrop = noParallax(landscapeCrop, rotatedDisplaySize, bitmapSize, rtl); // compute the crop on portrait at the center of the landscape crop - crop = getAdjustedCrop(landscapeCrop, bitmapSize, displaySize, false, ADD); + crop = getAdjustedCrop(landscapeCrop, bitmapSize, displaySize, false, rtl, ADD); // add some parallax (until the border of the landscape crop without parallax) if (rtl) { @@ -160,7 +160,7 @@ public class WallpaperCropper { } } - return getAdjustedCrop(crop, bitmapSize, displaySize, true, ADD); + return getAdjustedCrop(crop, bitmapSize, displaySize, true, rtl, ADD); } // If any suggested crop is invalid, fallback to case 1 @@ -176,7 +176,7 @@ public class WallpaperCropper { // Case 2: if the orientation exists in the suggested crops, adjust the suggested crop Rect suggestedCrop = suggestedCrops.get(orientation); if (suggestedCrop != null) { - return getAdjustedCrop(suggestedCrop, bitmapSize, displaySize, true, ADD); + return getAdjustedCrop(suggestedCrop, bitmapSize, displaySize, true, rtl, ADD); } // Case 3: if we have the 90° rotated orientation in the suggested crops, reuse it and @@ -188,7 +188,7 @@ public class WallpaperCropper { if (suggestedCrop != null) { // only keep the visible part (without parallax) Rect adjustedCrop = noParallax(suggestedCrop, suggestedDisplaySize, bitmapSize, rtl); - return getAdjustedCrop(adjustedCrop, bitmapSize, displaySize, false, BALANCE); + return getAdjustedCrop(adjustedCrop, bitmapSize, displaySize, false, rtl, BALANCE); } // Case 4: if the device is a foldable, if we're looking for a folded orientation and have @@ -200,13 +200,13 @@ public class WallpaperCropper { // compute the visible part (without parallax) of the unfolded screen Rect adjustedCrop = noParallax(suggestedCrop, suggestedDisplaySize, bitmapSize, rtl); // compute the folded crop, at the center of the crop of the unfolded screen - Rect res = getAdjustedCrop(adjustedCrop, bitmapSize, displaySize, false, REMOVE); + Rect res = getAdjustedCrop(adjustedCrop, bitmapSize, displaySize, false, rtl, REMOVE); // if we removed some width, add it back to add a parallax effect if (res.width() < adjustedCrop.width()) { if (rtl) res.left = Math.min(res.left, adjustedCrop.left); else res.right = Math.max(res.right, adjustedCrop.right); // use getAdjustedCrop(parallax=true) to make sure we don't exceed MAX_PARALLAX - res = getAdjustedCrop(res, bitmapSize, displaySize, true, ADD); + res = getAdjustedCrop(res, bitmapSize, displaySize, true, rtl, ADD); } return res; } @@ -220,7 +220,7 @@ public class WallpaperCropper { if (suggestedCrop != null) { // only keep the visible part (without parallax) Rect adjustedCrop = noParallax(suggestedCrop, suggestedDisplaySize, bitmapSize, rtl); - return getAdjustedCrop(adjustedCrop, bitmapSize, displaySize, false, ADD); + return getAdjustedCrop(adjustedCrop, bitmapSize, displaySize, false, rtl, ADD); } // Case 6: for a foldable device, try to combine case 3 + case 4 or 5: @@ -255,7 +255,7 @@ public class WallpaperCropper { @VisibleForTesting static Rect noParallax(Rect crop, Point displaySize, Point bitmapSize, boolean rtl) { if (displaySize == null) return crop; - Rect adjustedCrop = getAdjustedCrop(crop, bitmapSize, displaySize, true, ADD); + Rect adjustedCrop = getAdjustedCrop(crop, bitmapSize, displaySize, true, rtl, ADD); // only keep the visible part (without parallax) float suggestedDisplayRatio = 1f * displaySize.x / displaySize.y; int widthToRemove = (int) (adjustedCrop.width() @@ -272,7 +272,7 @@ public class WallpaperCropper { * Adjust a given crop: * <ul> * <li>If parallax = true, make sure we have a parallax of at most {@link #MAX_PARALLAX}, - * by removing content from both sides if necessary. + * by removing content from the right (or left if RTL) if necessary. * <li>If parallax = false, make sure we do not have additional width for parallax. If we * have additional width for parallax, remove half of the additional width on both sides. * <li>Make sure the crop fills the screen, i.e. that the width/height ratio of the crop @@ -282,7 +282,7 @@ public class WallpaperCropper { */ @VisibleForTesting static Rect getAdjustedCrop(Rect crop, Point bitmapSize, Point screenSize, - boolean parallax, int mode) { + boolean parallax, boolean rtl, int mode) { Rect adjustedCrop = new Rect(crop); float cropRatio = ((float) crop.width()) / crop.height(); float screenRatio = ((float) screenSize.x) / screenSize.y; @@ -297,7 +297,8 @@ public class WallpaperCropper { Rect rotatedCrop = new Rect(newLeft, newTop, newRight, newBottom); Point rotatedBitmap = new Point(bitmapSize.y, bitmapSize.x); Point rotatedScreen = new Point(screenSize.y, screenSize.x); - Rect rect = getAdjustedCrop(rotatedCrop, rotatedBitmap, rotatedScreen, false, mode); + Rect rect = getAdjustedCrop( + rotatedCrop, rotatedBitmap, rotatedScreen, false, rtl, mode); int resultLeft = rect.top; int resultRight = resultLeft + rect.height(); int resultTop = rotatedBitmap.x - rect.right; @@ -308,8 +309,11 @@ public class WallpaperCropper { if (additionalWidthForParallax > MAX_PARALLAX) { int widthToRemove = (int) Math.ceil( (additionalWidthForParallax - MAX_PARALLAX) * screenRatio * crop.height()); - adjustedCrop.left += widthToRemove / 2; - adjustedCrop.right -= widthToRemove / 2 + widthToRemove % 2; + if (rtl) { + adjustedCrop.left += widthToRemove; + } else { + adjustedCrop.right -= widthToRemove; + } } } else { // Note: the third case when MODE == BALANCE, -W + sqrt(W * H * R), is the width to add diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 2d2a88a866ba..fec1af47d6e6 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -803,6 +803,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final LetterboxUiController mLetterboxUiController; /** + * The policy for transparent activities + */ + final TransparentPolicy mTransparentPolicy; + + /** * The scale to fit at least one side of the activity to its parent. If the activity uses * 1920x1080, and the actually size on the screen is 960x540, then the scale is 0.5. */ @@ -1698,7 +1703,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (isState(RESUMED)) { newParent.setResumedActivity(this, "onParentChanged"); } - mLetterboxUiController.updateInheritedLetterbox(); + mTransparentPolicy.start(); } if (rootTask != null && rootTask.topRunningActivity() == this) { @@ -2136,6 +2141,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Don't move below setOrientation(info.screenOrientation) since it triggers // getOverrideOrientation that requires having mLetterboxUiController // initialised. + mTransparentPolicy = new TransparentPolicy(this, mWmService.mLetterboxConfiguration); mLetterboxUiController = new LetterboxUiController(mWmService, this); mCameraCompatControlEnabled = mWmService.mContext.getResources() .getBoolean(R.bool.config_isCameraCompatControlForStretchedIssuesEnabled); @@ -8080,13 +8086,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @Configuration.Orientation int getRequestedConfigurationOrientation(boolean forDisplay, @ActivityInfo.ScreenOrientation int requestedOrientation) { - if (mLetterboxUiController.hasInheritedOrientation()) { + if (mTransparentPolicy.hasInheritedOrientation()) { final RootDisplayArea root = getRootDisplayArea(); if (forDisplay && root != null && root.isOrientationDifferentFromDisplay()) { return reverseConfigurationOrientation( - mLetterboxUiController.getInheritedOrientation()); + mTransparentPolicy.getInheritedOrientation()); } else { - return mLetterboxUiController.getInheritedOrientation(); + return mTransparentPolicy.getInheritedOrientation(); } } if (task != null && requestedOrientation == SCREEN_ORIENTATION_BEHIND) { @@ -8302,8 +8308,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @Nullable CompatDisplayInsets getCompatDisplayInsets() { - if (mLetterboxUiController.hasInheritedLetterboxBehavior()) { - return mLetterboxUiController.getInheritedCompatDisplayInsets(); + if (mTransparentPolicy.isRunning()) { + return mTransparentPolicy.getInheritedCompatDisplayInsets(); } return mCompatDisplayInsets; } @@ -8466,7 +8472,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } mSizeCompatBounds = null; mCompatDisplayInsets = null; - mLetterboxUiController.clearInheritedCompatDisplayInsets(); + mTransparentPolicy.clearInheritedCompatDisplayInsets(); } @VisibleForTesting @@ -8784,8 +8790,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE; } // TODO(b/256564921): Investigate if we need new metrics for translucent activities - if (mLetterboxUiController.hasInheritedLetterboxBehavior()) { - return mLetterboxUiController.getInheritedAppCompatState(); + if (mTransparentPolicy.isRunning()) { + return mTransparentPolicy.getInheritedAppCompatState(); } if (mInSizeCompatModeForBounds) { return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE; @@ -8938,7 +8944,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // We check if the current activity is transparent. In that case we need to // recomputeConfiguration of the first opaque activity beneath, to allow a // proper computation of the new bounds. - if (!mLetterboxUiController.applyOnOpaqueActivityBelow( + if (!mTransparentPolicy.applyOnOpaqueActivityBelow( ActivityRecord::recomputeConfiguration)) { onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration()); } @@ -9411,7 +9417,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A void updateSizeCompatScale(Rect resolvedAppBounds, Rect containerAppBounds) { // Only allow to scale down. - mSizeCompatScale = mLetterboxUiController.findOpaqueNotFinishingActivityBelow() + mSizeCompatScale = mTransparentPolicy.findOpaqueNotFinishingActivityBelow() .map(activityRecord -> activityRecord.mSizeCompatScale) .orElseGet(() -> { final int contentW = resolvedAppBounds.width(); @@ -9424,7 +9430,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } private boolean isInSizeCompatModeForBounds(final Rect appBounds, final Rect containerBounds) { - if (mLetterboxUiController.hasInheritedLetterboxBehavior()) { + if (mTransparentPolicy.isRunning()) { // To avoid wrong app behaviour, we decided to disable SCM when a translucent activity // is letterboxed. return false; @@ -9487,7 +9493,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A public Rect getBounds() { // TODO(b/268458693): Refactor configuration inheritance in case of translucent activities final Rect superBounds = super.getBounds(); - return mLetterboxUiController.findOpaqueNotFinishingActivityBelow() + return mTransparentPolicy.findOpaqueNotFinishingActivityBelow() .map(ActivityRecord::getBounds) .orElseGet(() -> { if (mSizeCompatBounds != null) { @@ -9851,8 +9857,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * Returns the min aspect ratio of this activity. */ float getMinAspectRatio() { - if (mLetterboxUiController.hasInheritedLetterboxBehavior()) { - return mLetterboxUiController.getInheritedMinAspectRatio(); + if (mTransparentPolicy.isRunning()) { + return mTransparentPolicy.getInheritedMinAspectRatio(); } if (info.applicationInfo == null) { return info.getMinAspectRatio(); @@ -9902,8 +9908,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } float getMaxAspectRatio() { - if (mLetterboxUiController.hasInheritedLetterboxBehavior()) { - return mLetterboxUiController.getInheritedMaxAspectRatio(); + if (mTransparentPolicy.isRunning()) { + return mTransparentPolicy.getInheritedMaxAspectRatio(); } return info.getMaxAspectRatio(); } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index a9192c4c6139..d7a696f47b7e 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1365,18 +1365,6 @@ class ActivityStarter { request.outActivity[0] = mLastStartActivityRecord; } - // Reset the ActivityRecord#mCurrentLaunchCanTurnScreenOn state of activity started - // before this one if it is no longer the top-most focusable activity. - // Doing so in case the state is not yet consumed during rapid activity launch. - if (previousStart != null && !previousStart.finishing && previousStart.isAttached() - && previousStart.currentLaunchCanTurnScreenOn()) { - final ActivityRecord topFocusable = previousStart.getDisplayContent().getActivity( - ar -> ar.isFocusable() && !ar.finishing); - if (previousStart != topFocusable) { - previousStart.setCurrentLaunchCanTurnScreenOn(false); - } - } - return mLastStartActivityResult; } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 3aa63af014c8..cfd5300417b4 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -1439,6 +1439,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { resultTo.removeResultsLocked(r, resultWho, requestCode); } + final int origCallingUid = Binder.getCallingUid(); + final int origCallingPid = Binder.getCallingPid(); final long origId = Binder.clearCallingIdentity(); // TODO(b/64750076): Check if calling pid should really be -1. try { @@ -1446,13 +1448,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { options = new SafeActivityOptions(ActivityOptions.makeBasic()); } - // Fixes b/230492947 + // Fixes b/230492947 b/337726734 // Prevents background activity launch through #startNextMatchingActivity - // An activity going into the background could still go back to the foreground - // if the intent used matches both: - // - the activity in the background - // - a second activity. - options.getOptions(r).setAvoidMoveToFront(); + // launchedFromUid of the calling activity represents the app that launches it. + // It may have BAL privileges (i.e. the Launcher App). Using its identity to + // launch to launch next matching activity causes BAL. + // Change the realCallingUid to the calling activity's uid. + // In ActivityStarter, when caller is set, the callingUid and callingPid are + // ignored. So now both callingUid and realCallingUid is set to the caller app. final int res = getActivityStartController() .obtainStarter(intent, "startNextMatchingActivity") .setCaller(r.app.getThread()) @@ -1465,8 +1468,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { .setCallingUid(r.launchedFromUid) .setCallingPackage(r.launchedFromPackage) .setCallingFeatureId(r.launchedFromFeatureId) - .setRealCallingPid(-1) - .setRealCallingUid(r.launchedFromUid) + .setRealCallingPid(origCallingPid) + .setRealCallingUid(origCallingUid) .setActivityOptions(options) .setUserId(userId) .execute(); @@ -1507,7 +1510,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { a.persistableMode = ActivityInfo.PERSIST_NEVER; a.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; a.colorMode = ActivityInfo.COLOR_MODE_DEFAULT; - a.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; + a.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS | ActivityInfo.FLAG_SHOW_WHEN_LOCKED; a.configChanges = 0xffffffff; if (homePanelDream()) { diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index a10f7e7b00d0..3867d2d229ea 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -155,7 +155,7 @@ import com.android.server.LocalServices; import com.android.server.am.ActivityManagerService; import com.android.server.am.HostingRecord; import com.android.server.am.UserState; -import com.android.server.pm.PackageManagerServiceUtils; +import com.android.server.pm.SaferIntentUtils; import com.android.server.utils.Slogf; import com.android.server.wm.ActivityMetricsLogger.LaunchingState; @@ -769,7 +769,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { // (e.g. AMS.startActivityAsUser). final long token = Binder.clearCallingIdentity(); try { - return mService.getPackageManagerInternalLocked().resolveIntentExported( + return mService.getPackageManagerInternalLocked().resolveIntent( intent, resolvedType, modifiedFlags, privateResolveFlags, userId, true, filterCallingUid, callingPid); } finally { @@ -2856,14 +2856,14 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { // We need to temporarily disable the explicit intent filter matching enforcement // because Task does not store the resolved type of the intent data, causing filter // mismatch in certain cases. (b/240373119) - PackageManagerServiceUtils.DISABLE_ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS.set(true); + SaferIntentUtils.DISABLE_ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS.set(true); return mService.getActivityStartController().startActivityInPackage(taskCallingUid, callingPid, callingUid, callingPackage, callingFeatureId, intent, null, null, null, 0, 0, options, userId, task, "startActivityFromRecents", false /* validateIncomingUser */, null /* originatingPendingIntent */, BackgroundStartPrivileges.NONE); } finally { - PackageManagerServiceUtils.DISABLE_ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS.set(false); + SaferIntentUtils.DISABLE_ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS.set(false); synchronized (mService.mGlobalLock) { mService.continueWindowLayout(); } diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java index 19d7a3c8d86c..a4fb95964a5c 100644 --- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java +++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java @@ -427,19 +427,6 @@ public class BackgroundActivityStartController { return name + "[debugOnly]"; } - /** @return valid targetSdk or <code>-1</code> */ - private int getTargetSdk(String packageName) { - if (packageName == null) { - return -1; - } - try { - PackageManager pm = mService.mContext.getPackageManager(); - return pm.getTargetSdkVersion(packageName); - } catch (Exception e) { - return -1; - } - } - private boolean hasRealCaller() { return mRealCallingUid != NO_PROCESS_UID; } @@ -1730,7 +1717,9 @@ public class BackgroundActivityStartController { state.mResultForRealCaller == null ? BAL_BLOCK : state.mResultForRealCaller.getRawCode(), state.mBalAllowedByPiSender.allowsBackgroundActivityStarts(), - state.realCallerExplicitOptInOrOut() + state.realCallerExplicitOptInOrOut(), + getTargetSdk(state.mCallingPackage), + getTargetSdk(state.mRealCallingPackage) ); } @@ -1811,6 +1800,19 @@ public class BackgroundActivityStartController { + ", taskFragment=" + ar.getTaskFragment(); } + /** @return valid targetSdk or <code>-1</code> */ + private int getTargetSdk(String packageName) { + if (packageName == null) { + return -1; + } + try { + PackageManager pm = mService.mContext.getPackageManager(); + return pm.getTargetSdkVersion(packageName); + } catch (Exception e) { + return -1; + } + } + private class FinishedActivityEntry { int mUid; int mTaskId; diff --git a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java index 125eb2a3a810..be44629a1fcf 100644 --- a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java +++ b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java @@ -194,6 +194,16 @@ public class DeferredDisplayUpdater implements DisplayUpdater { final Rect startBounds = new Rect(0, 0, mDisplayContent.mInitialDisplayWidth, mDisplayContent.mInitialDisplayHeight); final int fromRotation = mDisplayContent.getRotation(); + if (Flags.blastSyncNotificationShadeOnDisplaySwitch() && physicalDisplayUpdated) { + final WindowState notificationShade = + mDisplayContent.getDisplayPolicy().getNotificationShade(); + if (notificationShade != null && notificationShade.isVisible() + && mDisplayContent.mAtmService.mKeyguardController.isKeyguardOrAodShowing( + mDisplayContent.mDisplayId)) { + Slog.i(TAG, notificationShade + " uses blast for display switch"); + notificationShade.mSyncMethodOverride = BLASTSyncEngine.METHOD_BLAST; + } + } mDisplayContent.mAtmService.deferWindowLayout(); try { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index a551c7c01b64..a3a6b51521f2 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -4160,6 +4160,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp && mImeLayeringTarget != null && mImeLayeringTarget.mActivityRecord != null && mImeLayeringTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN + && mImeLayeringTarget.getBounds().equals(mImeWindowsContainer.getBounds()) // IME is attached to app windows that fill display area. This excludes // letterboxed windows. && mImeLayeringTarget.matchesDisplayAreaBounds(); diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index d0086aa24337..2f2395502e4b 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -2011,9 +2011,14 @@ public class DisplayPolicy { public String toString() { final StringBuilder tmpSb = new StringBuilder(32); return "{nonDecorInsets=" + mNonDecorInsets.toShortString(tmpSb) + + ", overrideNonDecorInsets=" + mOverrideNonDecorInsets.toShortString(tmpSb) + ", configInsets=" + mConfigInsets.toShortString(tmpSb) + + ", overrideConfigInsets=" + mOverrideConfigInsets.toShortString(tmpSb) + ", nonDecorFrame=" + mNonDecorFrame.toShortString(tmpSb) - + ", configFrame=" + mConfigFrame.toShortString(tmpSb) + '}'; + + ", overrideNonDecorFrame=" + mOverrideNonDecorFrame.toShortString(tmpSb) + + ", configFrame=" + mConfigFrame.toShortString(tmpSb) + + ", overrideConfigFrame=" + mOverrideConfigFrame.toShortString(tmpSb) + + '}'; } } diff --git a/services/core/java/com/android/server/wm/EventLogTags.logtags b/services/core/java/com/android/server/wm/EventLogTags.logtags index d957591ab7f9..cc2249de010c 100644 --- a/services/core/java/com/android/server/wm/EventLogTags.logtags +++ b/services/core/java/com/android/server/wm/EventLogTags.logtags @@ -59,6 +59,10 @@ option java_package com.android.server.wm 31002 wm_task_moved (TaskId|1|5),(Root Task ID|1|5),(Display Id|1|5),(ToTop|1),(Index|1) # Task removed with source explanation. 31003 wm_task_removed (TaskId|1|5),(Root Task ID|1|5),(Display Id|1|5),(Reason|3) +# Embedded TaskFragment created +31004 wm_tf_created (Token|1|5),(TaskId|1|5) +# Embedded TaskFragment removed +31005 wm_tf_removed (Token|1|5),(TaskId|1|5) # Set the requested orientation of an activity. 31006 wm_set_requested_orientation (Orientation|1|5),(Component Name|3) diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index b8d0694047c7..194771f6b387 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -40,7 +40,6 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER; import static android.content.pm.ActivityInfo.isFixedOrientation; import static android.content.pm.ActivityInfo.isFixedOrientationLandscape; @@ -54,10 +53,6 @@ import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCREEN; import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; -import static android.content.res.Configuration.ORIENTATION_UNDEFINED; -import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED; -import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED; -import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; @@ -80,7 +75,6 @@ import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANG import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__RIGHT; import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__TOP; import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__UNKNOWN_POSITION; -import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN; import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__BOTTOM_TO_CENTER; import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_BOTTOM; import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_LEFT; @@ -135,12 +129,7 @@ import com.android.server.wm.utils.OptPropFactory.OptProp; import com.android.window.flags.Flags; import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; import java.util.function.BooleanSupplier; -import java.util.function.Consumer; -import java.util.function.Predicate; /** Controls behaviour of the letterbox UI for {@link mActivityRecord}. */ // TODO(b/185262487): Improve test coverage of this class. Parts of it are tested in @@ -150,13 +139,8 @@ import java.util.function.Predicate; // TODO(b/263021211): Consider renaming to more generic CompatUIController. final class LetterboxUiController { - private static final Predicate<ActivityRecord> FIRST_OPAQUE_NOT_FINISHING_ACTIVITY_PREDICATE = - ActivityRecord::occludesParent; - private static final String TAG = TAG_WITH_CLASS_NAME ? "LetterboxUiController" : TAG_ATM; - private static final float UNDEFINED_ASPECT_RATIO = 0f; - // Minimum value of mSetOrientationRequestCounter before qualifying as orientation request loop @VisibleForTesting static final int MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP = 2; @@ -188,10 +172,6 @@ final class LetterboxUiController { // Corresponds to OVERRIDE_RESPECT_REQUESTED_ORIENTATION private final boolean mIsOverrideRespectRequestedOrientationEnabled; - // The list of observers for the destroy event of candidate opaque activities - // when dealing with translucent activities. - private final List<LetterboxUiController> mDestroyListeners = new ArrayList<>(); - @NonNull private final OptProp mAllowOrientationOverrideOptProp; @NonNull @@ -206,34 +186,11 @@ final class LetterboxUiController { @NonNull private final OptProp mAllowUserAspectRatioFullscreenOverrideOptProp; - /* - * WindowContainerListener responsible to make translucent activities inherit - * constraints from the first opaque activity beneath them. It's null for not - * translucent activities. - */ - @Nullable - private WindowContainerListener mLetterboxConfigListener; - - @Nullable - @VisibleForTesting - ActivityRecord mFirstOpaqueActivityBeneath; - private boolean mShowWallpaperForLetterboxBackground; - // In case of transparent activities we might need to access the aspectRatio of the - // first opaque activity beneath. - private float mInheritedMinAspectRatio = UNDEFINED_ASPECT_RATIO; - private float mInheritedMaxAspectRatio = UNDEFINED_ASPECT_RATIO; - // Updated when ActivityRecord#setRequestedOrientation is called private long mTimeMsLastSetOrientationRequest = 0; - @Configuration.Orientation - private int mInheritedOrientation = ORIENTATION_UNDEFINED; - - // The app compat state for the opaque activity if any - private int mInheritedAppCompatState = APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN; - // Counter for ActivityRecord#setRequestedOrientation private int mSetOrientationRequestCounter = 0; @@ -242,9 +199,6 @@ final class LetterboxUiController { @PackageManager.UserMinAspectRatio private int mUserAspectRatio = USER_MIN_ASPECT_RATIO_UNSET; - // The CompatDisplayInsets of the opaque activity beneath the translucent one. - private ActivityRecord.CompatDisplayInsets mInheritedCompatDisplayInsets; - @Nullable private Letterbox mLetterbox; @@ -361,14 +315,7 @@ final class LetterboxUiController { mLetterbox.destroy(); mLetterbox = null; } - for (int i = mDestroyListeners.size() - 1; i >= 0; i--) { - mDestroyListeners.get(i).updateInheritedLetterbox(); - } - mDestroyListeners.clear(); - if (mLetterboxConfigListener != null) { - mLetterboxConfigListener.onRemoved(); - mLetterboxConfigListener = null; - } + mActivityRecord.mTransparentPolicy.stop(); } void onMovedToDisplay(int displayId) { @@ -877,7 +824,7 @@ final class LetterboxUiController { // For this reason we use ActivityRecord#getBounds() that the translucent activity // inherits from the first opaque activity beneath and also takes care of the scaling // in case of activities in size compat mode. - final Rect innerFrame = hasInheritedLetterboxBehavior() + final Rect innerFrame = mActivityRecord.mTransparentPolicy.isRunning() ? mActivityRecord.getBounds() : w.getFrame(); mLetterbox.layout(spaceToFill, innerFrame, mTmpPoint); if (mDoubleTapEvent) { @@ -1343,9 +1290,9 @@ final class LetterboxUiController { } // Use screen resolved bounds which uses resolved bounds or size compat bounds // as activity bounds can sometimes be empty - final Rect opaqueActivityBounds = hasInheritedLetterboxBehavior() - ? mFirstOpaqueActivityBeneath.getScreenResolvedBounds() - : mActivityRecord.getScreenResolvedBounds(); + final Rect opaqueActivityBounds = mActivityRecord.mTransparentPolicy + .getFirstOpaqueActivity().map(ActivityRecord::getScreenResolvedBounds) + .orElse(mActivityRecord.getScreenResolvedBounds()); return mLetterboxConfiguration.getIsHorizontalReachabilityEnabled() && parentConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_FULLSCREEN @@ -1380,10 +1327,10 @@ final class LetterboxUiController { return false; } // Use screen resolved bounds which uses resolved bounds or size compat bounds - // as activity bounds can sometimes be empty - final Rect opaqueActivityBounds = hasInheritedLetterboxBehavior() - ? mFirstOpaqueActivityBeneath.getScreenResolvedBounds() - : mActivityRecord.getScreenResolvedBounds(); + // as activity bounds can sometimes be empty. + final Rect opaqueActivityBounds = mActivityRecord.mTransparentPolicy + .getFirstOpaqueActivity().map(ActivityRecord::getScreenResolvedBounds) + .orElse(mActivityRecord.getScreenResolvedBounds()); return mLetterboxConfiguration.getIsVerticalReachabilityEnabled() && parentConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_FULLSCREEN @@ -1490,7 +1437,8 @@ final class LetterboxUiController { // corners because we assume the specific layout would. This is the case when the layout // of the translucent activity uses only a part of all the bounds because of the use of // LayoutParams.WRAP_CONTENT. - if (hasInheritedLetterboxBehavior() && (cropBounds.width() != mainWindow.mRequestedWidth + if (mActivityRecord.mTransparentPolicy.isRunning() + && (cropBounds.width() != mainWindow.mRequestedWidth || cropBounds.height() != mainWindow.mRequestedHeight)) { return null; } @@ -1794,173 +1742,6 @@ final class LetterboxUiController { ); } - /** - * Handles translucent activities letterboxing inheriting constraints from the - * first opaque activity beneath. - * @param parent The parent container. - */ - void updateInheritedLetterbox() { - final WindowContainer<?> parent = mActivityRecord.getParent(); - if (parent == null) { - return; - } - if (!mLetterboxConfiguration.isTranslucentLetterboxingEnabled()) { - return; - } - if (mLetterboxConfigListener != null) { - mLetterboxConfigListener.onRemoved(); - clearInheritedConfig(); - } - // In case mActivityRecord.hasCompatDisplayInsetsWithoutOverride() we don't apply the - // opaque activity constraints because we're expecting the activity is already letterboxed. - mFirstOpaqueActivityBeneath = mActivityRecord.getTask().getActivity( - FIRST_OPAQUE_NOT_FINISHING_ACTIVITY_PREDICATE /* callback */, - mActivityRecord /* boundary */, false /* includeBoundary */, - true /* traverseTopToBottom */); - if (mFirstOpaqueActivityBeneath == null || mFirstOpaqueActivityBeneath.isEmbedded()) { - // We skip letterboxing if the translucent activity doesn't have any opaque - // activities beneath or the activity below is embedded which never has letterbox. - mActivityRecord.recomputeConfiguration(); - return; - } - if (mActivityRecord.getTask() == null || mActivityRecord.fillsParent() - || mActivityRecord.hasCompatDisplayInsetsWithoutInheritance()) { - return; - } - mFirstOpaqueActivityBeneath.mLetterboxUiController.mDestroyListeners.add(this); - inheritConfiguration(mFirstOpaqueActivityBeneath); - mLetterboxConfigListener = WindowContainer.overrideConfigurationPropagation( - mActivityRecord, mFirstOpaqueActivityBeneath, - (opaqueConfig, transparentOverrideConfig) -> { - resetTranslucentOverrideConfig(transparentOverrideConfig); - final Rect parentBounds = parent.getWindowConfiguration().getBounds(); - final Rect bounds = transparentOverrideConfig.windowConfiguration.getBounds(); - final Rect letterboxBounds = opaqueConfig.windowConfiguration.getBounds(); - // We cannot use letterboxBounds directly here because the position relies on - // letterboxing. Using letterboxBounds directly, would produce a double offset. - bounds.set(parentBounds.left, parentBounds.top, - parentBounds.left + letterboxBounds.width(), - parentBounds.top + letterboxBounds.height()); - // We need to initialize appBounds to avoid NPE. The actual value will - // be set ahead when resolving the Configuration for the activity. - transparentOverrideConfig.windowConfiguration.setAppBounds(new Rect()); - inheritConfiguration(mFirstOpaqueActivityBeneath); - return transparentOverrideConfig; - }); - } - - /** - * @return {@code true} if the current activity is translucent with an opaque activity - * beneath. In this case it will inherit bounds, orientation and aspect ratios from - * the first opaque activity beneath. - */ - boolean hasInheritedLetterboxBehavior() { - return mLetterboxConfigListener != null; - } - - /** - * @return {@code true} if the current activity is translucent with an opaque activity - * beneath and needs to inherit its orientation. - */ - boolean hasInheritedOrientation() { - // To force a different orientation, the transparent one needs to have an explicit one - // otherwise the existing one is fine and the actual orientation will depend on the - // bounds. - // To avoid wrong behaviour, we're not forcing orientation for activities with not - // fixed orientation (e.g. permission dialogs). - return hasInheritedLetterboxBehavior() - && mActivityRecord.getOverrideOrientation() - != SCREEN_ORIENTATION_UNSPECIFIED; - } - - float getInheritedMinAspectRatio() { - return mInheritedMinAspectRatio; - } - - float getInheritedMaxAspectRatio() { - return mInheritedMaxAspectRatio; - } - - int getInheritedAppCompatState() { - return mInheritedAppCompatState; - } - - @Configuration.Orientation - int getInheritedOrientation() { - return mInheritedOrientation; - } - - ActivityRecord.CompatDisplayInsets getInheritedCompatDisplayInsets() { - return mInheritedCompatDisplayInsets; - } - - void clearInheritedCompatDisplayInsets() { - mInheritedCompatDisplayInsets = null; - } - - /** - * In case of translucent activities, it consumes the {@link ActivityRecord} of the first opaque - * activity beneath using the given consumer and returns {@code true}. - */ - boolean applyOnOpaqueActivityBelow(@NonNull Consumer<ActivityRecord> consumer) { - return findOpaqueNotFinishingActivityBelow() - .map(activityRecord -> { - consumer.accept(activityRecord); - return true; - }).orElse(false); - } - - /** - * @return The first not finishing opaque activity beneath the current translucent activity - * if it exists and the strategy is enabled. - */ - Optional<ActivityRecord> findOpaqueNotFinishingActivityBelow() { - if (!hasInheritedLetterboxBehavior() || mActivityRecord.getTask() == null) { - return Optional.empty(); - } - return Optional.ofNullable(mFirstOpaqueActivityBeneath); - } - - /** Resets the screen size related fields so they can be resolved by requested bounds later. */ - private static void resetTranslucentOverrideConfig(Configuration config) { - // The values for the following properties will be defined during the configuration - // resolution in {@link ActivityRecord#resolveOverrideConfiguration} using the - // properties inherited from the first not finishing opaque activity beneath. - config.orientation = ORIENTATION_UNDEFINED; - config.screenWidthDp = config.compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED; - config.screenHeightDp = config.compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED; - config.smallestScreenWidthDp = config.compatSmallestScreenWidthDp = - SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; - } - - private void inheritConfiguration(ActivityRecord firstOpaque) { - // To avoid wrong behaviour, we're not forcing a specific aspect ratio to activities - // which are not already providing one (e.g. permission dialogs) and presumably also - // not resizable. - if (mActivityRecord.getMinAspectRatio() != UNDEFINED_ASPECT_RATIO) { - mInheritedMinAspectRatio = firstOpaque.getMinAspectRatio(); - } - if (mActivityRecord.getMaxAspectRatio() != UNDEFINED_ASPECT_RATIO) { - mInheritedMaxAspectRatio = firstOpaque.getMaxAspectRatio(); - } - mInheritedOrientation = firstOpaque.getRequestedConfigurationOrientation(); - mInheritedAppCompatState = firstOpaque.getAppCompatState(); - mInheritedCompatDisplayInsets = firstOpaque.getCompatDisplayInsets(); - } - - private void clearInheritedConfig() { - if (mFirstOpaqueActivityBeneath != null) { - mFirstOpaqueActivityBeneath.mLetterboxUiController.mDestroyListeners.remove(this); - } - mFirstOpaqueActivityBeneath = null; - mLetterboxConfigListener = null; - mInheritedMinAspectRatio = UNDEFINED_ASPECT_RATIO; - mInheritedMaxAspectRatio = UNDEFINED_ASPECT_RATIO; - mInheritedOrientation = ORIENTATION_UNDEFINED; - mInheritedAppCompatState = APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN; - mInheritedCompatDisplayInsets = null; - } - @NonNull private static BooleanSupplier asLazy(@NonNull BooleanSupplier supplier) { return new BooleanSupplier() { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index be8c2aea7ad1..9c7c41c8525c 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -1693,7 +1693,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } /** - * Check if home activity start should be allowed on a display. + * Check if home activity start should be allowed on a {@link TaskDisplayArea}. * * @param homeInfo {@code ActivityInfo} of the home activity that is going to be * launched. @@ -1717,6 +1717,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return false; } + if (taskDisplayArea != null && !taskDisplayArea.canHostHomeTask()) { + return false; + } + final int displayId = taskDisplayArea != null ? taskDisplayArea.getDisplayId() : INVALID_DISPLAY; if (shouldPlacePrimaryHomeOnDisplay(displayId)) { diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 69a8aed04d96..13883fdf14eb 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -3739,7 +3739,13 @@ class Task extends TaskFragment { return !isOwnActivity && !isTrustedTaskFragment; } - void setDecorSurfaceBoosted( + /** + * Sets the requested boosted state for the decor surface. + * + * The caller must call {@link #commitDecorSurfaceBoostedState()} to ensure that the change is + * applied. + */ + void requestDecorSurfaceBoosted( @NonNull TaskFragment ownerTaskFragment, boolean isBoosted, @Nullable SurfaceControl.Transaction clientTransaction) { @@ -3747,9 +3753,17 @@ class Task extends TaskFragment { || mDecorSurfaceContainer.mOwnerTaskFragment != ownerTaskFragment) { return; } - mDecorSurfaceContainer.setBoosted(isBoosted, clientTransaction); - // scheduleAnimation() is called inside assignChildLayers(), which ensures that child - // surface visibility is updated with prepareSurfaces() + mDecorSurfaceContainer.requestBoosted(isBoosted, clientTransaction); + } + + void commitDecorSurfaceBoostedState() { + if (mDecorSurfaceContainer == null) { + return; + } + mDecorSurfaceContainer.commitBoostedState(); + + // assignChildLayers() calls scheduleAnimation(), which calls prepareSurfaces() + // to ensure child surface visibility. assignChildLayers(); } @@ -6790,11 +6804,11 @@ class Task extends TaskFragment { * Associates the decor surface with the given TF, or create one if there * isn't one in the Task yet. The surface will be removed with the TF, * and become invisible if the TF is invisible. */ - void moveOrCreateDecorSurfaceFor(TaskFragment taskFragment) { + void moveOrCreateDecorSurfaceFor(TaskFragment taskFragment, boolean visible) { if (mDecorSurfaceContainer != null) { mDecorSurfaceContainer.mOwnerTaskFragment = taskFragment; } else { - mDecorSurfaceContainer = new DecorSurfaceContainer(taskFragment); + mDecorSurfaceContainer = new DecorSurfaceContainer(taskFragment, visible); assignChildLayers(); sendTaskFragmentParentInfoChangedIfNeeded(); } @@ -6813,6 +6827,13 @@ class Task extends TaskFragment { return mDecorSurfaceContainer != null ? mDecorSurfaceContainer.mDecorSurface : null; } + void setDecorSurfaceVisible(@NonNull SurfaceControl.Transaction t) { + if (mDecorSurfaceContainer == null) { + return; + } + t.show(mDecorSurfaceContainer.mDecorSurface); + } + /** * A class managing the decor surface. * @@ -6852,12 +6873,13 @@ class Task extends TaskFragment { @NonNull TaskFragment mOwnerTaskFragment; private boolean mIsBoosted; + private boolean mIsBoostedRequested; // The surface transactions that will be applied when the layer is reassigned. @NonNull private final List<SurfaceControl.Transaction> mPendingClientTransactions = new ArrayList<>(); - private DecorSurfaceContainer(@NonNull TaskFragment initialOwner) { + private DecorSurfaceContainer(@NonNull TaskFragment initialOwner, boolean visible) { mOwnerTaskFragment = initialOwner; mContainerSurface = makeSurface().setContainerLayer() .setParent(mSurfaceControl) @@ -6870,23 +6892,36 @@ class Task extends TaskFragment { mDecorSurface = makeSurface() .setParent(mContainerSurface) .setName(mSurfaceControl + " - decor surface") - .setHidden(false) + .setHidden(!visible) .setCallsite("Task.DecorSurfaceContainer") .build(); } - private void setBoosted( + /** + * Sets the requested boosted state. The state is not applied until + * {@link commitBoostedState} is called. + */ + private void requestBoosted( boolean isBoosted, @Nullable SurfaceControl.Transaction clientTransaction) { - mIsBoosted = isBoosted; - // The client transaction will be applied together with the next assignLayer. + mIsBoostedRequested = isBoosted; + // The client transaction will be applied together with the next commitBoostedState. if (clientTransaction != null) { mPendingClientTransactions.add(clientTransaction); } } + /** Applies the last requested boosted state. */ + private void commitBoostedState() { + mIsBoosted = mIsBoostedRequested; + applyPendingClientTransactions(getSyncTransaction()); + } + private void assignLayer(@NonNull SurfaceControl.Transaction t, int layer) { t.setLayer(mContainerSurface, layer); t.setVisibility(mContainerSurface, mOwnerTaskFragment.isVisible() || mIsBoosted); + } + + private void applyPendingClientTransactions(@NonNull SurfaceControl.Transaction t) { for (int i = 0; i < mPendingClientTransactions.size(); i++) { t.merge(mPendingClientTransactions.get(i)); } diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 61022cc971e2..b8b746a3de7f 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -2999,6 +2999,9 @@ class TaskFragment extends WindowContainer<WindowContainer> { @Override void removeImmediately() { + if (asTask() == null) { + EventLogTags.writeWmTfRemoved(System.identityHashCode(this), getTaskId()); + } mIsRemovalRequested = false; resetAdjacentTaskFragment(); cleanUpEmbeddedTaskFragment(); diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 86c6f8db8899..4aa3e3644daa 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -1374,13 +1374,22 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { // processed all the participants first (in particular, we want to trigger pip-enter first) for (int i = 0; i < mParticipants.size(); ++i) { final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord(); + if (ar == null) continue; + // If the activity was just inserted to an invisible task, it will keep INITIALIZING // state. Then no need to notify the callback to avoid clearing some states // unexpectedly, e.g. launch-task-behind. - if (ar != null && (ar.isVisibleRequested() - || !ar.isState(ActivityRecord.State.INITIALIZING))) { + if (ar.isVisibleRequested() || !ar.isState(ActivityRecord.State.INITIALIZING)) { mController.dispatchLegacyAppTransitionFinished(ar); } + + // Reset the ActivityRecord#mCurrentLaunchCanTurnScreenOn state if it is not the top + // running activity. Doing so in case the state is not yet consumed during rapid + // activity launch. + if (ar.currentLaunchCanTurnScreenOn() && ar.getDisplayContent() != null + && ar.getDisplayContent().topRunningActivity() != ar) { + ar.setCurrentLaunchCanTurnScreenOn(false); + } } // Update the input-sink (touch-blocking) state now that the animation is finished. @@ -1895,6 +1904,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { for (int i = changes.size() - 1; i >= 0; --i) { if (mTargets.get(i).mContainer.asActivityRecord() != null) { changes.get(i).setAnimationOptions(mOverrideOptions); + // TODO(b/295805497): Extract mBackgroundColor from AnimationOptions. + changes.get(i).setBackgroundColor(mOverrideOptions.getBackgroundColor()); } } } diff --git a/services/core/java/com/android/server/wm/TransparentPolicy.java b/services/core/java/com/android/server/wm/TransparentPolicy.java new file mode 100644 index 000000000000..b408397d1861 --- /dev/null +++ b/services/core/java/com/android/server/wm/TransparentPolicy.java @@ -0,0 +1,353 @@ +/* + * 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.server.wm; + +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.content.res.Configuration.ORIENTATION_UNDEFINED; +import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED; +import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED; +import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; + +import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.res.Configuration; +import android.graphics.Rect; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; +import java.util.function.Predicate; + +/** + * Encapsulate logic about translucent activities. + * <p/> + * An activity is defined as translucent if {@link ActivityRecord#fillsParent()} returns + * {@code false}. When the policy is running for a letterboxed activity, a transparent activity + * will inherit constraints about bounds, aspect ratios and orientation from the first not finishing + * activity below. + */ +class TransparentPolicy { + + private static final String TAG = TAG_WITH_CLASS_NAME ? "TransparentPolicy" : TAG_ATM; + + // The predicate used to find the first opaque not finishing activity below the potential + // transparent activity. + private static final Predicate<ActivityRecord> FIRST_OPAQUE_NOT_FINISHING_ACTIVITY_PREDICATE = + ActivityRecord::occludesParent; + + // The ActivityRecord this policy relates to. + @NonNull + private final ActivityRecord mActivityRecord; + + // If transparent activity policy is enabled. + @NonNull + private final BooleanSupplier mIsTranslucentLetterboxingEnabledSupplier; + + // The list of observers for the destroy event of candidate opaque activities + // when dealing with translucent activities. + @NonNull + private final List<TransparentPolicy> mDestroyListeners = new ArrayList<>(); + + // The current state for the possible transparent activity + @NonNull + private final TransparentPolicyState mTransparentPolicyState; + + TransparentPolicy(@NonNull ActivityRecord activityRecord, + @NonNull LetterboxConfiguration letterboxConfiguration) { + mActivityRecord = activityRecord; + mIsTranslucentLetterboxingEnabledSupplier = + letterboxConfiguration::isTranslucentLetterboxingEnabled; + mTransparentPolicyState = new TransparentPolicyState(activityRecord); + } + + /** + * Handles translucent activities letterboxing inheriting constraints from the + * first opaque activity beneath. + */ + void start() { + if (!mIsTranslucentLetterboxingEnabledSupplier.getAsBoolean()) { + return; + } + final WindowContainer<?> parent = mActivityRecord.getParent(); + if (parent == null) { + return; + } + mTransparentPolicyState.reset(); + // In case mActivityRecord.hasCompatDisplayInsetsWithoutOverride() we don't apply the + // opaque activity constraints because we're expecting the activity is already letterboxed. + final ActivityRecord firstOpaqueActivity = mActivityRecord.getTask().getActivity( + FIRST_OPAQUE_NOT_FINISHING_ACTIVITY_PREDICATE /* callback */, + mActivityRecord /* boundary */, false /* includeBoundary */, + true /* traverseTopToBottom */); + // We check if we need for some reason to skip the policy gievn the specific first + // opaque activity + if (shouldSkipTransparentPolicy(firstOpaqueActivity)) { + return; + } + mTransparentPolicyState.start(firstOpaqueActivity); + } + + void stop() { + for (int i = mDestroyListeners.size() - 1; i >= 0; i--) { + mDestroyListeners.get(i).start(); + } + mDestroyListeners.clear(); + mTransparentPolicyState.reset(); + } + + /** + * @return {@code true} if the current activity is translucent with an opaque activity + * beneath and the related policy is running. In this case it will inherit bounds, orientation + * and aspect ratios from the first opaque activity beneath. + */ + boolean isRunning() { + return mTransparentPolicyState.isRunning(); + } + + /** + * @return {@code true} if the current activity is translucent with an opaque activity + * beneath and needs to inherit its orientation. + */ + boolean hasInheritedOrientation() { + // To avoid wrong behaviour (e.g. permission dialogs not centered or with wrong size), + // transparent activities inherit orientation from the first opaque activity below only if + // they explicitly define an orientation different from SCREEN_ORIENTATION_UNSPECIFIED. + return isRunning() + && mActivityRecord.getOverrideOrientation() + != SCREEN_ORIENTATION_UNSPECIFIED; + } + + float getInheritedMinAspectRatio() { + return mTransparentPolicyState.mInheritedMinAspectRatio; + } + + float getInheritedMaxAspectRatio() { + return mTransparentPolicyState.mInheritedMaxAspectRatio; + } + + int getInheritedAppCompatState() { + return mTransparentPolicyState.mInheritedAppCompatState; + } + + @Configuration.Orientation + int getInheritedOrientation() { + return mTransparentPolicyState.mInheritedOrientation; + } + + ActivityRecord.CompatDisplayInsets getInheritedCompatDisplayInsets() { + return mTransparentPolicyState.mInheritedCompatDisplayInsets; + } + + void clearInheritedCompatDisplayInsets() { + mTransparentPolicyState.clearInheritedCompatDisplayInsets(); + } + + TransparentPolicyState getTransparentPolicyState() { + return mTransparentPolicyState; + } + + /** + * In case of translucent activities, it consumes the {@link ActivityRecord} of the first opaque + * activity beneath using the given consumer and returns {@code true}. + */ + boolean applyOnOpaqueActivityBelow(@NonNull Consumer<ActivityRecord> consumer) { + return mTransparentPolicyState.applyOnOpaqueActivityBelow(consumer); + } + + @NonNull + Optional<ActivityRecord> getFirstOpaqueActivity() { + return isRunning() ? Optional.of(mTransparentPolicyState.mFirstOpaqueActivity) + : Optional.empty(); + } + + /** + * @return The first not finishing opaque activity beneath the current translucent activity + * if it exists and the strategy is enabled. + */ + Optional<ActivityRecord> findOpaqueNotFinishingActivityBelow() { + return mTransparentPolicyState.findOpaqueNotFinishingActivityBelow(); + } + + // We evaluate the case when the policy should not be applied. + private boolean shouldSkipTransparentPolicy(@Nullable ActivityRecord opaqueActivity) { + if (opaqueActivity == null || opaqueActivity.isEmbedded()) { + // We skip letterboxing if the translucent activity doesn't have any + // opaque activities beneath or the activity below is embedded which + // never has letterbox. + mActivityRecord.recomputeConfiguration(); + return true; + } + if (mActivityRecord.getTask() == null || mActivityRecord.fillsParent() + || mActivityRecord.hasCompatDisplayInsetsWithoutInheritance()) { + return true; + } + return false; + } + + /** Resets the screen size related fields so they can be resolved by requested bounds later. */ + private static void resetTranslucentOverrideConfig(Configuration config) { + // The values for the following properties will be defined during the configuration + // resolution in {@link ActivityRecord#resolveOverrideConfiguration} using the + // properties inherited from the first not finishing opaque activity beneath. + config.orientation = ORIENTATION_UNDEFINED; + config.screenWidthDp = config.compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED; + config.screenHeightDp = config.compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED; + config.smallestScreenWidthDp = config.compatSmallestScreenWidthDp = + SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; + } + + private void inheritConfiguration(ActivityRecord firstOpaque) { + mTransparentPolicyState.inheritFromOpaque(firstOpaque); + } + + /** + * Encapsulate the state for the current translucent activity when the transparent policy + * has started. + */ + static class TransparentPolicyState { + // Aspect ratio value to consider as undefined. + private static final float UNDEFINED_ASPECT_RATIO = 0f; + + @NonNull + private final ActivityRecord mActivityRecord; + + @Configuration.Orientation + private int mInheritedOrientation = ORIENTATION_UNDEFINED; + private float mInheritedMinAspectRatio = UNDEFINED_ASPECT_RATIO; + private float mInheritedMaxAspectRatio = UNDEFINED_ASPECT_RATIO; + + // The app compat state for the opaque activity if any + private int mInheritedAppCompatState = APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN; + + // The CompatDisplayInsets of the opaque activity beneath the translucent one. + @Nullable + private ActivityRecord.CompatDisplayInsets mInheritedCompatDisplayInsets; + + @Nullable + private ActivityRecord mFirstOpaqueActivity; + + /* + * WindowContainerListener responsible to make translucent activities inherit + * constraints from the first opaque activity beneath them. It's null for not + * translucent activities. + */ + @Nullable + private WindowContainerListener mLetterboxConfigListener; + + TransparentPolicyState(@NonNull ActivityRecord activityRecord) { + mActivityRecord = activityRecord; + } + + private void start(@NonNull ActivityRecord firstOpaqueActivity) { + mFirstOpaqueActivity = firstOpaqueActivity; + mFirstOpaqueActivity.mTransparentPolicy + .mDestroyListeners.add(mActivityRecord.mTransparentPolicy); + inheritFromOpaque(firstOpaqueActivity); + final WindowContainer<?> parent = mActivityRecord.getParent(); + mLetterboxConfigListener = WindowContainer.overrideConfigurationPropagation( + mActivityRecord, mFirstOpaqueActivity, + (opaqueConfig, transparentOverrideConfig) -> { + resetTranslucentOverrideConfig(transparentOverrideConfig); + final Rect parentBounds = parent.getWindowConfiguration().getBounds(); + final Rect bounds = transparentOverrideConfig + .windowConfiguration.getBounds(); + final Rect letterboxBounds = opaqueConfig.windowConfiguration.getBounds(); + // We cannot use letterboxBounds directly here because the position relies + // on letterboxing. Using letterboxBounds directly, would produce a + // double offset. + bounds.set(parentBounds.left, parentBounds.top, + parentBounds.left + letterboxBounds.width(), + parentBounds.top + letterboxBounds.height()); + // We need to initialize appBounds to avoid NPE. The actual value will + // be set ahead when resolving the Configuration for the activity. + transparentOverrideConfig.windowConfiguration.setAppBounds(new Rect()); + inheritFromOpaque(mFirstOpaqueActivity); + return transparentOverrideConfig; + }); + } + + private void inheritFromOpaque(@NonNull ActivityRecord opaqueActivity) { + // To avoid wrong behaviour, we're not forcing a specific aspect ratio to activities + // which are not already providing one (e.g. permission dialogs) and presumably also + // not resizable. + if (mActivityRecord.getMinAspectRatio() != UNDEFINED_ASPECT_RATIO) { + mInheritedMinAspectRatio = opaqueActivity.getMinAspectRatio(); + } + if (mActivityRecord.getMaxAspectRatio() != UNDEFINED_ASPECT_RATIO) { + mInheritedMaxAspectRatio = opaqueActivity.getMaxAspectRatio(); + } + mInheritedOrientation = opaqueActivity.getRequestedConfigurationOrientation(); + mInheritedAppCompatState = opaqueActivity.getAppCompatState(); + mInheritedCompatDisplayInsets = opaqueActivity.getCompatDisplayInsets(); + } + + private void reset() { + if (mLetterboxConfigListener != null) { + mLetterboxConfigListener.onRemoved(); + } + mLetterboxConfigListener = null; + mInheritedOrientation = ORIENTATION_UNDEFINED; + mInheritedMinAspectRatio = UNDEFINED_ASPECT_RATIO; + mInheritedMaxAspectRatio = UNDEFINED_ASPECT_RATIO; + mInheritedAppCompatState = APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN; + mInheritedCompatDisplayInsets = null; + if (mFirstOpaqueActivity != null) { + mFirstOpaqueActivity.mTransparentPolicy + .mDestroyListeners.remove(mActivityRecord.mTransparentPolicy); + } + mFirstOpaqueActivity = null; + } + + private boolean isRunning() { + return mLetterboxConfigListener != null; + } + + private void clearInheritedCompatDisplayInsets() { + mInheritedCompatDisplayInsets = null; + } + + /** + * @return The first not finishing opaque activity beneath the current translucent activity + * if it exists and the strategy is enabled. + */ + private Optional<ActivityRecord> findOpaqueNotFinishingActivityBelow() { + if (!isRunning() || mActivityRecord.getTask() == null) { + return Optional.empty(); + } + return Optional.ofNullable(mFirstOpaqueActivity); + } + + /** + * In case of translucent activities, it consumes the {@link ActivityRecord} of the first + * opaque activity beneath using the given consumer and returns {@code true}. + */ + private boolean applyOnOpaqueActivityBelow(@NonNull Consumer<ActivityRecord> consumer) { + return findOpaqueNotFinishingActivityBelow() + .map(activityRecord -> { + consumer.accept(activityRecord); + return true; + }).orElse(false); + } + } + +} diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index edbba9244738..70143bae9fb0 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -1077,9 +1077,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< if (dc != null && dc != this) { dc.getPendingTransaction().merge(mPendingTransaction); } - if (dc != this && mLocalInsetsSources != null) { - mLocalInsetsSources.clear(); - } for (int i = mChildren.size() - 1; i >= 0; --i) { final WindowContainer child = mChildren.get(i); child.onDisplayChanged(dc); diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 7eda53f2e28e..72109d34ec8a 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -23,8 +23,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS; import static android.view.Display.DEFAULT_DISPLAY; import static android.window.TaskFragmentOperation.OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS; -import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT; import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE; +import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT; import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT; import static android.window.TaskFragmentOperation.OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE; import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_BOTTOM_OF_TASK; @@ -1595,11 +1595,31 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub break; } case OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE: { - taskFragment.getTask().moveOrCreateDecorSurfaceFor(taskFragment); + final Task task = taskFragment.getTask(); + if (task == null) { + break; + } + // If any TaskFragment in the Task is collected by the transition, we make the decor + // surface visible in sync with the TaskFragment transition. Otherwise, we make the + // decor surface visible immediately. + final TaskFragment syncTaskFragment = transition != null + ? task.getTaskFragment(transition.mParticipants::contains) + : null; + + if (syncTaskFragment != null) { + task.moveOrCreateDecorSurfaceFor(taskFragment, false /* visible */); + task.setDecorSurfaceVisible(syncTaskFragment.getSyncTransaction()); + } else { + task.moveOrCreateDecorSurfaceFor(taskFragment, true /* visible */); + } break; } case OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE: { - taskFragment.getTask().removeDecorSurface(); + final Task task = taskFragment.getTask(); + if (task == null) { + break; + } + task.removeDecorSurface(); break; } case OP_TYPE_SET_DIM_ON_TASK: { @@ -1627,21 +1647,15 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub clientTransaction.sanitize(caller.mPid, caller.mUid); } - if (transition != null) { - // The decor surface boost/unboost must happen after the transition is - // completed. Otherwise, the decor surface could be moved before Shell - // completes the transition, causing flicker. - transition.addTransitionEndedListener(() -> - task.setDecorSurfaceBoosted( - taskFragment, - operation.getBooleanValue() /* isBoosted */, - clientTransaction)); - } else { - task.setDecorSurfaceBoosted( - taskFragment, - operation.getBooleanValue() /* isBoosted */, - clientTransaction); - } + task.requestDecorSurfaceBoosted( + taskFragment, + operation.getBooleanValue() /* isBoosted */, + clientTransaction); + + // The decor surface boost/unboost must be applied after the transition is + // completed. Otherwise, the decor surface could be moved before Shell completes + // the transition, causing flicker. + runAfterTransition(transition, task::commitDecorSurfaceBoostedState); } break; } @@ -1654,6 +1668,19 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub return effects; } + /** + * Executes the provided {@code runnable} after the {@code transition}. If the + * {@code transition} is {@code null}, the {@code runnable} is executed immediately. + */ + private static void runAfterTransition( + @Nullable Transition transition, @NonNull Runnable runnable) { + if (transition == null) { + runnable.run(); + } else { + transition.addTransitionEndedListener(runnable); + } + } + private boolean validateTaskFragmentOperation( @NonNull WindowContainerTransaction.HierarchyOp hop, @Nullable IBinder errorCallbackToken, @Nullable ITaskFragmentOrganizer organizer) { @@ -1835,7 +1862,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub task.getParent().positionChildAt( hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM, - task, false /* includingParents */); + task, hop.includingParents()); } return TRANSACT_EFFECTS_LIFECYCLE; } @@ -2361,6 +2388,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub position = POSITION_TOP; } ownerTask.addChild(taskFragment, position); + EventLogTags.writeWmTfCreated(System.identityHashCode(taskFragment), ownerTask.mTaskId); taskFragment.setWindowingMode(creationParams.getWindowingMode()); if (!creationParams.getInitialRelativeBounds().isEmpty()) { // The surface operations for the task fragment should sync with the transition. diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index a7b3f4fad399..dcd4bd68c3fc 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1814,9 +1814,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (mInsetsSourceProviders == null) { return false; } + final @InsetsType int decorInsetsTypes = + mWmService.mConfigTypes | mWmService.mOverrideConfigTypes; for (int i = mInsetsSourceProviders.size() - 1; i >= 0; i--) { final InsetsSource source = mInsetsSourceProviders.valueAt(i).getSource(); - if ((source.getType() & mWmService.mConfigTypes) != 0) { + if ((source.getType() & decorInsetsTypes) != 0) { return true; } } diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd index 610b502f2a07..eeb8b9b0b469 100644 --- a/services/core/xsd/display-device-config/display-device-config.xsd +++ b/services/core/xsd/display-device-config/display-device-config.xsd @@ -779,6 +779,21 @@ </xs:complexType> <xs:complexType name="blockingZoneConfig"> + <!-- list of supported modes for blocking zone . Each point corresponds to one mode. + Supported only for lowerBlockingZoneConfigs + Mode format is : first = refreshRate, second = vsyncRate. E.g. : + <supportedModes> + <point> + <first>60</first> // refreshRate + <second>60</second> //vsyncRate + </point> + .... + </supportedModes> + --> + <xs:element type="nonNegativeFloatToFloatMap" name="supportedModes" minOccurs="0"> + <xs:annotation name="nullable"/> + <xs:annotation name="final"/> + </xs:element> <xs:element name="defaultRefreshRate" type="xs:nonNegativeInteger" minOccurs="1" maxOccurs="1"> <xs:annotation name="final"/> diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt index 203a6d99dba1..757b23a2df7e 100644 --- a/services/core/xsd/display-device-config/schema/current.txt +++ b/services/core/xsd/display-device-config/schema/current.txt @@ -35,9 +35,11 @@ package com.android.server.display.config { method public final com.android.server.display.config.BlockingZoneThreshold getBlockingZoneThreshold(); method public final java.math.BigInteger getDefaultRefreshRate(); method @Nullable public final String getRefreshRateThermalThrottlingId(); + method @Nullable public final com.android.server.display.config.NonNegativeFloatToFloatMap getSupportedModes(); method public final void setBlockingZoneThreshold(com.android.server.display.config.BlockingZoneThreshold); method public final void setDefaultRefreshRate(java.math.BigInteger); method public final void setRefreshRateThermalThrottlingId(@Nullable String); + method public final void setSupportedModes(@Nullable com.android.server.display.config.NonNegativeFloatToFloatMap); } public class BlockingZoneThreshold { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java index a0ea4e9b94f4..901cafa70d53 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java @@ -240,7 +240,7 @@ final class PolicyDefinition<V> { POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_INHERITABLE | POLICY_FLAG_NON_COEXISTABLE_POLICY | POLICY_FLAG_SKIP_ENFORCEMENT_IF_UNCHANGED, - PolicyEnforcerCallbacks::noOp, + PolicyEnforcerCallbacks::setApplicationRestrictions, new BundlePolicySerializer()); /** 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 3bdcd9b0fdcd..161a8168d993 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 @@ -246,24 +246,32 @@ class AppOpService(private val service: AccessCheckingService) : AppOpsCheckingS } override fun setUidMode(uid: Int, deviceId: String, code: Int, mode: Int): Boolean { + val appId = UserHandle.getAppId(uid) + val userId = UserHandle.getUserId(uid) + val appOpName = AppOpsManager.opToPublicName(code) + if ( Flags.runtimePermissionAppopsMappingEnabled() && code in runtimeAppOpToPermissionNames ) { - Slog.w( - LOG_TAG, - "Cannot set UID mode for runtime permission app op, " + - " callingUid = ${Binder.getCallingUid()}, " + + val oldMode = + service.getState { with(appIdPolicy) { getAppOpMode(appId, userId, appOpName) } } + val wouldHaveChanged = oldMode != mode + val logMessage = + (if (wouldHaveChanged) "Blocked" else "Ignored") + + " setUidMode call for runtime permission app op:" + " uid = $uid," + " code = ${AppOpsManager.opToName(code)}," + - " mode = ${AppOpsManager.modeToName(mode)}", - RuntimeException() - ) + " mode = ${AppOpsManager.modeToName(mode)}," + + " callingUid = ${Binder.getCallingUid()}," + + " oldMode = ${AppOpsManager.modeToName(oldMode)}" + if (wouldHaveChanged) { + Slog.e(LOG_TAG, logMessage, RuntimeException()) + } else { + Slog.w(LOG_TAG, logMessage) + } return false } - val appId = UserHandle.getAppId(uid) - val userId = UserHandle.getUserId(uid) - val appOpName = AppOpsManager.opToPublicName(code) var wasChanged: Boolean service.mutateState { wasChanged = with(appIdPolicy) { setAppOpMode(appId, userId, appOpName, mode) } diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt index d3072000a56e..bb0838db97b5 100644 --- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt +++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt @@ -1277,10 +1277,11 @@ class AppIdPermissionPolicy : SchemePolicy() { permissionName ) else -> - permissionAllowlist.getProductSignatureAppAllowlistState( - packageName, - permissionName - ) + permissionAllowlist.getApexSignatureAppAllowlistState(packageName, permissionName) + ?: permissionAllowlist.getProductSignatureAppAllowlistState( + packageName, + permissionName + ) ?: permissionAllowlist.getVendorSignatureAppAllowlistState( packageName, permissionName diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java index 33bf4bd1cc02..cd70ed23a824 100644 --- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java +++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java @@ -25,6 +25,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.hardware.camera2.CameraManager; import android.os.Handler; import android.os.IBinder.DeathRecipient; import android.os.Looper; @@ -258,6 +259,7 @@ public final class ProfcollectForwardingService extends SystemService { BackgroundThread.get().getThreadHandler().post( () -> { registerAppLaunchObserver(); + registerCameraOpenObserver(); registerDex2oatObserver(); registerOTAObserver(); }); @@ -321,16 +323,14 @@ public final class ProfcollectForwardingService extends SystemService { "dex2oat_trace_freq", 25); int randomNum = ThreadLocalRandom.current().nextInt(100); if (randomNum < traceFrequency) { - BackgroundThread.get().getThreadHandler().post(() -> { + // Dex2oat could take a while before it starts. Add a short delay before start tracing. + BackgroundThread.get().getThreadHandler().postDelayed(() -> { try { - // Dex2oat could take a while before it starts. Add a short delay before start - // tracing. - Thread.sleep(1000); mIProfcollect.trace_once("dex2oat"); - } catch (RemoteException | InterruptedException e) { + } catch (RemoteException e) { Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage()); } - }); + }, 1000); } } @@ -371,4 +371,36 @@ public final class ProfcollectForwardingService extends SystemService { pfs.getContext().sendBroadcast(intent); }); } + + private void registerCameraOpenObserver() { + CameraManager cm = getContext().getSystemService(CameraManager.class); + cm.registerAvailabilityCallback(new CameraManager.AvailabilityCallback() { + @Override + public void onCameraOpened(String cameraId, String packageId) { + Log.d(LOG_TAG, "Received camera open event from: " + packageId); + // Skip face auth and Android System Intelligence, since they trigger way too + // often. + if (packageId.startsWith("client.pid") + || packageId.equals("com.google.android.as")) { + return; + } + // Sample for a fraction of camera events. + final int traceFrequency = + DeviceConfig.getInt(DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT, + "camera_trace_freq", 10); + int randomNum = ThreadLocalRandom.current().nextInt(100); + if (randomNum >= traceFrequency) { + return; + } + // Wait for 1s before starting tracing. + BackgroundThread.get().getThreadHandler().postDelayed(() -> { + try { + mIProfcollect.trace_once("camera"); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage()); + } + }, 1000); + } + }, null); + } } diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java index 46d08b0ce018..9a25b1acfaae 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java @@ -948,6 +948,22 @@ public final class DisplayDeviceConfigTest { assertThat(supportedModeData.vsyncRate).isEqualTo(120); } + @Test + public void testLowLightBlockingZoneSupportedModesFromConfigFile() throws IOException { + setupDisplayDeviceConfigFromDisplayConfigFile(); + + RefreshRateData refreshRateData = mDisplayDeviceConfig.getRefreshRateData(); + assertNotNull(refreshRateData); + assertThat(refreshRateData.lowLightBlockingZoneSupportedModes).hasSize(2); + SupportedModeData supportedModeData = + refreshRateData.lowLightBlockingZoneSupportedModes.get(0); + assertThat(supportedModeData.refreshRate).isEqualTo(60); + assertThat(supportedModeData.vsyncRate).isEqualTo(60); + supportedModeData = refreshRateData.lowLightBlockingZoneSupportedModes.get(1); + assertThat(supportedModeData.refreshRate).isEqualTo(240); + assertThat(supportedModeData.vsyncRate).isEqualTo(240); + } + private String getValidLuxThrottling() { return "<luxThrottling>\n" + " <brightnessLimitMap>\n" @@ -1117,6 +1133,19 @@ public final class DisplayDeviceConfigTest { + "</lowPowerSupportedModes>\n"; } + private String getLowLightVrrSupportedModesConfig() { + return "<supportedModes>\n" + + " <point>\n" + + " <first>60</first>\n" + + " <second>60</second>\n" + + " </point>\n" + + " <point>\n" + + " <first>240</first>\n" + + " <second>240</second>\n" + + " </point>\n" + + "</supportedModes>\n"; + } + private String getHdrBrightnessConfig() { return "<hdrBrightnessConfig>\n" + " <brightnessMap>\n" @@ -1624,6 +1653,7 @@ public final class DisplayDeviceConfigTest { + "<nits>-1</nits>\n" + "</displayBrightnessPoint>\n" + "</blockingZoneThreshold>\n" + + getLowLightVrrSupportedModesConfig() + "</lowerBlockingZoneConfigs>\n" + "<higherBlockingZoneConfigs>\n" + "<defaultRefreshRate>90</defaultRefreshRate>\n" diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java index 8fd1e6baf522..efa224f28c8c 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java @@ -39,6 +39,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.app.ActivityManager; @@ -1284,14 +1285,37 @@ public final class DisplayPowerControllerTest { @Test public void testDwbcCallsHappenOnHandler() { + when(mDisplayManagerFlagsMock.isAdaptiveTone1Enabled()).thenReturn(true); mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); + // Send a display power request + DisplayPowerRequest dpr = new DisplayPowerRequest(); + dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; + dpr.useProximitySensor = true; + mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); + + // Run updatePowerState + advanceTime(1); + + setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), + mHolder.config, /* isEnabled= */ true); + + // dispatch handler looper + advanceTime(1); + clearInvocations(mDisplayWhiteBalanceControllerMock, mHolder.automaticBrightnessController, + mHolder.animator); mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE); - verify(mDisplayWhiteBalanceControllerMock, never()).setStrongModeEnabled(true); + verifyNoMoreInteractions(mDisplayWhiteBalanceControllerMock, + mHolder.automaticBrightnessController, + mHolder.animator); // dispatch handler looper advanceTime(1); - verify(mDisplayWhiteBalanceControllerMock, times(1)).setStrongModeEnabled(true); + verify(mHolder.automaticBrightnessController).switchMode(AUTO_BRIGHTNESS_MODE_IDLE, + /* sendUpdate= */ true); + verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX_IDLE, + BRIGHTNESS_RAMP_DECREASE_MAX_IDLE); + verify(mDisplayWhiteBalanceControllerMock).setStrongModeEnabled(true); } @Test @@ -1506,6 +1530,9 @@ public final class DisplayPowerControllerTest { // switch to idle mode mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE); + // Process the MSG_SWITCH_AUTOBRIGHTNESS_MODE event + advanceTime(1); + // A second time when switching to idle mode. verify(mHolder.animator, times(2)).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX, BRIGHTNESS_RAMP_DECREASE_MAX); @@ -1532,6 +1559,8 @@ public final class DisplayPowerControllerTest { // switch to idle mode mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE); + // Process the MSG_SWITCH_AUTOBRIGHTNESS_MODE event + advanceTime(1); verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX_IDLE, BRIGHTNESS_RAMP_DECREASE_MAX_IDLE); } diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java index 323ef6a28e14..88d3238861f5 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java @@ -33,6 +33,7 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; import android.hardware.SensorManager; +import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; import android.os.Handler; import android.os.HandlerExecutor; @@ -119,7 +120,8 @@ public final class DisplayBrightnessControllerTest { int targetDisplayState = Display.STATE_DOZE; when(mDisplayBrightnessStrategySelector.selectStrategy( any(StrategySelectionRequest.class))).thenReturn(displayBrightnessStrategy); - mDisplayBrightnessController.updateBrightness(displayPowerRequest, targetDisplayState); + mDisplayBrightnessController.updateBrightness(displayPowerRequest, targetDisplayState, mock( + DisplayManagerInternal.DisplayOffloadSession.class)); verify(displayBrightnessStrategy).updateBrightness( eq(new StrategyExecutionRequest(displayPowerRequest, DEFAULT_BRIGHTNESS, /* userSetBrightnessChanged= */ false))); @@ -128,6 +130,12 @@ public final class DisplayBrightnessControllerTest { } @Test + public void isAllowAutoBrightnessWhileDozingDelegatesToDozeBrightnessStrategy() { + mDisplayBrightnessController.isAllowAutoBrightnessWhileDozing(); + verify(mDisplayBrightnessStrategySelector).isAllowAutoBrightnessWhileDozing(); + } + + @Test public void isAllowAutoBrightnessWhileDozingConfigDelegatesToDozeBrightnessStrategy() { mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig(); verify(mDisplayBrightnessStrategySelector).isAllowAutoBrightnessWhileDozingConfig(); diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java index df9671235071..639d06d21510 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java @@ -16,13 +16,15 @@ package com.android.server.display.brightness; +import static junit.framework.Assert.assertFalse; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import android.content.ContentResolver; @@ -97,6 +99,9 @@ public final class DisplayBrightnessStrategySelectorTest { @Mock private DisplayManagerFlags mDisplayManagerFlags; + @Mock + private DisplayManagerInternal.DisplayOffloadSession mDisplayOffloadSession; + private DisplayBrightnessStrategySelector mDisplayBrightnessStrategySelector; private Context mContext; private DisplayBrightnessStrategySelector.Injector mInjector = @@ -191,7 +196,7 @@ public final class DisplayBrightnessStrategySelectorTest { DISALLOW_AUTO_BRIGHTNESS_WHILE_DOZING); assertEquals(mDisplayBrightnessStrategySelector.selectStrategy( new StrategySelectionRequest(displayPowerRequest, Display.STATE_DOZE, - 0.1f, false)), + 0.1f, false, mDisplayOffloadSession)), mDozeBrightnessModeStrategy); } @@ -205,7 +210,30 @@ public final class DisplayBrightnessStrategySelectorTest { DISALLOW_AUTO_BRIGHTNESS_WHILE_DOZING); assertNotEquals(mDisplayBrightnessStrategySelector.selectStrategy( new StrategySelectionRequest(displayPowerRequest, Display.STATE_DOZE, - 0.1f, false)), + 0.1f, false, mDisplayOffloadSession)), + mDozeBrightnessModeStrategy); + } + + @Test + public void selectStrategyDoesNotSelectDozeStrategyWhenOffloadSessionAutoBrightnessIsEnabled() { + when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true); + when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true); + when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true); + when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn( + true); + when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn( + true); + + mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext, + mInjector, DISPLAY_ID, mDisplayManagerFlags); + DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock( + DisplayManagerInternal.DisplayPowerRequest.class); + displayPowerRequest.policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE; + displayPowerRequest.dozeScreenBrightness = 0.2f; + + assertNotEquals(mDisplayBrightnessStrategySelector.selectStrategy( + new StrategySelectionRequest(displayPowerRequest, Display.STATE_DOZE, + 0.1f, false, mDisplayOffloadSession)), mDozeBrightnessModeStrategy); } @@ -215,7 +243,7 @@ public final class DisplayBrightnessStrategySelectorTest { DisplayManagerInternal.DisplayPowerRequest.class); assertEquals(mDisplayBrightnessStrategySelector.selectStrategy( new StrategySelectionRequest(displayPowerRequest, Display.STATE_OFF, - 0.1f, false)), + 0.1f, false, mDisplayOffloadSession)), mScreenOffBrightnessModeStrategy); } @@ -227,7 +255,7 @@ public final class DisplayBrightnessStrategySelectorTest { when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(Float.NaN); assertEquals(mDisplayBrightnessStrategySelector.selectStrategy( new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON, - 0.1f, false)), + 0.1f, false, mDisplayOffloadSession)), mOverrideBrightnessStrategy); } @@ -240,7 +268,7 @@ public final class DisplayBrightnessStrategySelectorTest { when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(0.3f); assertEquals(mDisplayBrightnessStrategySelector.selectStrategy( new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON, - 0.1f, false)), + 0.1f, false, mDisplayOffloadSession)), mTemporaryBrightnessStrategy); } @@ -254,7 +282,7 @@ public final class DisplayBrightnessStrategySelectorTest { when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(Float.NaN); assertEquals(mDisplayBrightnessStrategySelector.selectStrategy( new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON, - 0.1f, false)), + 0.1f, false, mDisplayOffloadSession)), mBoostBrightnessStrategy); } @@ -268,7 +296,7 @@ public final class DisplayBrightnessStrategySelectorTest { when(mOffloadBrightnessStrategy.getOffloadScreenBrightness()).thenReturn(Float.NaN); assertEquals(mDisplayBrightnessStrategySelector.selectStrategy( new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON, - 0.1f, false)), + 0.1f, false, mDisplayOffloadSession)), mInvalidBrightnessStrategy); } @@ -279,7 +307,7 @@ public final class DisplayBrightnessStrategySelectorTest { when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(0.3f); assertEquals(mDisplayBrightnessStrategySelector.selectStrategy( new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON, - 0.1f, false)), + 0.1f, false, mDisplayOffloadSession)), mFollowerBrightnessStrategy); } @@ -297,13 +325,18 @@ public final class DisplayBrightnessStrategySelectorTest { when(mOffloadBrightnessStrategy.getOffloadScreenBrightness()).thenReturn(0.3f); assertEquals(mDisplayBrightnessStrategySelector.selectStrategy( new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON, - 0.1f, false)), + 0.1f, false, mDisplayOffloadSession)), mOffloadBrightnessStrategy); } @Test public void selectStrategy_selectsAutomaticStrategyWhenValid() { when(mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()).thenReturn(true); + when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true); + when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true); + when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true); + when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn( + true); mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext, mInjector, DISPLAY_ID, mDisplayManagerFlags); DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock( @@ -316,13 +349,11 @@ public final class DisplayBrightnessStrategySelectorTest { when(mAutomaticBrightnessStrategy.isAutoBrightnessValid()).thenReturn(true); assertEquals(mDisplayBrightnessStrategySelector.selectStrategy( new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON, - 0.1f, false)), + 0.1f, false, mDisplayOffloadSession)), mAutomaticBrightnessStrategy); - verifyZeroInteractions(mOffloadBrightnessStrategy); verify(mAutomaticBrightnessStrategy).setAutoBrightnessState(Display.STATE_ON, - false, BrightnessReason.REASON_UNKNOWN, + true, BrightnessReason.REASON_UNKNOWN, DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT, 0.1f, false); - } @Test @@ -341,7 +372,7 @@ public final class DisplayBrightnessStrategySelectorTest { when(mAutoBrightnessFallbackStrategy.isValid()).thenReturn(true); assertEquals(mDisplayBrightnessStrategySelector.selectStrategy( new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON, - 0.1f, false)), + 0.1f, false, mDisplayOffloadSession)), mAutoBrightnessFallbackStrategy); } @@ -359,7 +390,7 @@ public final class DisplayBrightnessStrategySelectorTest { assertNotEquals(mOffloadBrightnessStrategy, mDisplayBrightnessStrategySelector.selectStrategy( new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON, - 0.1f, false))); + 0.1f, false, mDisplayOffloadSession))); } @Test @@ -377,7 +408,7 @@ public final class DisplayBrightnessStrategySelectorTest { when(mAutomaticBrightnessStrategy.isAutoBrightnessValid()).thenReturn(false); assertEquals(mDisplayBrightnessStrategySelector.selectStrategy( new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON, - 0.1f, false)), + 0.1f, false, mDisplayOffloadSession)), mFallbackBrightnessStrategy); } @@ -392,7 +423,7 @@ public final class DisplayBrightnessStrategySelectorTest { mDisplayBrightnessStrategySelector.selectStrategy( new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON, - 0.1f, false)); + 0.1f, false, mDisplayOffloadSession)); StrategySelectionNotifyRequest strategySelectionNotifyRequest = new StrategySelectionNotifyRequest(displayPowerRequest, Display.STATE_ON, @@ -422,4 +453,78 @@ public final class DisplayBrightnessStrategySelectorTest { assertEquals(mAutomaticBrightnessStrategy, mDisplayBrightnessStrategySelector.getAutomaticBrightnessStrategy()); } + + @Test + public void setAllowAutoBrightnessWhileDozing_enabledWhenConfigAndOffloadSessionAreEnabled() { + when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true); + when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true); + when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true); + when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn( + true); + mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext, + mInjector, DISPLAY_ID, mDisplayManagerFlags); + mDisplayBrightnessStrategySelector + .setAllowAutoBrightnessWhileDozing(mDisplayOffloadSession); + assertTrue(mDisplayBrightnessStrategySelector.isAllowAutoBrightnessWhileDozing()); + } + + @Test + public void setAllowAutoBrightnessWhileDozing_disabledWhenOffloadSessionFlagIsDisabled() { + when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true); + when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true); + when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(false); + when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn( + true); + mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext, + mInjector, DISPLAY_ID, mDisplayManagerFlags); + mDisplayBrightnessStrategySelector + .setAllowAutoBrightnessWhileDozing(mDisplayOffloadSession); + assertFalse(mDisplayBrightnessStrategySelector.isAllowAutoBrightnessWhileDozing()); + } + + @Test + public void setAllowAutoBrightnessWhileDozing_disabledWhenABWhileDozingConfigIsDisabled() { + when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true); + when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true); + when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true); + when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn( + false); + mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext, + mInjector, DISPLAY_ID, mDisplayManagerFlags); + mDisplayBrightnessStrategySelector + .setAllowAutoBrightnessWhileDozing(mDisplayOffloadSession); + assertFalse(mDisplayBrightnessStrategySelector.isAllowAutoBrightnessWhileDozing()); + } + + @Test + public void setAllowAutoBrightnessWhileDozing_EnabledWhenOffloadSessionIsNotSet() { + when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn( + true); + mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext, + mInjector, DISPLAY_ID, mDisplayManagerFlags); + mDisplayBrightnessStrategySelector.setAllowAutoBrightnessWhileDozing(null); + assertTrue(mDisplayBrightnessStrategySelector.isAllowAutoBrightnessWhileDozing()); + } + + @Test + public void setAllowAutoBrightnessWhileDozing_EnabledWhenFlagsAreDisabled() { + when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true); + when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn( + true); + mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext, + mInjector, DISPLAY_ID, mDisplayManagerFlags); + + // Same as the config_allowAutoBrightnessWhileDozing when either of the concerned flags + // are disabled + when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(false); + mDisplayBrightnessStrategySelector + .setAllowAutoBrightnessWhileDozing(mDisplayOffloadSession); + assertTrue(mDisplayBrightnessStrategySelector.isAllowAutoBrightnessWhileDozing()); + + when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true); + when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(false); + mDisplayBrightnessStrategySelector + .setAllowAutoBrightnessWhileDozing(mDisplayOffloadSession); + assertTrue(mDisplayBrightnessStrategySelector.isAllowAutoBrightnessWhileDozing()); + } } diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/BrightnessObserverTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/BrightnessObserverTest.kt index 88c0daaffcd2..95702aa1bce1 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/mode/BrightnessObserverTest.kt +++ b/services/tests/displayservicetests/src/com/android/server/display/mode/BrightnessObserverTest.kt @@ -19,11 +19,12 @@ package com.android.server.display.mode import android.content.Context import android.content.ContextWrapper import android.hardware.display.BrightnessInfo -import android.util.SparseArray import android.view.Display import androidx.test.core.app.ApplicationProvider import androidx.test.filters.SmallTest import com.android.server.display.DisplayDeviceConfig +import com.android.server.display.config.RefreshRateData +import com.android.server.display.config.SupportedModeData import com.android.server.display.feature.DisplayManagerFlags import com.android.server.display.mode.DisplayModeDirector.DisplayDeviceConfigProvider import com.android.server.testutils.TestHandler @@ -39,6 +40,13 @@ import org.mockito.junit.MockitoJUnit import org.mockito.kotlin.mock import org.mockito.kotlin.whenever +private val LOW_LIGHT_REFRESH_RATE_DATA = createRefreshRateData( + lowLightBlockingZoneSupportedModes = listOf( + SupportedModeData(60f, 60f), SupportedModeData(240f, 240f))) +private val EXPECTED_SUPPORTED_MODES_VOTE = SupportedRefreshRatesVote( + listOf(SupportedRefreshRatesVote.RefreshRates(60f, 60f), + SupportedRefreshRatesVote.RefreshRates(240f, 240f))) + @SmallTest @RunWith(TestParameterInjector::class) class BrightnessObserverTest { @@ -65,21 +73,25 @@ class BrightnessObserverTest { whenever(mockFlags.isVsyncLowLightVoteEnabled).thenReturn(testCase.vsyncLowLightVoteEnabled) val displayModeDirector = DisplayModeDirector( spyContext, testHandler, mockInjector, mockFlags, mockDisplayDeviceConfigProvider) - val ddcByDisplay = SparseArray<DisplayDeviceConfig>() whenever(mockDeviceConfig.isVrrSupportEnabled).thenReturn(testCase.vrrSupported) - ddcByDisplay.put(Display.DEFAULT_DISPLAY, mockDeviceConfig) - displayModeDirector.injectDisplayDeviceConfigByDisplay(ddcByDisplay) + whenever(mockDeviceConfig.refreshRateData).thenReturn(testCase.refreshRateData) + whenever(mockDeviceConfig.defaultLowBlockingZoneRefreshRate).thenReturn(-1) + + displayModeDirector.defaultDisplayDeviceUpdated(mockDeviceConfig) + val brightnessObserver = displayModeDirector.BrightnessObserver( spyContext, testHandler, mockInjector, mockFlags) - + // set mRefreshRateChangeable to true brightnessObserver.onRefreshRateSettingChangedLocked(0.0f, 120.0f) brightnessObserver.updateBlockingZoneThresholds(mockDeviceConfig, false) - brightnessObserver.onDeviceConfigRefreshRateInLowZoneChanged(60) + brightnessObserver.onDeviceConfigRefreshRateInLowZoneChanged(testCase.refreshRateInLowZone) brightnessObserver.onDisplayChanged(Display.DEFAULT_DISPLAY) assertThat(displayModeDirector.getVote(VotesStorage.GLOBAL_ID, - Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH)).isEqualTo(testCase.expectedVote) + Vote.PRIORITY_FLICKER_REFRESH_RATE)).isEqualTo(testCase.expectedRefreshRateVote) + assertThat(displayModeDirector.getVote(VotesStorage.GLOBAL_ID, + Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH)).isEqualTo(testCase.expectedSwitchVote) } private fun setUpLowBrightnessZone() { @@ -98,14 +110,20 @@ class BrightnessObserverTest { enum class LowLightTestCase( val vrrSupported: Boolean, val vsyncLowLightVoteEnabled: Boolean, - internal val expectedVote: Vote + val refreshRateData: RefreshRateData, + val refreshRateInLowZone: Int, + internal val expectedRefreshRateVote: Vote, + internal val expectedSwitchVote: Vote?, ) { - ALL_ENABLED(true, true, CombinedVote( - listOf(DisableRefreshRateSwitchingVote(true), - SupportedRefreshRatesVote( - listOf(SupportedRefreshRatesVote.RefreshRates(60f, 60f), - SupportedRefreshRatesVote.RefreshRates(120f, 120f)))))), - VRR_NOT_SUPPORTED(false, true, DisableRefreshRateSwitchingVote(true)), - VSYNC_VOTE_DISABLED(true, false, DisableRefreshRateSwitchingVote(true)) + ALL_ENABLED(true, true, LOW_LIGHT_REFRESH_RATE_DATA, 60, + EXPECTED_SUPPORTED_MODES_VOTE, null), + ALL_ENABLED_NO_RR_IN_LOW_ZONE(true, true, LOW_LIGHT_REFRESH_RATE_DATA, 0, + EXPECTED_SUPPORTED_MODES_VOTE, null), + VRR_NOT_SUPPORTED(false, true, LOW_LIGHT_REFRESH_RATE_DATA, 60, + Vote.forPhysicalRefreshRates(60f, 60f), DisableRefreshRateSwitchingVote(true)), + VSYNC_VOTE_DISABLED(true, false, LOW_LIGHT_REFRESH_RATE_DATA, 50, + Vote.forPhysicalRefreshRates(50f, 50f), DisableRefreshRateSwitchingVote(true)), + NO_LOW_LIGHT_CONFIG(true, true, createRefreshRateData(), 40, + Vote.forPhysicalRefreshRates(40f, 40f), DisableRefreshRateSwitchingVote(true)), } }
\ No newline at end of file diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java index 714b423fae70..242d5593c3c8 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java @@ -132,7 +132,8 @@ public class DisplayModeDirectorTest { /* defaultPeakRefreshRate= */ 0, /* defaultRefreshRateInHbmHdr= */ 0, /* defaultRefreshRateInHbmSunlight= */ 0, - /* lowPowerSupportedModes =*/ List.of()); + /* lowPowerSupportedModes= */ List.of(), + /* lowLightBlockingZoneSupportedModes= */ List.of()); public static Collection<Object[]> getAppRequestedSizeTestCases() { var appRequestedSizeTestCases = Arrays.asList(new Object[][] { @@ -3170,7 +3171,8 @@ public class DisplayModeDirectorTest { /* defaultPeakRefreshRate= */ 65, /* defaultRefreshRateInHbmHdr= */ 65, /* defaultRefreshRateInHbmSunlight= */ 75, - /* lowPowerSupportedModes= */ List.of()); + /* lowPowerSupportedModes= */ List.of(), + /* lowLightBlockingZoneSupportedModes= */ List.of()); when(displayDeviceConfig.getRefreshRateData()).thenReturn(refreshRateData); when(displayDeviceConfig.getDefaultLowBlockingZoneRefreshRate()).thenReturn(50); when(displayDeviceConfig.getDefaultHighBlockingZoneRefreshRate()).thenReturn(55); diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/TestUtils.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/TestUtils.kt index 1206e30b9e88..5b07166d63e4 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/mode/TestUtils.kt +++ b/services/tests/displayservicetests/src/com/android/server/display/mode/TestUtils.kt @@ -34,9 +34,10 @@ fun createRefreshRateData( defaultPeakRefreshRate: Int = 60, defaultRefreshRateInHbmHdr: Int = 60, defaultRefreshRateInHbmSunlight: Int = 60, - lowPowerSupportedModes: List<SupportedModeData> = emptyList() + lowPowerSupportedModes: List<SupportedModeData> = emptyList(), + lowLightBlockingZoneSupportedModes: List<SupportedModeData> = emptyList() ): RefreshRateData { return RefreshRateData(defaultRefreshRate, defaultPeakRefreshRate, defaultRefreshRateInHbmHdr, defaultRefreshRateInHbmSunlight, - lowPowerSupportedModes) + lowPowerSupportedModes, lowLightBlockingZoneSupportedModes) } diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/VotesStorageTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/VotesStorageTest.java index a248d6de118f..0125ddb7b7d9 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/mode/VotesStorageTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/mode/VotesStorageTest.java @@ -38,10 +38,10 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) public class VotesStorageTest { private static final int DISPLAY_ID = 100; - private static final int PRIORITY = Vote.PRIORITY_APP_REQUEST_SIZE; + private static final @Vote.Priority int PRIORITY = Vote.PRIORITY_APP_REQUEST_SIZE; private static final Vote VOTE = Vote.forDisableRefreshRateSwitching(); private static final int DISPLAY_ID_OTHER = 101; - private static final int PRIORITY_OTHER = Vote.PRIORITY_FLICKER_REFRESH_RATE; + private static final @Vote.Priority int PRIORITY_OTHER = Vote.PRIORITY_FLICKER_REFRESH_RATE; private static final Vote VOTE_OTHER = Vote.forBaseModeRefreshRate(10f); @Mock diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java index daa827eacf44..5f126774835d 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java @@ -556,7 +556,7 @@ public final class ServiceBindingOomAdjPolicyTest { rInfo.serviceInfo = makeServiceInfo(compName.getClassName(), compName.getPackageName(), serviceUid); doReturn(rInfo).when(mPackageManagerInt).resolveService(any(Intent.class), any(), - anyLong(), anyInt(), anyInt()); + anyLong(), anyInt(), anyInt(), anyInt()); return serviceIntent; } diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt index 396edae2f672..9ab607de474d 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt +++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt @@ -140,6 +140,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) { PropertyInvalidatedCache.disableForTestMode() val apply = ExtendedMockito.mockitoSession() .strictness(Strictness.LENIENT) + .mockStatic(SaferIntentUtils::class.java) .mockStatic(SystemProperties::class.java) .mockStatic(SystemConfig::class.java) .mockStatic(SELinuxMMAC::class.java, Mockito.CALLS_REAL_METHODS) diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperCropperTest.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperCropperTest.java index 1b0a8d2222b9..f1bf86f2f57c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperCropperTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperCropperTest.java @@ -211,9 +211,11 @@ public class WallpaperCropperTest { new Rect(100, 200, bitmapSize.x - 100, bitmapSize.y))) { for (int mode: ALL_MODES) { for (boolean parallax: List.of(true, false)) { - assertThat(WallpaperCropper.getAdjustedCrop( - crop, bitmapSize, displaySize, parallax, mode)) - .isEqualTo(crop); + for (boolean rtl: List.of(true, false)) { + assertThat(WallpaperCropper.getAdjustedCrop( + crop, bitmapSize, displaySize, parallax, rtl, mode)) + .isEqualTo(crop); + } } } } @@ -234,8 +236,11 @@ public class WallpaperCropperTest { Point expectedCropSize = new Point(expectedWidth, 1000); for (int mode: ALL_MODES) { assertThat(WallpaperCropper.getAdjustedCrop( - crop, bitmapSize, displaySize, true, mode)) - .isEqualTo(centerOf(crop, expectedCropSize)); + crop, bitmapSize, displaySize, true, false, mode)) + .isEqualTo(leftOf(crop, expectedCropSize)); + assertThat(WallpaperCropper.getAdjustedCrop( + crop, bitmapSize, displaySize, true, true, mode)) + .isEqualTo(rightOf(crop, expectedCropSize)); } } @@ -254,9 +259,11 @@ public class WallpaperCropperTest { Point bitmapSize = new Point(acceptableWidth, 1000); Rect crop = new Rect(0, 0, bitmapSize.x, bitmapSize.y); for (int mode : ALL_MODES) { - assertThat(WallpaperCropper.getAdjustedCrop( - crop, bitmapSize, displaySize, true, mode)) - .isEqualTo(crop); + for (boolean rtl : List.of(false, true)) { + assertThat(WallpaperCropper.getAdjustedCrop( + crop, bitmapSize, displaySize, true, rtl, mode)) + .isEqualTo(crop); + } } } } @@ -286,9 +293,11 @@ public class WallpaperCropperTest { for (int i = 0; i < crops.size(); i++) { Rect crop = crops.get(i); Rect expectedCrop = expectedAdjustedCrops.get(i); - assertThat(WallpaperCropper.getAdjustedCrop( - crop, bitmapSize, displaySize, false, WallpaperCropper.ADD)) - .isEqualTo(expectedCrop); + for (boolean rtl: List.of(false, true)) { + assertThat(WallpaperCropper.getAdjustedCrop( + crop, bitmapSize, displaySize, false, rtl, WallpaperCropper.ADD)) + .isEqualTo(expectedCrop); + } } } @@ -309,9 +318,11 @@ public class WallpaperCropperTest { Point expectedCropSize = new Point(1000, 1000); for (Rect crop: crops) { - assertThat(WallpaperCropper.getAdjustedCrop( - crop, bitmapSize, displaySize, false, WallpaperCropper.REMOVE)) - .isEqualTo(centerOf(crop, expectedCropSize)); + for (boolean rtl : List.of(false, true)) { + assertThat(WallpaperCropper.getAdjustedCrop( + crop, bitmapSize, displaySize, false, rtl, WallpaperCropper.REMOVE)) + .isEqualTo(centerOf(crop, expectedCropSize)); + } } } @@ -338,14 +349,14 @@ public class WallpaperCropperTest { Rect crop = crops.get(i); Rect expected = expectedAdjustedCrops.get(i); assertThat(WallpaperCropper.getAdjustedCrop( - crop, bitmapSize, displaySize, false, WallpaperCropper.BALANCE)) + crop, bitmapSize, displaySize, false, false, WallpaperCropper.BALANCE)) .isEqualTo(expected); Rect transposedCrop = new Rect(crop.top, crop.left, crop.bottom, crop.right); Rect expectedTransposed = new Rect( expected.top, expected.left, expected.bottom, expected.right); assertThat(WallpaperCropper.getAdjustedCrop(transposedCrop, bitmapSize, - transposedDisplaySize, false, WallpaperCropper.BALANCE)) + transposedDisplaySize, false, false, WallpaperCropper.BALANCE)) .isEqualTo(expectedTransposed); } } @@ -376,9 +387,11 @@ public class WallpaperCropperTest { Point displaySize = displaySizes.get(i); Point expectedCropSize = expectedCropSizes.get(i); for (boolean rtl : List.of(false, true)) { + Rect expectedCrop = rtl ? rightOf(bitmapRect, expectedCropSize) + : leftOf(bitmapRect, expectedCropSize); assertThat(mWallpaperCropper.getCrop( displaySize, bitmapSize, suggestedCrops, rtl)) - .isEqualTo(centerOf(bitmapRect, expectedCropSize)); + .isEqualTo(expectedCrop); } } } diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java index 851cf4a535a2..976cc18127f0 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java @@ -91,7 +91,7 @@ public class BatteryUsageStatsTest { final Parcel parcel = Parcel.obtain(); parcel.writeParcelable(outBatteryUsageStats, 0); - assertThat(parcel.dataSize()).isLessThan(8000); + assertThat(parcel.dataSize()).isLessThan(10000); parcel.setDataPosition(0); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java index d4f0d5aa7ef6..52b33db556e6 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java @@ -593,12 +593,6 @@ public class ProxyManagerTest { } @Override - public void onMagnificationSystemUIConnectionChanged(boolean connected) - throws RemoteException { - - } - - @Override public void onMagnificationChanged(int displayId, Region region, MagnificationConfig config) throws RemoteException { diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java index 0de5807067e6..87fe6cf8f283 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java @@ -59,7 +59,6 @@ import android.view.accessibility.MagnificationAnimationCallback; import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.FlakyTest; -import com.android.compatibility.common.util.TestUtils; import com.android.internal.util.test.FakeSettingsProvider; import com.android.server.LocalServices; import com.android.server.accessibility.AccessibilityTraceManager; @@ -77,7 +76,6 @@ import org.mockito.invocation.InvocationOnMock; */ public class MagnificationConnectionManagerTest { - private static final int WAIT_CONNECTION_TIMEOUT_SECOND = 1; private static final int CURRENT_USER_ID = UserHandle.USER_SYSTEM; private static final int SERVICE_ID = 1; @@ -117,19 +115,17 @@ public class MagnificationConnectionManagerTest { private void stubSetConnection(boolean needDelay) { doAnswer((InvocationOnMock invocation) -> { final boolean connect = (Boolean) invocation.getArguments()[0]; - // Use post to simulate setConnection() called by another process. - final Context context = ApplicationProvider.getApplicationContext(); + // Simulates setConnection() called by another process. if (needDelay) { + final Context context = ApplicationProvider.getApplicationContext(); context.getMainThreadHandler().postDelayed( () -> { mMagnificationConnectionManager.setConnection( connect ? mMockConnection.getConnection() : null); }, 10); } else { - context.getMainThreadHandler().post(() -> { - mMagnificationConnectionManager.setConnection( - connect ? mMockConnection.getConnection() : null); - }); + mMagnificationConnectionManager.setConnection( + connect ? mMockConnection.getConnection() : null); } return true; }).when(mMockStatusBarManagerInternal).requestMagnificationConnection(anyBoolean()); @@ -633,10 +629,9 @@ public class MagnificationConnectionManagerTest { } @Test - public void isConnected_requestConnection_expectedValue() throws Exception { + public void isConnected_requestConnection_expectedValue() throws RemoteException { mMagnificationConnectionManager.requestConnection(true); - TestUtils.waitUntil("connection is not ready", WAIT_CONNECTION_TIMEOUT_SECOND, - () -> mMagnificationConnectionManager.isConnected()); + assertTrue(mMagnificationConnectionManager.isConnected()); mMagnificationConnectionManager.requestConnection(false); assertFalse(mMagnificationConnectionManager.isConnected()); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java index 40de1b253dea..182d60328440 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java @@ -320,7 +320,7 @@ public class FingerprintAuthenticationClientTest { } @Test - public void luxProbeNotEnabledOnStartWhenNotWake() throws RemoteException { + public void luxProbeDisabledOnStartWhenNotWake() throws RemoteException { luxProbeEnabledOnStart(false /* isAwake */); } @@ -337,6 +337,7 @@ public class FingerprintAuthenticationClientTest { .getValue().toAidlContext()); verify(mLuxProbe, isAwake ? times(1) : never()).enable(); + verify(mLuxProbe, isAwake ? never() : times(1)).disable(); } @Test diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/camera/VirtualCameraControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/camera/VirtualCameraControllerTest.java index 4505a8b88b25..627ca03c8d96 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/camera/VirtualCameraControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/camera/VirtualCameraControllerTest.java @@ -95,7 +95,7 @@ public class VirtualCameraControllerTest { mVirtualCameraController = new VirtualCameraController(mVirtualCameraServiceMock, DEVICE_POLICY_CUSTOM, DEVICE_ID); when(mVirtualCameraServiceMock.registerCamera(any(), any(), anyInt())).thenReturn(true); - when(mVirtualCameraServiceMock.getCameraId(any())).thenReturn(0); + when(mVirtualCameraServiceMock.getCameraId(any())).thenReturn("0"); } @After diff --git a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java index 32bbc7a618d1..6d79ae467bf0 100644 --- a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java @@ -551,7 +551,7 @@ public class ThermalManagerServiceTest { // Add some time-series data for (int i = 1; i < 20; ++i) { - samples.add(0, watcher.createSampleForTesting(1000 * i, 25.0f + 0.5f * i)); + samples.add(watcher.createSampleForTesting(1000 * i, 25.0f + 0.5f * i)); } // Now the forecast should vary depending on how far ahead we are trying to predict diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 89140a2c0b44..1fd8f50b9dec 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -16,10 +16,8 @@ package com.android.server.wm; -import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; import static android.app.Activity.RESULT_CANCELED; import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP; -import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.app.ActivityManager.START_ABORTED; import static android.app.ActivityManager.START_CANCELED; import static android.app.ActivityManager.START_CLASS_NOT_FOUND; @@ -44,7 +42,6 @@ import static android.content.pm.ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBE import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Process.SYSTEM_UID; import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations; @@ -52,7 +49,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; @@ -79,15 +75,12 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyObject; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.notNull; import android.app.ActivityOptions; -import android.app.ActivityOptions.BackgroundActivityStartMode; import android.app.AppOpsManager; -import android.app.BackgroundStartPrivileges; import android.app.IApplicationThread; import android.app.PictureInPictureParams; import android.content.ComponentName; @@ -101,10 +94,8 @@ import android.content.pm.SigningDetails; import android.graphics.Rect; import android.os.Binder; import android.os.IBinder; -import android.os.Process; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; -import android.platform.test.annotations.RequiresFlagsDisabled; import android.provider.DeviceConfig; import android.service.voice.IVoiceInteractionSession; import android.util.Pair; @@ -116,8 +107,6 @@ import android.window.TaskFragmentOrganizerToken; import androidx.test.filters.SmallTest; import com.android.compatibility.common.util.DeviceConfigStateHelper; -import com.android.internal.util.FrameworkStatsLog; -import com.android.server.am.PendingIntentRecord; import com.android.server.pm.PackageArchiver; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.wm.BackgroundActivityStartController.BalVerdict; @@ -126,11 +115,8 @@ import com.android.server.wm.utils.MockTracker; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.MockitoSession; -import org.mockito.quality.Strictness; import java.util.ArrayList; import java.util.Arrays; @@ -416,9 +402,7 @@ public class ActivityStarterTests extends WindowTestsBase { doReturn("packageName").when(mMockPackageManager).getNameForUid(anyInt()); doReturn(false).when(mMockPackageManager).isInstantAppInstallerComponent(any()); doReturn(null).when(mMockPackageManager).resolveIntent(any(), any(), anyLong(), anyLong(), - anyInt(), anyBoolean(), anyInt()); - doReturn(null).when(mMockPackageManager).resolveIntentExported(any(), any(), - anyLong(), anyLong(), anyInt(), anyBoolean(), anyInt(), anyInt()); + anyInt(), anyBoolean(), anyInt(), anyInt()); doReturn(new ComponentName("", "")).when(mMockPackageManager).getSystemUiServiceComponent(); // Never review permissions @@ -728,497 +712,68 @@ public class ActivityStarterTests extends WindowTestsBase { eq(FAKE_REAL_CALLING_UID), anyInt(), anyBoolean(), eq(false)); } - /** - * This test ensures that unsupported usecases aren't aborted when background starts are - * allowed. - */ - @Test - public void testBackgroundActivityStartsAllowed_noStartsAborted() { - doReturn(true).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * This test ensures that unsupported usecases are aborted when background starts are - * disallowed. - */ - @Test - public void testBackgroundActivityStartsDisallowed_unsupportedUsecaseAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_unsupportedUsecase_aborted", true, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * This test ensures that unsupported usecases are aborted when background starts are - * disallowed. - */ - @Test - public void testBackgroundActivityStartsDisallowed_callingUidProcessStateTopAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callingUidProcessStateTop_aborted", true, - UNIMPORTANT_UID, false, PROCESS_STATE_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * This test ensures that unsupported usecases are aborted when background starts are - * disallowed. - */ - @Test - public void testBackgroundActivityStartsDisallowed_realCallingUidProcessStateTopAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_realCallingUidProcessStateTop_aborted", true, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * This test ensures that unsupported usecases are aborted when background starts are - * disallowed. - */ - @Test - public void testBackgroundActivityStartsDisallowed_hasForegroundActivitiesAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_hasForegroundActivities_aborted", true, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - true, false, false, false, false, false, false, false); - } /** * This test ensures that unsupported usecases are aborted when background starts are * disallowed. */ @Test - public void testBackgroundActivityStartsDisallowed_pinnedSingleInstanceAborted() { + public void testPinnedSingleInstanceAborted() { doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_pinned_singleinstance_aborted", true, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, true, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the calling process runs as ROOT_UID. - */ - @Test - public void testBackgroundActivityStartsDisallowed_rootUidNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false, - Process.ROOT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the calling process is running as SYSTEM_UID. - */ - @Test - public void testBackgroundActivityStartsDisallowed_systemUidNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted", false, - Process.SYSTEM_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the calling process is running as NFC_UID. - */ - @Test - public void testBackgroundActivityStartsDisallowed_nfcUidNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest("disallowed_nfcUid_notAborted", false, - Process.NFC_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the calling process has a visible window. - */ - @Test - public void testBackgroundActivityStartsDisallowed_callingUidHasVisibleWindowNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callingUidHasVisibleWindow_notAborted", false, - UNIMPORTANT_UID, true, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * The sending app has a visible window, but does not (by default) allow the pending intent to - * start the background activity. - */ - @Test - @Ignore("b/266015587") - public void testBackgroundActivityStartsDisallowed_realCallingUidHasVisibleWindowAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_realCallingUidHasVisibleWindow_abortedInU", true, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, true, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the caller is in the recent activity list. - */ - @Test - public void testBackgroundActivityStartsDisallowed_callerIsRecentsNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callerIsRecents_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, true, false, false, false, false, false, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the caller is temporarily (10s) allowed to start. - */ - @Test - public void testBackgroundActivityStartsDisallowed_callerIsAllowedNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callerIsAllowed_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, true, false, false, false, false, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the caller explicitly has background activity start privilege. - */ - @Test - public void testBackgroundActivityStartsDisallowed_callerIsInstrumentingWithBASPnotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callerIsInstrumentingWithBackgroundActivityStartPrivileges_notAborted", - false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, true, false, false, false, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the caller is a device owner. - */ - @Test - public void - testBackgroundActivityStartsDisallowed_callingPackageNameIsDeviceOwnerNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callingPackageNameIsDeviceOwner_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, true, false, false, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the caller is a affiliated profile owner. - */ - @Test - public void - testBackgroundActivityStartsDisallowed_isAffiliatedProfileOwnerNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callingUidIsAffiliatedProfileOwner_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, true, false, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the caller has the OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop. - */ - @Test - public void testBackgroundActivityStartsDisallowed_callerHasSystemExemptAppOpNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callerHasSystemExemptAppOpNotAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, true); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the caller is an IME. - */ - @Test - public void testBackgroundActivityStartsDisallowed_callingPackageNameIsImeNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - setupImeWindow(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callingPackageNameIsIme_notAborted", false, - CURRENT_IME_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * This test ensures proper logging for BAL_ALLOW_PERMISSION. - */ - @Test - public void testBackgroundActivityStartsAllowed_logging() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - MockitoSession mockingSession = mockitoSession() - .mockStatic(ActivityTaskManagerService.class) - .mockStatic(FrameworkStatsLog.class) - .strictness(Strictness.LENIENT) - .startMocking(); - try { - doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission( - eq(START_ACTIVITIES_FROM_BACKGROUND), - anyInt(), anyInt())); - runAndVerifyBackgroundActivityStartsSubtest( - "allowed_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, true, false, false, false, false, false, false); - verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, - "", // activity name - BackgroundActivityStartController.BAL_ALLOW_PERMISSION, - UNIMPORTANT_UID, - UNIMPORTANT_UID2, - BackgroundActivityStartController.BAL_ALLOW_PERMISSION, - true, // opt in - false, // but no explicit opt in - BackgroundActivityStartController.BAL_BLOCK, - true, // opt in - false // but no explicit opt in - )); - } finally { - mockingSession.finishMocking(); - } - } - - /** - * This test ensures proper logging for BAL_ALLOW_PENDING_INTENT, when the PendingIntent sender - * is the only reason BAL is allowed. - */ - @Test - @RequiresFlagsDisabled(com.android.window.flags.Flags.FLAG_BAL_IMPROVED_METRICS) - public void testBackgroundActivityStartsAllowed_loggingOnlyPendingIntentAllowed() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - MockitoSession mockingSession = mockitoSession() - .mockStatic(ActivityTaskManagerService.class) - .mockStatic(FrameworkStatsLog.class) - .mockStatic(PendingIntentRecord.class) - .strictness(Strictness.LENIENT) - .startMocking(); - try { - doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission( - eq(START_ACTIVITIES_FROM_BACKGROUND), - anyInt(), anyInt())); - doReturn(BackgroundStartPrivileges.allowBackgroundActivityStarts(null)).when( - () -> PendingIntentRecord.getBackgroundStartPrivilegesAllowedByCaller( - anyObject(), anyInt(), anyObject())); - runAndVerifyBackgroundActivityStartsSubtest( - "allowed_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - Process.SYSTEM_UID, true, PROCESS_STATE_BOUND_TOP, - false, true, false, false, false, false, false, false, - ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED); - verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, - DEFAULT_COMPONENT_PACKAGE_NAME + "/" + DEFAULT_COMPONENT_PACKAGE_NAME, - BackgroundActivityStartController.BAL_ALLOW_PENDING_INTENT, - UNIMPORTANT_UID, - Process.SYSTEM_UID, - BackgroundActivityStartController.BAL_ALLOW_PERMISSION, - false, // opt in - true, // explicit opt out - BackgroundActivityStartController.BAL_ALLOW_VISIBLE_WINDOW, - true, // opt in - false // but no explicit opt in - )); - } finally { - mockingSession.finishMocking(); - } - } - - /** - * This test ensures proper logging for BAL_ALLOW_PENDING_INTENT, when the PendingIntent sender - * is not the primary reason to allow BAL (but the creator). - */ - @Test - @RequiresFlagsDisabled(com.android.window.flags.Flags.FLAG_BAL_IMPROVED_METRICS) - public void testBackgroundActivityStartsAllowed_loggingPendingIntentAllowed() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - MockitoSession mockingSession = mockitoSession() - .mockStatic(ActivityTaskManagerService.class) - .mockStatic(FrameworkStatsLog.class) - .mockStatic(PendingIntentRecord.class) - .strictness(Strictness.LENIENT) - .startMocking(); - try { - doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission( - eq(START_ACTIVITIES_FROM_BACKGROUND), - anyInt(), anyInt())); - doReturn(BackgroundStartPrivileges.allowBackgroundActivityStarts(null)).when( - () -> PendingIntentRecord.getBackgroundStartPrivilegesAllowedByCaller( - anyObject(), anyInt(), anyObject())); - runAndVerifyBackgroundActivityStartsSubtest( - "allowed_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - Process.SYSTEM_UID, true, PROCESS_STATE_BOUND_TOP, - false, true, false, false, false, false, false, false, - ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED); - verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, - "", - BackgroundActivityStartController.BAL_ALLOW_PERMISSION, - UNIMPORTANT_UID, - Process.SYSTEM_UID, - BackgroundActivityStartController.BAL_ALLOW_PERMISSION, - true, // opt in - true, // explicit opt in - BackgroundActivityStartController.BAL_ALLOW_VISIBLE_WINDOW, - true, // opt in - false // but no explicit opt in - )); - } finally { - mockingSession.finishMocking(); - } - } - - private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted, - int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState, - int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState, - boolean hasForegroundActivities, boolean callerIsRecents, - boolean callerIsTempAllowed, - boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges, - boolean isCallingUidDeviceOwner, - boolean isCallingUidAffiliatedProfileOwner, - boolean isPinnedSingleInstance, - boolean hasSystemExemptAppOp) { - runAndVerifyBackgroundActivityStartsSubtest(name, shouldHaveAborted, callingUid, - callingUidHasVisibleWindow, callingUidProcState, realCallingUid, - realCallingUidHasVisibleWindow, realCallingUidProcState, hasForegroundActivities, - callerIsRecents, callerIsTempAllowed, - callerIsInstrumentingWithBackgroundActivityStartPrivileges, - isCallingUidDeviceOwner, isCallingUidAffiliatedProfileOwner, isPinnedSingleInstance, - hasSystemExemptAppOp, - ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED); - } - - private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted, - int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState, - int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState, - boolean hasForegroundActivities, boolean callerIsRecents, - boolean callerIsTempAllowed, - boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges, - boolean isCallingUidDeviceOwner, - boolean isCallingUidAffiliatedProfileOwner, - boolean isPinnedSingleInstance, - boolean hasSystemExemptAppOp, - @BackgroundActivityStartMode int pendingIntentCreatorBackgroundActivityStartMode) { // window visibility - doReturn(callingUidHasVisibleWindow).when(mAtm).hasActiveVisibleWindow(callingUid); - doReturn(realCallingUidHasVisibleWindow).when(mAtm).hasActiveVisibleWindow(realCallingUid); + doReturn(false).when(mAtm).hasActiveVisibleWindow(UNIMPORTANT_UID); + doReturn(false).when(mAtm).hasActiveVisibleWindow(UNIMPORTANT_UID2); // process importance - mAtm.mActiveUids.onUidActive(callingUid, callingUidProcState); - mAtm.mActiveUids.onUidActive(realCallingUid, realCallingUidProcState); + mAtm.mActiveUids.onUidActive(UNIMPORTANT_UID, PROCESS_STATE_BOUND_TOP); + mAtm.mActiveUids.onUidActive(UNIMPORTANT_UID2, PROCESS_STATE_BOUND_TOP); // foreground activities final IApplicationThread caller = mock(IApplicationThread.class); final WindowProcessListener listener = mock(WindowProcessListener.class); final ApplicationInfo ai = new ApplicationInfo(); - ai.uid = callingUid; + ai.uid = UNIMPORTANT_UID; ai.packageName = "com.android.test.package"; - final WindowProcessController callerApp = - spy(new WindowProcessController(mAtm, ai, null, callingUid, -1, null, listener)); - doReturn(hasForegroundActivities).when(callerApp).hasForegroundActivities(); + final WindowProcessController callerApp = spy(new WindowProcessController( + mAtm, ai, null, UNIMPORTANT_UID, -1, null, listener)); + doReturn(false).when(callerApp).hasForegroundActivities(); doReturn(callerApp).when(mAtm).getProcessController(caller); // caller is recents RecentTasks recentTasks = mock(RecentTasks.class); mAtm.mTaskSupervisor.setRecentTasks(recentTasks); - doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid); + doReturn(false).when(recentTasks).isCallerRecents(UNIMPORTANT_UID); // caller is temp allowed - if (callerIsTempAllowed) { - callerApp.addOrUpdateBackgroundStartPrivileges(new Binder(), - BackgroundStartPrivileges.ALLOW_BAL); - } // caller is instrumenting with background activity starts privileges - callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges, - callerIsInstrumentingWithBackgroundActivityStartPrivileges ? Process.SHELL_UID : -1, - callerIsInstrumentingWithBackgroundActivityStartPrivileges); + callerApp.setInstrumenting(false, -1, false); // callingUid is the device owner - doReturn(isCallingUidDeviceOwner).when(mAtm).isDeviceOwner(callingUid); + doReturn(false).when(mAtm).isDeviceOwner(UNIMPORTANT_UID); // callingUid is the affiliated profile owner - doReturn(isCallingUidAffiliatedProfileOwner).when(mAtm) - .isAffiliatedProfileOwner(callingUid); + doReturn(false).when(mAtm).isAffiliatedProfileOwner(UNIMPORTANT_UID); // caller has OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop - doReturn(hasSystemExemptAppOp ? AppOpsManager.MODE_ALLOWED - : AppOpsManager.MODE_DEFAULT).when(mAppOpsManager).checkOpNoThrow( + doReturn(AppOpsManager.MODE_DEFAULT).when(mAppOpsManager).checkOpNoThrow( eq(AppOpsManager.OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION), anyInt(), any()); - int launchMode = LAUNCH_MULTIPLE; - if (isPinnedSingleInstance) { - final ActivityRecord baseActivity = - new ActivityBuilder(mAtm).setCreateTask(true).build(); - baseActivity.getRootTask() - .setWindowingMode(WINDOWING_MODE_PINNED); - doReturn(baseActivity).when(mRootWindowContainer).findTask(any(), any()); - launchMode = LAUNCH_SINGLE_INSTANCE; - } + final ActivityRecord baseActivity = new ActivityBuilder(mAtm).setCreateTask(true).build(); + baseActivity.getRootTask().setWindowingMode(WINDOWING_MODE_PINNED); + doReturn(baseActivity).when(mRootWindowContainer).findTask(any(), any()); ActivityOptions rawOptions = ActivityOptions.makeBasic() .setPendingIntentCreatorBackgroundActivityStartMode( - pendingIntentCreatorBackgroundActivityStartMode); + ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED); final ActivityOptions options = spy(rawOptions); ActivityRecord[] outActivity = new ActivityRecord[1]; ActivityStarter starter = prepareStarter( - FLAG_ACTIVITY_NEW_TASK, true, launchMode) + FLAG_ACTIVITY_NEW_TASK, true, LAUNCH_SINGLE_INSTANCE) .setCallingPackage("com.whatever.dude") .setCaller(caller) - .setCallingUid(callingUid) - .setRealCallingUid(realCallingUid) + .setCallingUid(UNIMPORTANT_UID) + .setRealCallingUid(UNIMPORTANT_UID2) .setActivityOptions(new SafeActivityOptions(options)) .setOutActivity(outActivity); - final int result = starter.setReason("testBackgroundActivityStarts_" + name).execute(); - - assertEquals(ActivityStarter.getExternalResult( - shouldHaveAborted ? START_ABORTED : START_SUCCESS), result); - verify(options, times(shouldHaveAborted ? 1 : 0)).abort(); + final int result = starter.setReason("testPinnedSingleInstanceAborted").execute(); + assertEquals(ActivityStarter.getExternalResult(START_ABORTED), result); + verify(options, times(1)).abort(); final ActivityRecord startedActivity = outActivity[0]; if (startedActivity != null && startedActivity.getTask() != null) { diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java index a39a1a8637df..c67d1ec63827 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java @@ -550,7 +550,7 @@ public class BackNavigationControllerTests extends WindowTestsBase { }).when(appWindow.mSession).setOnBackInvokedCallbackInfo(eq(appWindow.mClient), any()); addToWindowMap(appWindow, true); - dispatcher.attachToWindow(appWindow.mSession, appWindow.mClient, null); + dispatcher.attachToWindow(appWindow.mSession, appWindow.mClient, null, null); OnBackInvokedCallback appCallback = createBackCallback(appLatch); diff --git a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java index 4afc8ac6c599..366e519fb063 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java @@ -29,6 +29,7 @@ import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.app.ActivityOptions; @@ -564,4 +565,136 @@ public class BackgroundActivityStartControllerExemptionTests { assertWithMessage(balState.toString()).that(callerVerdict.getCode()).isEqualTo( BAL_ALLOW_SAW_PERMISSION); } + + @Test + public void testCaller_isRecents() { + int callingUid = REGULAR_UID_1; + int callingPid = REGULAR_PID_1; + final String callingPackage = REGULAR_PACKAGE_1; + int realCallingUid = REGULAR_UID_2; + int realCallingPid = REGULAR_PID_2; + + // setup state + //if (mSupervisor.mRecentTasks.isCallerRecents(state.mCallingUid)) + RecentTasks recentTasks = mock(RecentTasks.class); + when(recentTasks.isCallerRecents(eq(callingUid))).thenReturn(true); + mSupervisor.mRecentTasks = recentTasks; + + // prepare call + PendingIntentRecord originatingPendingIntent = mPendingIntentRecord; + BackgroundStartPrivileges forcedBalByPiSender = BackgroundStartPrivileges.NONE; + Intent intent = TEST_INTENT; + ActivityOptions checkedOptions = mCheckedOptions; + BackgroundActivityStartController.BalState balState = mController.new BalState(callingUid, + callingPid, callingPackage, realCallingUid, realCallingPid, null, + originatingPendingIntent, forcedBalByPiSender, mResultRecord, intent, + checkedOptions); + + // call + BalVerdict callerVerdict = mController.checkBackgroundActivityStartAllowedByCaller( + balState); + balState.setResultForCaller(callerVerdict); + + // assertions + assertWithMessage(balState.toString()).that(callerVerdict.getCode()).isEqualTo( + BAL_ALLOW_ALLOWLISTED_COMPONENT); + } + + @Test + public void testCaller_isDeviceOwner() { + int callingUid = REGULAR_UID_1; + int callingPid = REGULAR_PID_1; + final String callingPackage = REGULAR_PACKAGE_1; + int realCallingUid = REGULAR_UID_2; + int realCallingPid = REGULAR_PID_2; + + // setup state + when(mService.isDeviceOwner(eq(callingUid))).thenReturn(true); + + // prepare call + PendingIntentRecord originatingPendingIntent = mPendingIntentRecord; + BackgroundStartPrivileges forcedBalByPiSender = BackgroundStartPrivileges.NONE; + Intent intent = TEST_INTENT; + ActivityOptions checkedOptions = mCheckedOptions; + BackgroundActivityStartController.BalState balState = mController.new BalState(callingUid, + callingPid, callingPackage, realCallingUid, realCallingPid, null, + originatingPendingIntent, forcedBalByPiSender, mResultRecord, intent, + checkedOptions); + + // call + BalVerdict callerVerdict = mController.checkBackgroundActivityStartAllowedByCaller( + balState); + balState.setResultForCaller(callerVerdict); + + // assertions + assertWithMessage(balState.toString()).that(callerVerdict.getCode()).isEqualTo( + BAL_ALLOW_ALLOWLISTED_COMPONENT); + } + + @Test + public void testCaller_isAffiliatedProfileOwner() { + int callingUid = REGULAR_UID_1; + int callingPid = REGULAR_PID_1; + final String callingPackage = REGULAR_PACKAGE_1; + int realCallingUid = REGULAR_UID_2; + int realCallingPid = REGULAR_PID_2; + + // setup state + when(mService.isAffiliatedProfileOwner(eq(callingUid))).thenReturn(true); + + // prepare call + PendingIntentRecord originatingPendingIntent = mPendingIntentRecord; + BackgroundStartPrivileges forcedBalByPiSender = BackgroundStartPrivileges.NONE; + Intent intent = TEST_INTENT; + ActivityOptions checkedOptions = mCheckedOptions; + BackgroundActivityStartController.BalState balState = mController.new BalState(callingUid, + callingPid, callingPackage, realCallingUid, realCallingPid, null, + originatingPendingIntent, forcedBalByPiSender, mResultRecord, intent, + checkedOptions); + + // call + BalVerdict callerVerdict = mController.checkBackgroundActivityStartAllowedByCaller( + balState); + balState.setResultForCaller(callerVerdict); + + // assertions + assertWithMessage(balState.toString()).that(callerVerdict.getCode()).isEqualTo( + BAL_ALLOW_ALLOWLISTED_COMPONENT); + } + + @Test + public void testCaller_isExemptFromBgStartRestriction() { + int callingUid = REGULAR_UID_1; + int callingPid = REGULAR_PID_1; + final String callingPackage = REGULAR_PACKAGE_1; + int realCallingUid = REGULAR_UID_2; + int realCallingPid = REGULAR_PID_2; + + mDeviceConfig.set("system_exempt_from_activity_bg_start_restriction_enabled", "true"); + AppOpsManager appOpsManager = mock(AppOpsManager.class); + when(mService.getAppOpsManager()).thenReturn(appOpsManager); + when(appOpsManager.checkOpNoThrow(eq( + AppOpsManager.OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION), + eq(callingUid), eq(callingPackage))).thenReturn(AppOpsManager.MODE_ALLOWED); + + + // prepare call + PendingIntentRecord originatingPendingIntent = mPendingIntentRecord; + BackgroundStartPrivileges forcedBalByPiSender = BackgroundStartPrivileges.NONE; + Intent intent = TEST_INTENT; + ActivityOptions checkedOptions = mCheckedOptions; + BackgroundActivityStartController.BalState balState = mController.new BalState(callingUid, + callingPid, callingPackage, realCallingUid, realCallingPid, null, + originatingPendingIntent, forcedBalByPiSender, mResultRecord, intent, + checkedOptions); + + // call + BalVerdict callerVerdict = mController.checkBackgroundActivityStartAllowedByCaller( + balState); + balState.setResultForCaller(callerVerdict); + + // assertions + assertWithMessage(balState.toString()).that(callerVerdict.getCode()).isEqualTo( + BAL_ALLOW_PERMISSION); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/BackgroundLaunchProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackgroundLaunchProcessControllerTests.java new file mode 100644 index 000000000000..a4df03447754 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundLaunchProcessControllerTests.java @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW; +import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_DISALLOW; +import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_FOREGROUND; +import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_GRACE_PERIOD; +import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_PERMISSION; +import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_VISIBLE_WINDOW; +import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK; + +import static com.google.common.truth.Truth.assertThat; + +import android.app.BackgroundStartPrivileges; +import android.content.Context; +import android.os.Binder; +import android.os.IBinder; +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; + +import com.android.server.wm.BackgroundActivityStartController.BalVerdict; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +/** + * Tests for the {@link BackgroundLaunchProcessController} class. + * + * Build/Install/Run: + * atest WmTests:BackgroundLaunchProcessControllerTests + */ +@SmallTest +@Presubmit +@RunWith(JUnit4.class) +public class BackgroundLaunchProcessControllerTests { + + Set<IBinder> mActivityStartAllowed = new HashSet<>(); + Set<Integer> mHasActiveVisibleWindow = new HashSet<>(); + + BackgroundActivityStartCallback mCallback = new BackgroundActivityStartCallback() { + @Override + public boolean isActivityStartAllowed(Collection<IBinder> tokens, int uid, + String packageName) { + for (IBinder token : tokens) { + if (token == null || mActivityStartAllowed.contains(token)) { + return true; + } + } + return false; + } + + @Override + public boolean canCloseSystemDialogs(Collection<IBinder> tokens, int uid) { + return false; + } + }; + BackgroundLaunchProcessController mController = new BackgroundLaunchProcessController( + mHasActiveVisibleWindow::contains, mCallback); + + int mPid = 123; + int mUid = 234; + String mPackageName = "package.name"; + int mAppSwitchState = APP_SWITCH_DISALLOW; + boolean mIsCheckingForFgsStart = false; + boolean mHasActivityInVisibleTask = false; + boolean mHasBackgroundActivityStartPrivileges = false; + long mLastStopAppSwitchesTime = 0L; + long mLastActivityLaunchTime = 0L; + long mLastActivityFinishTime = 0L; + + @Test + public void testNothingAllows() { + BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( + mPid, mUid, mPackageName, + mAppSwitchState, mIsCheckingForFgsStart, + mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, + mLastStopAppSwitchesTime, mLastActivityLaunchTime, + mLastActivityFinishTime); + assertThat(balVerdict.getCode()).isEqualTo(BAL_BLOCK); + } + + @Test + public void testInstrumenting() { + mHasBackgroundActivityStartPrivileges = true; + BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( + mPid, mUid, mPackageName, + mAppSwitchState, mIsCheckingForFgsStart, + mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, + mLastStopAppSwitchesTime, mLastActivityLaunchTime, + mLastActivityFinishTime); + assertThat(balVerdict.getCode()).isEqualTo(BAL_ALLOW_PERMISSION); + } + + @Test + public void testAllowedByTokenNoCallback() { + mController = new BackgroundLaunchProcessController(mHasActiveVisibleWindow::contains, + null); + Binder token = new Binder(); + mActivityStartAllowed.add(token); + mController.addOrUpdateAllowBackgroundStartPrivileges(token, + BackgroundStartPrivileges.ALLOW_BAL); + BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( + mPid, mUid, mPackageName, + mAppSwitchState, mIsCheckingForFgsStart, + mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, + mLastStopAppSwitchesTime, mLastActivityLaunchTime, + mLastActivityFinishTime); + assertThat(balVerdict.getCode()).isEqualTo(BAL_ALLOW_PERMISSION); + } + + @Test + public void testAllowedByToken() { + Binder token = new Binder(); + mActivityStartAllowed.add(token); + mController.addOrUpdateAllowBackgroundStartPrivileges(token, + BackgroundStartPrivileges.ALLOW_BAL); + BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( + mPid, mUid, mPackageName, + mAppSwitchState, mIsCheckingForFgsStart, + mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, + mLastStopAppSwitchesTime, mLastActivityLaunchTime, + mLastActivityFinishTime); + assertThat(balVerdict.getCode()).isEqualTo(BAL_ALLOW_PERMISSION); + } + + @Test + public void testBoundByForeground() { + mAppSwitchState = APP_SWITCH_ALLOW; + mController.addBoundClientUid(999, "visible.package", Context.BIND_ALLOW_ACTIVITY_STARTS); + mHasActiveVisibleWindow.add(999); + BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( + mPid, mUid, mPackageName, + mAppSwitchState, mIsCheckingForFgsStart, + mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, + mLastStopAppSwitchesTime, mLastActivityLaunchTime, + mLastActivityFinishTime); + assertThat(balVerdict.getCode()).isEqualTo(BAL_ALLOW_VISIBLE_WINDOW); + } + + @Test + public void testForegroundTask() { + mAppSwitchState = APP_SWITCH_ALLOW; + mHasActivityInVisibleTask = true; + BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( + mPid, mUid, mPackageName, + mAppSwitchState, mIsCheckingForFgsStart, + mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, + mLastStopAppSwitchesTime, mLastActivityLaunchTime, + mLastActivityFinishTime); + assertThat(balVerdict.getCode()).isEqualTo(BAL_ALLOW_FOREGROUND); + } + + @Test + public void testGracePeriod() { + mAppSwitchState = APP_SWITCH_ALLOW; + long now = System.currentTimeMillis(); + mLastStopAppSwitchesTime = now - 10000; + mLastActivityLaunchTime = now - 9000; + mLastActivityFinishTime = now - 100; + BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( + mPid, mUid, mPackageName, + mAppSwitchState, mIsCheckingForFgsStart, + mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, + mLastStopAppSwitchesTime, mLastActivityLaunchTime, + mLastActivityFinishTime); + assertThat(balVerdict.getCode()).isEqualTo(BAL_ALLOW_GRACE_PERIOD); + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 87395a17698d..417ee6be17bc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -1343,6 +1343,27 @@ public class DisplayContentTests extends WindowTestsBase { assertEquals(mAppWindow, mDisplayContent.computeImeControlTarget()); } + @SetupWindows(addWindows = W_ACTIVITY) + @Test + public void testShouldImeAttachedToApp_targetBoundsDifferentFromImeContainer_returnsFalse() + throws Exception { + Rect imeContainerBounds = new Rect(0, 0, 100, 100); + Rect imeTargetBounds = new Rect(0, 0, 100, 200); + spyOn(mAppWindow); + spyOn(mAppWindow.mActivityRecord); + doReturn(imeTargetBounds).when(mAppWindow).getBounds(); + doReturn(true).when(mAppWindow.mActivityRecord).matchParentBounds(); + mDisplayContent.setImeInputTarget(mAppWindow); + mDisplayContent.setImeLayeringTarget( + mDisplayContent.getImeInputTarget().getWindowState()); + mDisplayContent.setRemoteInsetsController(createDisplayWindowInsetsController()); + final DisplayArea.Tokens imeContainer = mDisplayContent.getImeContainer(); + spyOn(imeContainer); + doReturn(imeContainerBounds).when(imeContainer).getBounds(); + + assertFalse(mDisplayContent.shouldImeAttachedToApp()); + } + @Test public void testUpdateSystemGestureExclusion() throws Exception { final DisplayContent dc = createNewDisplay(); diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java index c7f502045ac8..8129c3d030be 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java @@ -77,6 +77,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.annotation.Nullable; import android.compat.testing.PlatformCompatChangeRule; @@ -110,7 +111,7 @@ import org.junit.rules.TestRule; import org.junit.runner.RunWith; /** - * Test class for {@link LetterboxUiControllerTest}. + * Test class for {@link LetterboxUiController}. * * Build/Install/Run: * atest WmTests:LetterboxUiControllerTest @@ -521,8 +522,8 @@ public class LetterboxUiControllerTest extends WindowTestsBase { final Rect opaqueBounds = new Rect(0, 0, 500, 300); doReturn(opaqueBounds).when(mActivity).getBounds(); // Activity is translucent - spyOn(mActivity.mLetterboxUiController); - doReturn(true).when(mActivity.mLetterboxUiController).hasInheritedLetterboxBehavior(); + spyOn(mActivity.mTransparentPolicy); + when(mActivity.mTransparentPolicy.isRunning()).thenReturn(true); // Makes requested sizes different mainWindow.mRequestedWidth = opaqueBounds.width() - 1; diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java index 7756edd68eda..d88871cd4af7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java @@ -906,6 +906,24 @@ public class RootWindowContainerTests extends WindowTestsBase { } /** + * Tests whether home can be started if it's not allowed by policy. + */ + @Test + public void testCanStartHome_returnsFalse_ifDisallowedByPolicy() { + final ActivityInfo info = new ActivityInfo(); + info.applicationInfo = new ApplicationInfo(); + final WindowProcessController app = mock(WindowProcessController.class); + doReturn(app).when(mAtm).getProcessController(any(), anyInt()); + doReturn(false).when(app).isInstrumenting(); + final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); + doReturn(false).when(taskDisplayArea).canHostHomeTask(); + + assertFalse(mRootWindowContainer.canStartHomeOnDisplayArea(info, taskDisplayArea, + false /* allowInstrumenting*/)); + } + + + /** * Tests that secondary home activity should not be resolved if device is still locked. */ @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 7ced9d50ab3f..7adac5b283c5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -16,8 +16,6 @@ package com.android.server.wm; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.app.WindowConfiguration.ROTATION_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; @@ -62,7 +60,6 @@ import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANG import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE; import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED; import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE; -import static com.android.server.wm.ActivityRecord.State.DESTROYED; import static com.android.server.wm.ActivityRecord.State.PAUSED; import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS; import static com.android.server.wm.ActivityRecord.State.RESUMED; @@ -77,7 +74,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; @@ -199,26 +195,6 @@ public class SizeCompatTests extends WindowTestsBase { } @Test - public void testCleanLetterboxConfigListenerWhenTranslucentIsDestroyed() { - mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); - setUpDisplaySizeWithApp(2000, 1000); - prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); - // Translucent Activity - final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) - .setActivityTheme(android.R.style.Theme_Translucent) - .setLaunchedFromUid(mActivity.getUid()) - .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) - .build(); - mTask.addChild(translucentActivity); - - translucentActivity.setState(DESTROYED, "testing"); - translucentActivity.removeImmediately(); - - assertFalse(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior()); - } - - @Test public void testHorizontalReachabilityEnabledForTranslucentActivities() { testReachabilityEnabledForTranslucentActivity(/* dw */ 2500, /* dh */1000, SCREEN_ORIENTATION_PORTRAIT, /* minAspectRatio */ 0f, @@ -363,42 +339,6 @@ public class SizeCompatTests extends WindowTestsBase { } } - @Test - public void testApplyStrategyAgainWhenOpaqueIsDestroyed() { - mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); - setUpDisplaySizeWithApp(2000, 1000); - prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); - // Launch another opaque activity - final ActivityRecord opaqueActivity = new ActivityBuilder(mAtm) - .setLaunchedFromUid(mActivity.getUid()) - .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) - .build(); - mTask.addChild(opaqueActivity); - // Transparent activity strategy not applied - assertFalse(opaqueActivity.mLetterboxUiController.hasInheritedLetterboxBehavior()); - - // Launch translucent Activity - final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) - .setActivityTheme(android.R.style.Theme_Translucent) - .setLaunchedFromUid(mActivity.getUid()) - .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) - .build(); - mTask.addChild(translucentActivity); - // Transparent strategy applied - assertTrue(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior()); - - spyOn(translucentActivity.mLetterboxUiController); - clearInvocations(translucentActivity.mLetterboxUiController); - - // We destroy the first opaque activity - opaqueActivity.setState(DESTROYED, "testing"); - opaqueActivity.removeImmediately(); - - // Check that updateInheritedLetterbox() is invoked again - verify(translucentActivity.mLetterboxUiController).updateInheritedLetterbox(); - } - // TODO(b/333663877): Enable test after fix @Test @RequiresFlagsDisabled({Flags.FLAG_INSETS_DECOUPLED_CONFIGURATION}) @@ -450,283 +390,6 @@ public class SizeCompatTests extends WindowTestsBase { } @Test - public void testResetOpaqueReferenceWhenOpaqueIsDestroyed() { - mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); - setUpDisplaySizeWithApp(2000, 1000); - prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); - - // Launch translucent Activity - final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) - .setActivityTheme(android.R.style.Theme_Translucent) - .setLaunchedFromUid(mActivity.getUid()) - .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) - .build(); - mTask.addChild(translucentActivity); - // Transparent strategy applied - assertTrue(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior()); - assertNotNull(translucentActivity.mLetterboxUiController.mFirstOpaqueActivityBeneath); - - spyOn(translucentActivity.mLetterboxUiController); - clearInvocations(translucentActivity.mLetterboxUiController); - - // We destroy the first opaque activity - mActivity.removeImmediately(); - - // Check that updateInheritedLetterbox() is invoked again - verify(translucentActivity.mLetterboxUiController).updateInheritedLetterbox(); - assertNull(translucentActivity.mLetterboxUiController.mFirstOpaqueActivityBeneath); - } - - @Test - public void testNotApplyStrategyAgainWhenOpaqueIsNotDestroyed() { - mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); - setUpDisplaySizeWithApp(2000, 1000); - prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); - // Launch another opaque activity - final ActivityRecord opaqueActivity = new ActivityBuilder(mAtm) - .setLaunchedFromUid(mActivity.getUid()) - .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) - .build(); - mTask.addChild(opaqueActivity); - // Transparent activity strategy not applied - assertFalse(opaqueActivity.mLetterboxUiController.hasInheritedLetterboxBehavior()); - - // Launch translucent Activity - final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) - .setActivityTheme(android.R.style.Theme_Translucent) - .setLaunchedFromUid(mActivity.getUid()) - .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) - .build(); - mTask.addChild(translucentActivity); - // Transparent strategy applied - assertTrue(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior()); - - spyOn(translucentActivity.mLetterboxUiController); - clearInvocations(translucentActivity.mLetterboxUiController); - - // Check that updateInheritedLetterbox() is invoked again - verify(translucentActivity.mLetterboxUiController, never()).updateInheritedLetterbox(); - } - - @Test - public void testApplyStrategyToTranslucentActivities() { - mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); - setUpDisplaySizeWithApp(2000, 1000); - prepareUnresizable(mActivity, 1.5f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); - mActivity.info.setMinAspectRatio(1.2f); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); - // Translucent Activity - final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) - .setActivityTheme(android.R.style.Theme_Translucent) - .setLaunchedFromUid(mActivity.getUid()) - .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE) - .setMinAspectRatio(1.1f) - .setMaxAspectRatio(3f) - .build(); - mTask.addChild(translucentActivity); - // We check bounds - final Rect opaqueBounds = mActivity.getConfiguration().windowConfiguration.getBounds(); - final Rect translucentRequestedBounds = translucentActivity.getRequestedOverrideBounds(); - assertEquals(opaqueBounds, translucentRequestedBounds); - // We check orientation - final int translucentOrientation = - translucentActivity.getRequestedConfigurationOrientation(); - assertEquals(ORIENTATION_PORTRAIT, translucentOrientation); - // We check aspect ratios - assertEquals(1.2f, translucentActivity.getMinAspectRatio(), 0.00001f); - assertEquals(1.5f, translucentActivity.getMaxAspectRatio(), 0.00001f); - } - - @Test - public void testApplyStrategyToTranslucentActivitiesRetainsWindowConfigurationProperties() { - mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); - setUpDisplaySizeWithApp(2000, 1000); - prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); - // Translucent Activity - final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) - .setActivityTheme(android.R.style.Theme_Translucent) - .setLaunchedFromUid(mActivity.getUid()) - .build(); - final Configuration requestedConfig = - translucentActivity.getRequestedOverrideConfiguration(); - final WindowConfiguration translucentWinConf = requestedConfig.windowConfiguration; - translucentWinConf.setActivityType(ACTIVITY_TYPE_STANDARD); - translucentWinConf.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); - translucentWinConf.setAlwaysOnTop(true); - translucentActivity.onRequestedOverrideConfigurationChanged(requestedConfig); - - mTask.addChild(translucentActivity); - - // The original override of WindowConfiguration should keep. - assertEquals(ACTIVITY_TYPE_STANDARD, translucentActivity.getActivityType()); - assertEquals(WINDOWING_MODE_MULTI_WINDOW, translucentWinConf.getWindowingMode()); - assertTrue(translucentWinConf.isAlwaysOnTop()); - // Unless display is going to be rotated, it should always inherit from parent. - assertEquals(ROTATION_UNDEFINED, translucentWinConf.getDisplayRotation()); - } - - @Test - public void testApplyStrategyToMultipleTranslucentActivities() { - mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); - setUpDisplaySizeWithApp(2000, 1000); - prepareUnresizable(mActivity, 1.5f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); - mActivity.info.setMinAspectRatio(1.2f); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); - // Translucent Activity - final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) - .setActivityTheme(android.R.style.Theme_Translucent) - .setLaunchedFromUid(mActivity.getUid()) - .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE) - .setMinAspectRatio(1.1f) - .setMaxAspectRatio(3f) - .build(); - mTask.addChild(translucentActivity); - // We check bounds - final Rect opaqueBounds = mActivity.getConfiguration().windowConfiguration.getBounds(); - final Rect translucentRequestedBounds = translucentActivity.getRequestedOverrideBounds(); - assertEquals(opaqueBounds, translucentRequestedBounds); - // Launch another translucent activity - final ActivityRecord translucentActivity2 = new ActivityBuilder(mAtm) - .setActivityTheme(android.R.style.Theme_Translucent) - .setLaunchedFromUid(mActivity.getUid()) - .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE) - .build(); - mTask.addChild(translucentActivity2); - // We check bounds - final Rect translucent2RequestedBounds = translucentActivity2.getRequestedOverrideBounds(); - assertEquals(opaqueBounds, translucent2RequestedBounds); - } - - @Test - public void testNotApplyStrategyToTranslucentActivitiesOverEmbeddedActivities() { - mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); - setUpDisplaySizeWithApp(2000, 1000); - mActivity.info.screenOrientation = SCREEN_ORIENTATION_PORTRAIT; - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); - // Mock the activity as embedded without additional TaskFragment layer in the task for - // simplicity. - doReturn(true).when(mActivity).isEmbedded(); - // Translucent Activity - final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) - .setActivityTheme(android.R.style.Theme_Translucent).build(); - doReturn(false).when(translucentActivity).matchParentBounds(); - mTask.addChild(translucentActivity); - // Check the strategy has not being applied - assertFalse(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior()); - } - - @Test - public void testTranslucentActivitiesDontGoInSizeCompatMode() { - mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); - setUpDisplaySizeWithApp(2800, 1400); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); - prepareUnresizable(mActivity, -1f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); - // Rotate to put activity in size compat mode. - rotateDisplay(mActivity.mDisplayContent, ROTATION_90); - assertTrue(mActivity.inSizeCompatMode()); - // Rotate back - rotateDisplay(mActivity.mDisplayContent, ROTATION_0); - assertFalse(mActivity.inSizeCompatMode()); - // We launch a transparent activity - final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) - .setActivityTheme(android.R.style.Theme_Translucent) - .setLaunchedFromUid(mActivity.getUid()) - .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) - .build(); - mTask.addChild(translucentActivity); - // It should not be in SCM - assertFalse(translucentActivity.inSizeCompatMode()); - // We rotate again - rotateDisplay(translucentActivity.mDisplayContent, ROTATION_90); - assertFalse(translucentActivity.inSizeCompatMode()); - } - - @Test - public void testCheckOpaqueIsLetterboxedWhenStrategyIsApplied() { - mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); - setUpDisplaySizeWithApp(2000, 1000); - prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); - // Translucent Activity - final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) - .setActivityTheme(android.R.style.Theme_Translucent) - .setLaunchedFromUid(mActivity.getUid()) - .build(); - assertFalse(translucentActivity.fillsParent()); - assertTrue(mActivity.fillsParent()); - mActivity.finishing = true; - assertFalse(mActivity.occludesParent()); - mTask.addChild(translucentActivity); - // The translucent activity won't inherit letterbox behavior from a finishing activity. - assertFalse(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior()); - } - - @Test - public void testTranslucentActivitiesWhenUnfolding() { - mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); - setUpDisplaySizeWithApp(2800, 1400); - mActivity.mDisplayContent.setIgnoreOrientationRequest( - true /* ignoreOrientationRequest */); - mActivity.mWmService.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier( - 1.0f /*letterboxVerticalPositionMultiplier*/); - prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); - // We launch a transparent activity - final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) - .setActivityTheme(android.R.style.Theme_Translucent) - .setLaunchedFromUid(mActivity.getUid()) - .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) - .build(); - mTask.addChild(translucentActivity); - assertEquals(translucentActivity.getBounds(), mActivity.getBounds()); - - mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); - spyOn(mActivity); - - // Halffold - setFoldablePosture(translucentActivity, true /* isHalfFolded */, - false /* isTabletop */); - verify(mActivity).recomputeConfiguration(); - assertEquals(translucentActivity.getBounds(), mActivity.getBounds()); - clearInvocations(mActivity); - - // Unfold - setFoldablePosture(translucentActivity, false /* isHalfFolded */, - false /* isTabletop */); - verify(mActivity).recomputeConfiguration(); - assertEquals(translucentActivity.getBounds(), mActivity.getBounds()); - } - - @Test - public void testTranslucentActivity_clearSizeCompatMode_inheritedCompatDisplayInsetsCleared() { - mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); - setUpDisplaySizeWithApp(2800, 1400); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); - prepareUnresizable(mActivity, -1f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); - // Rotate to put activity in size compat mode. - rotateDisplay(mActivity.mDisplayContent, ROTATION_90); - assertTrue(mActivity.inSizeCompatMode()); - - // We launch a transparent activity - final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) - .setActivityTheme(android.R.style.Theme_Translucent) - .setLaunchedFromUid(mActivity.getUid()) - .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) - .build(); - mTask.addChild(translucentActivity); - - // The transparent activity inherits the compat display insets of the opaque activity - // beneath it - assertNotNull(translucentActivity.getCompatDisplayInsets()); - - // Clearing SCM should also clear the inherited compat display insets - translucentActivity.clearSizeCompatMode(); - assertNull(translucentActivity.getCompatDisplayInsets()); - } - - @Test public void testRestartProcessIfVisible() { setUpDisplaySizeWithApp(1000, 2500); doNothing().when(mSupervisor).scheduleRestartTimeout(mActivity); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java index d9fd312423d1..9670a9a44eb7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java @@ -1902,7 +1902,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { assertApplyTransactionAllowed(mTransaction); - verify(task).moveOrCreateDecorSurfaceFor(tf); + verify(task).moveOrCreateDecorSurfaceFor(tf, true /* visible */); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java index 225e85e03b26..6ecaea90b85b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -1695,7 +1695,7 @@ public class TaskTests extends WindowTestsBase { // Decor surface should be created. clearInvocations(task); - task.moveOrCreateDecorSurfaceFor(fragment); + task.moveOrCreateDecorSurfaceFor(fragment, true /* visible */); assertNotNull(task.mDecorSurfaceContainer); assertNotNull(task.getDecorSurface()); @@ -1722,14 +1722,14 @@ public class TaskTests extends WindowTestsBase { final TaskFragment fragment2 = createTaskFragmentWithEmbeddedActivity(task, organizer); doNothing().when(task).sendTaskFragmentParentInfoChangedIfNeeded(); - task.moveOrCreateDecorSurfaceFor(fragment1); + task.moveOrCreateDecorSurfaceFor(fragment1, true /* visible */); assertNotNull(task.mDecorSurfaceContainer); assertNotNull(task.getDecorSurface()); assertEquals(fragment1, task.mDecorSurfaceContainer.mOwnerTaskFragment); // Transfer ownership - task.moveOrCreateDecorSurfaceFor(fragment2); + task.moveOrCreateDecorSurfaceFor(fragment2, true /* visible */); assertNotNull(task.mDecorSurfaceContainer); assertNotNull(task.getDecorSurface()); @@ -1775,7 +1775,7 @@ public class TaskTests extends WindowTestsBase { doReturn(true).when(fragment2).isAllowedToBeEmbeddedInTrustedMode(); doReturn(true).when(fragment1).isVisible(); - task.moveOrCreateDecorSurfaceFor(fragment1); + task.moveOrCreateDecorSurfaceFor(fragment1, true /* visible */); task.assignChildLayers(t); verify(unembeddedActivity).assignLayer(t, 0); @@ -1880,7 +1880,7 @@ public class TaskTests extends WindowTestsBase { doReturn(false).when(fragment2).isAllowedToBeEmbeddedInTrustedMode(); doReturn(true).when(fragment1).isVisible(); - task.moveOrCreateDecorSurfaceFor(fragment1); + task.moveOrCreateDecorSurfaceFor(fragment1, true /* visible */); clearInvocations(t); clearInvocations(unembeddedActivity); @@ -1889,7 +1889,8 @@ public class TaskTests extends WindowTestsBase { // The decor surface should be placed above all the windows when boosted and the cover // surface should show. - task.setDecorSurfaceBoosted(fragment1, true /* isBoosted */, clientTransaction); + task.requestDecorSurfaceBoosted(fragment1, true /* isBoosted */, clientTransaction); + task.commitDecorSurfaceBoostedState(); verify(unembeddedActivity).assignLayer(t, 0); verify(fragment1).assignLayer(t, 1); @@ -1906,8 +1907,9 @@ public class TaskTests extends WindowTestsBase { // The decor surface should be placed just above the owner TaskFragment and the cover // surface should hide. - task.moveOrCreateDecorSurfaceFor(fragment1); - task.setDecorSurfaceBoosted(fragment1, false /* isBoosted */, clientTransaction); + task.moveOrCreateDecorSurfaceFor(fragment1, true /* visible */); + task.requestDecorSurfaceBoosted(fragment1, false /* isBoosted */, clientTransaction); + task.commitDecorSurfaceBoostedState(); verify(unembeddedActivity).assignLayer(t, 0); verify(fragment1).assignLayer(t, 1); diff --git a/services/tests/wmtests/src/com/android/server/wm/TransparentPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/TransparentPolicyTest.java new file mode 100644 index 000000000000..1d6e30777922 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/TransparentPolicyTest.java @@ -0,0 +1,637 @@ +/* + * 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.server.wm; + +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.ROTATION_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.view.Surface.ROTATION_0; +import static android.view.Surface.ROTATION_90; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.WindowConfiguration; +import android.content.res.Configuration; +import android.graphics.Rect; +import android.platform.test.annotations.Presubmit; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * Test class for {@link TransparentPolicy}. + * + * Build/Install/Run: + * atest WmTests:TransparentPolicyTest + */ +@Presubmit +@RunWith(WindowTestRunner.class) +public class TransparentPolicyTest extends WindowTestsBase { + + @Test + public void testNotStartingWhenDisabled() { + runTestScenario((robot) -> { + robot.launchTransparentActivityInTask(); + + robot.checkTopActivityPolicyStateIsNotRunning(); + }, /* policyEnabled */ false); + } + + @Test + public void testNotStartingWithoutTask() { + runTestScenario((robot) -> { + robot.launchTransparentActivity(); + + robot.checkTopActivityPolicyStartNotInvoked(); + robot.checkTopActivityPolicyStateIsNotRunning(); + }); + } + + @Test + public void testPolicyRunningWhenTransparentIsUsed() { + runTestScenario((robot) -> { + robot.launchTransparentActivityInTask(); + + robot.checkTopActivityPolicyStartNotInvoked(); + robot.checkTopActivityPolicyStateIsRunning(); + }); + } + + @Test + public void testCleanLetterboxConfigListenerWhenTranslucentIsDestroyed() { + runTestScenario((robot) -> { + robot.launchTransparentActivityInTask(); + robot.checkTopActivityPolicyStartNotInvoked(); + robot.checkTopActivityPolicyStateIsRunning(); + + robot.clearInteractions(); + robot.destroyTopActivity(); + + robot.checkTopActivityPolicyStopInvoked(); + robot.checkTopActivityPolicyStateIsNotRunning(); + }); + } + + @Test + public void testApplyStrategyAgainWhenOpaqueIsDestroyed() { + runTestScenario((robot) -> { + robot.launchOpaqueActivityInTask(); + robot.checkTopActivityPolicyStateIsNotRunning(); + + robot.launchTransparentActivityInTask(); + robot.checkTopActivityPolicyStateIsRunning(); + + robot.destroyActivity(/* fromTop */ 1); + robot.checkTopActivityPolicyStartInvoked(); + }); + } + + @Test + public void testResetOpaqueReferenceWhenOpaqueIsDestroyed() { + runTestScenario((robot) -> { + robot.launchTransparentActivityInTask(); + + robot.clearInteractions(); + robot.destroyActivity(/* fromTop */ 1); + + robot.checkTopActivityPolicyStartInvoked(); + robot.checkTopActivityPolicyStateIsNotRunning(); + }); + } + + @Test + public void testNotApplyStrategyAgainWhenOpaqueIsNotDestroyed() { + runTestScenario((robot) -> { + robot.launchOpaqueActivityInTask(); + robot.checkTopActivityPolicyStateIsNotRunning(); + + robot.launchTransparentActivityInTask(); + robot.checkTopActivityPolicyStateIsRunning(); + + robot.clearInteractions(); + robot.checkTopActivityPolicyStopNotInvoked(); + }); + } + + @Test + public void testApplyStrategyToTranslucentActivities() { + runTestScenario((robot) -> { + robot.configureTopActivity(/* minAspect */ 1.2f, /* maxAspect */ 1.5f, + SCREEN_ORIENTATION_PORTRAIT, /* isUnresizable */ true); + robot.configureTopActivityIgnoreOrientationRequest(true); + robot.launchActivity(/* minAspect */ 1.1f, /* maxAspect */ 3f, + SCREEN_ORIENTATION_LANDSCAPE, /* transparent */true, /* addToTask */true); + robot.checkTopActivityPolicyStateIsRunning(); + robot.checkTopActivityHasInheritedBoundsFrom(/* fromTop */ 1); + robot.checkTopOrientation(SCREEN_ORIENTATION_PORTRAIT); + robot.checkTopAspectRatios(/* minAspectRatio */ 1.2f, /* maxAspectRatio */ 1.5f); + }); + } + + @Test + public void testApplyStrategyToTransparentActivitiesRetainsWindowConfigurationProperties() { + runTestScenario((robot) -> { + robot.launchTransparentActivity(); + + robot.forceChangeInTopActivityConfiguration(); + robot.attachTopActivityToTask(); + + robot.checkTopActivityConfigurationConfiguration(); + }); + } + + @Test + public void testApplyStrategyToMultipleTranslucentActivities() { + runTestScenario((robot) -> { + robot.launchTransparentActivityInTask(); + robot.checkTopActivityPolicyStateIsRunning(); + robot.checkTopActivityHasInheritedBoundsFrom(/* fromTop */ 1); + + robot.launchTransparentActivityInTask(); + robot.checkTopActivityPolicyStateIsRunning(); + robot.checkTopActivityHasInheritedBoundsFrom(/* fromTop */ 2); + }); + } + + @Test + public void testNotApplyStrategyToTranslucentActivitiesOverEmbeddedActivities() { + runTestScenario((robot) -> { + robot.configureTopActivityAsEmbedded(); + robot.launchTransparentActivityInTask(); + + robot.checkTopActivityPolicyStartNotInvoked(); + robot.checkTopActivityPolicyStateIsNotRunning(); + }); + } + + @Test + public void testTranslucentActivitiesDontGoInSizeCompatMode() { + runTestScenario((robot) -> { + robot.configureTopActivityIgnoreOrientationRequest(true); + robot.configureUnresizableTopActivity(SCREEN_ORIENTATION_PORTRAIT); + robot.rotateDisplayForTopActivity(ROTATION_90); + robot.checkTopActivitySizeCompatMode(/* inScm */ true); + robot.rotateDisplayForTopActivity(ROTATION_0); + robot.checkTopActivitySizeCompatMode(/* inScm */ false); + + robot.launchTransparentActivityInTask(); + robot.checkTopActivitySizeCompatMode(/* inScm */ false); + robot.rotateDisplayForTopActivity(ROTATION_90); + robot.checkTopActivitySizeCompatMode(/* inScm */ false); + }, /* displayWidth */ 2800, /* displayHeight */ 1400); + } + + @Test + public void testCheckOpaqueIsLetterboxedWhenStrategyIsApplied() { + runTestScenario((robot) -> { + robot.configureUnresizableTopActivity(SCREEN_ORIENTATION_PORTRAIT); + robot.configureTopActivityIgnoreOrientationRequest(true); + robot.launchTransparentActivity(); + + robot.assertFalseOnTopActivity(ActivityRecord::fillsParent); + robot.assertTrueOnActivity(/* fromTop */ 1, ActivityRecord::fillsParent); + robot.applyTo(/* fromTop */ 1, (activity) -> { + activity.finishing = true; + }); + robot.assertFalseOnActivity(/* fromTop */ 1, ActivityRecord::occludesParent); + robot.attachTopActivityToTask(); + + robot.checkTopActivityPolicyStateIsNotRunning(); + }); + } + + @Test + public void testTranslucentActivitiesWhenUnfolding() { + runTestScenario((robot) -> { + robot.applyToTop((activity) -> { + activity.mWmService.mLetterboxConfiguration + .setLetterboxHorizontalPositionMultiplier(1.0f); + }); + robot.configureUnresizableTopActivity(SCREEN_ORIENTATION_PORTRAIT); + robot.configureTopActivityIgnoreOrientationRequest(true); + robot.launchTransparentActivityInTask(); + robot.checkTopActivityHasInheritedBoundsFrom(/* fromTop */ 1); + + robot.configureTaskWindowingMode(WINDOWING_MODE_FULLSCREEN); + + robot.configureTopActivityFoldablePosture(/* isHalfFolded */ true, + /* isTabletop */ false); + robot.checkTopActivityRecomputedConfiguration(); + robot.checkTopActivityHasInheritedBoundsFrom(/* fromTop */ 1); + robot.clearInteractions(); + + robot.configureTopActivityFoldablePosture(/* isHalfFolded */ false, + /* isTabletop */ false); + robot.checkTopActivityRecomputedConfiguration(); + robot.checkTopActivityHasInheritedBoundsFrom(/* fromTop */ 1); + }, /* displayWidth */ 2800, /* displayHeight */ 1400); + } + + + @Test + public void testTranslucentActivity_clearSizeCompatMode_inheritedCompatDisplayInsetsCleared() { + runTestScenario((robot) -> { + robot.configureTopActivityIgnoreOrientationRequest(true); + robot.configureUnresizableTopActivity(SCREEN_ORIENTATION_PORTRAIT); + // Rotate to put activity in size compat mode. + robot.rotateDisplayForTopActivity(ROTATION_90); + robot.checkTopActivitySizeCompatMode(/* inScm */ true); + + robot.launchTransparentActivityInTask(); + robot.assertNotNullOnTopActivity(ActivityRecord::getCompatDisplayInsets); + robot.applyToTop(ActivityRecord::clearSizeCompatMode); + robot.assertNullOnTopActivity(ActivityRecord::getCompatDisplayInsets); + }); + } + + private void runTestScenario(Consumer<TransparentPolicyRobotTest> consumer, + boolean policyEnabled, int displayWidth, int displayHeight) { + spyOn(mWm.mLetterboxConfiguration); + when(mWm.mLetterboxConfiguration.isTranslucentLetterboxingEnabled()) + .thenReturn(policyEnabled); + final TestDisplayContent.Builder builder = new TestDisplayContent.Builder(mAtm, + displayWidth, displayHeight); + final Task task = new TaskBuilder(mSupervisor).setDisplay(builder.build()) + .setCreateActivity(true).build(); + final ActivityRecord opaqueActivity = task.getTopNonFinishingActivity(); + final TransparentPolicyRobotTest robot = new TransparentPolicyRobotTest(mAtm, task, + opaqueActivity); + consumer.accept(robot); + } + + private void runTestScenario(Consumer<TransparentPolicyRobotTest> consumer, + int displayWidth, int displayHeight) { + runTestScenario(consumer, /* policyEnabled */ true, displayWidth, displayHeight); + } + + private void runTestScenario(Consumer<TransparentPolicyRobotTest> consumer, + boolean policyEnabled) { + runTestScenario(consumer, policyEnabled, /* displayWidth */ 2000, + /* displayHeight */ 1000); + } + + private void runTestScenario(Consumer<TransparentPolicyRobotTest> consumer) { + runTestScenario(consumer, /* policyEnabled */ true); + } + + /** + * Robot pattern implementation for TransparentPolicy + * TODO(b/344587983): Extract Robot to be reused in different test classes. + */ + private static class TransparentPolicyRobotTest { + + private final ActivityTaskManagerService mAtm; + + private final Task mTask; + + private final ActivityStackTest mActivityStack; + + private WindowConfiguration mTopActivityWindowConfiguration; + + private TransparentPolicyRobotTest(ActivityTaskManagerService atm, Task task, + ActivityRecord opaqueActivity) { + mAtm = atm; + mTask = task; + mActivityStack = new ActivityStackTest(); + mActivityStack.pushActivity(opaqueActivity); + spyOn(opaqueActivity.mTransparentPolicy); + } + + void configureTopActivityAsEmbedded() { + final ActivityRecord topActivity = mActivityStack.top(); + spyOn(topActivity); + doReturn(true).when(topActivity).isEmbedded(); + } + + private void launchActivity(float minAspectRatio, float maxAspectRatio, + @Configuration.Orientation int orientation, boolean transparent, + boolean addToTask) { + final ActivityBuilder activityBuilder = new ActivityBuilder(mAtm) + .setScreenOrientation(orientation) + .setLaunchedFromUid(mActivityStack.base().getUid()); + if (transparent) { + activityBuilder.setActivityTheme(android.R.style.Theme_Translucent); + } + if (minAspectRatio >= 0) { + activityBuilder.setMinAspectRatio(minAspectRatio); + } + if (maxAspectRatio >= 0) { + activityBuilder.setMaxAspectRatio(maxAspectRatio); + } + final ActivityRecord newActivity = activityBuilder.build(); + if (addToTask) { + mTask.addChild(newActivity); + } + spyOn(newActivity.mTransparentPolicy); + mActivityStack.pushActivity(newActivity); + } + + void attachTopActivityToTask() { + mTask.addChild(mActivityStack.top()); + } + + void launchTransparentActivity() { + launchActivity(/*minAspectRatio */ -1, /* maxAspectRatio */ -1, + SCREEN_ORIENTATION_PORTRAIT, /* transparent */ true, + /* addToTask */ false); + } + + void launchTransparentActivityInTask() { + launchActivity(/*minAspectRatio */ -1, /* maxAspectRatio */ -1, + SCREEN_ORIENTATION_PORTRAIT, /* transparent */ true, + /* addToTask */true); + } + + void launchOpaqueActivityInTask() { + launchActivity(/*minAspectRatio */ -1, /* maxAspectRatio */ -1, + SCREEN_ORIENTATION_PORTRAIT, /* transparent */ false, + /* addToTask */true); + } + + void destroyTopActivity() { + mActivityStack.top().removeImmediately(); + } + + void destroyActivity(int fromTop) { + mActivityStack.applyTo(/* fromTop */ fromTop, ActivityRecord::removeImmediately); + } + + void forceChangeInTopActivityConfiguration() { + mActivityStack.applyToTop((activity) -> { + final Configuration requestedConfig = activity.getRequestedOverrideConfiguration(); + mTopActivityWindowConfiguration = requestedConfig.windowConfiguration; + mTopActivityWindowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD); + mTopActivityWindowConfiguration.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); + mTopActivityWindowConfiguration.setAlwaysOnTop(true); + activity.onRequestedOverrideConfigurationChanged(requestedConfig); + }); + } + + void checkTopActivityPolicyStateIsRunning() { + assertTrue(mActivityStack.top().mTransparentPolicy.isRunning()); + } + + void checkTopActivityPolicyStateIsNotRunning() { + assertFalse(mActivityStack.top().mTransparentPolicy.isRunning()); + } + + void checkTopActivityPolicyStopInvoked() { + verify(mActivityStack.top().mTransparentPolicy).stop(); + } + + void checkTopActivityPolicyStopNotInvoked() { + mActivityStack.applyToTop((activity) -> { + verify(activity.mTransparentPolicy, never()).stop(); + }); + } + + void checkTopActivityPolicyStartInvoked() { + mActivityStack.applyToTop((activity) -> { + verify(activity.mTransparentPolicy).start(); + }); + } + + void checkTopActivityPolicyStartNotInvoked() { + verify(mActivityStack.top().mTransparentPolicy, never()).start(); + } + + void assertTrueOnActivity(int fromTop, Predicate<ActivityRecord> predicate) { + mActivityStack.applyTo(fromTop, (activity) -> { + Assert.assertTrue(predicate.test(activity)); + }); + } + + void assertFalseOnTopActivity(Predicate<ActivityRecord> predicate) { + Assert.assertFalse(predicate.test(mActivityStack.top())); + } + + void assertFalseOnActivity(int fromTop, Predicate<ActivityRecord> predicate) { + mActivityStack.applyTo(fromTop, (activity) -> { + Assert.assertFalse(predicate.test(activity)); + }); + } + + void assertNotNullOnTopActivity(Function<ActivityRecord, Object> getter) { + Assert.assertNotNull(getter.apply(mActivityStack.top())); + } + + void assertNullOnTopActivity(Function<ActivityRecord, Object> getter) { + Assert.assertNull(getter.apply(mActivityStack.top())); + } + + void checkTopActivityConfigurationConfiguration() { + mActivityStack.applyToTop((activity) -> { + // The original override of WindowConfiguration should keep. + assertEquals(ACTIVITY_TYPE_STANDARD, activity.getActivityType()); + assertEquals(WINDOWING_MODE_MULTI_WINDOW, + mTopActivityWindowConfiguration.getWindowingMode()); + assertTrue(mTopActivityWindowConfiguration.isAlwaysOnTop()); + // Unless display is going to be rotated, it should always inherit from parent. + assertEquals(ROTATION_UNDEFINED, + mTopActivityWindowConfiguration.getDisplayRotation()); + }); + } + + void checkTopActivityHasInheritedBoundsFrom(int fromTop) { + final ActivityRecord topActivity = mActivityStack.top(); + final ActivityRecord otherActivity = mActivityStack.getFromTop(/* fromTop */ fromTop); + final Rect opaqueBounds = otherActivity.getConfiguration().windowConfiguration + .getBounds(); + final Rect translucentRequestedBounds = topActivity.getRequestedOverrideBounds(); + Assert.assertEquals(opaqueBounds, translucentRequestedBounds); + } + + void checkTopActivityRecomputedConfiguration() { + verify(mActivityStack.top()).recomputeConfiguration(); + } + + void checkTopOrientation(int orientation) { + Assert.assertEquals(orientation, mActivityStack.top() + .getRequestedConfigurationOrientation()); + } + + void configureTaskWindowingMode(int windowingMode) { + mTask.setWindowingMode(windowingMode); + } + + void checkTopAspectRatios(float minAspectRatio, float maxAspectRatio) { + final ActivityRecord topActivity = mActivityStack.top(); + Assert.assertEquals(minAspectRatio, topActivity.getMinAspectRatio(), 0.0001); + Assert.assertEquals(maxAspectRatio, topActivity.getMaxAspectRatio(), 0.0001); + } + + void checkTopActivitySizeCompatMode(boolean inScm) { + Assert.assertEquals(inScm, mActivityStack.top().inSizeCompatMode()); + } + + void clearInteractions() { + mActivityStack.applyToAll((activity) -> { + clearInvocations(activity); + clearInvocations(activity.mTransparentPolicy); + }); + } + + void configureTopActivity(float minAspect, float maxAspect, int screenOrientation, + boolean isUnresizable) { + prepareLimitedBounds(mActivityStack.top(), minAspect, maxAspect, screenOrientation, + isUnresizable); + } + + void configureTopActivityIgnoreOrientationRequest(boolean ignoreOrientationRequest) { + mActivityStack.top().mDisplayContent + .setIgnoreOrientationRequest(ignoreOrientationRequest); + } + + void configureUnresizableTopActivity(int screenOrientation) { + configureTopActivity(-1, -1, screenOrientation, true); + } + + void applyToTop(Consumer<ActivityRecord> consumer) { + consumer.accept(mActivityStack.top()); + } + + void applyTo(int fromTop, Consumer<ActivityRecord> consumer) { + mActivityStack.applyTo(fromTop, consumer); + } + + void rotateDisplayForTopActivity(int rotation) { + rotateDisplay(mActivityStack.top().mDisplayContent, rotation); + } + + /** + * Setups activity with restriction on its bounds, such as maxAspect, minAspect, + * fixed orientation, and/or whether it is resizable. + */ + void prepareLimitedBounds(ActivityRecord activity, float minAspect, float maxAspect, + int screenOrientation, boolean isUnresizable) { + activity.info.resizeMode = isUnresizable + ? RESIZE_MODE_UNRESIZEABLE + : RESIZE_MODE_RESIZEABLE; + final Task task = activity.getTask(); + if (task != null) { + // Update the Task resize value as activity will follow the task. + task.mResizeMode = activity.info.resizeMode; + task.getRootActivity().info.resizeMode = activity.info.resizeMode; + } + activity.setVisibleRequested(true); + if (maxAspect >= 0) { + activity.info.setMaxAspectRatio(maxAspect); + } + if (minAspect >= 0) { + activity.info.setMinAspectRatio(minAspect); + } + if (screenOrientation != SCREEN_ORIENTATION_UNSPECIFIED) { + activity.info.screenOrientation = screenOrientation; + activity.setRequestedOrientation(screenOrientation); + } + // Make sure to use the provided configuration to construct the size compat fields. + activity.clearSizeCompatMode(); + activity.ensureActivityConfiguration(); + // Make sure the display configuration reflects the change of activity. + if (activity.mDisplayContent.updateOrientation()) { + activity.mDisplayContent.sendNewConfiguration(); + } + } + + void configureTopActivityFoldablePosture(boolean isHalfFolded, boolean isTabletop) { + mActivityStack.applyToTop((activity) -> { + final DisplayRotation r = activity.mDisplayContent.getDisplayRotation(); + doReturn(isHalfFolded).when(r).isDisplaySeparatingHinge(); + doReturn(false).when(r) + .isDeviceInPosture(any(DeviceStateController.DeviceState.class), + anyBoolean()); + if (isHalfFolded) { + doReturn(true).when(r) + .isDeviceInPosture(DeviceStateController.DeviceState.HALF_FOLDED, + isTabletop); + } + activity.recomputeConfiguration(); + }); + } + + private static void rotateDisplay(DisplayContent display, int rotation) { + final Configuration c = new Configuration(); + display.getDisplayRotation().setRotation(rotation); + display.computeScreenConfiguration(c); + display.onRequestedOverrideConfigurationChanged(c); + } + + /** + * Contains all the ActivityRecord launched in the test. This is different from what's in + * the Task because activities are added here even if not added to tasks. + */ + private static class ActivityStackTest { + private final List<ActivityRecord> mActivities = new ArrayList<>(); + + void pushActivity(ActivityRecord activityRecord) { + mActivities.add(activityRecord); + } + + void applyToTop(Consumer<ActivityRecord> consumer) { + consumer.accept(top()); + } + + ActivityRecord getFromTop(int fromTop) { + return mActivities.get(mActivities.size() - fromTop - 1); + } + + ActivityRecord base() { + return mActivities.get(0); + } + + ActivityRecord top() { + return mActivities.get(mActivities.size() - 1); + } + + // Allows access to the activity at position beforeLast from the top. + // If fromTop = 0 the activity used is the top one. + void applyTo(int fromTop, Consumer<ActivityRecord> consumer) { + consumer.accept(getFromTop(fromTop)); + } + + void applyToAll(Consumer<ActivityRecord> consumer) { + for (int i = mActivities.size() - 1; i >= 0; i--) { + consumer.accept(mActivities.get(i)); + } + } + } + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java index 9f85acb98817..4ebbf496b2a4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -960,10 +960,20 @@ public class WindowContainerTests extends WindowTestsBase { assertTrue(child.handlesOrientationChangeFromDescendant(orientation)); } + private static void addLocalInsets(WindowContainer wc) { + final Binder owner = new Binder(); + Rect genericOverlayInsetsRect1 = new Rect(0, 200, 1080, 700); + final InsetsFrameProvider provider1 = + new InsetsFrameProvider(owner, 1, WindowInsets.Type.systemOverlays()) + .setArbitraryRectangle(genericOverlayInsetsRect1); + wc.addLocalInsetsFrameProvider(provider1, owner); + } + @Test public void testOnDisplayChanged() { final Task rootTask = createTask(mDisplayContent); final Task task = createTaskInRootTask(rootTask, 0 /* userId */); + addLocalInsets(task); final ActivityRecord activity = createActivityRecord(mDisplayContent, task); final DisplayContent newDc = createNewDisplay(); @@ -972,6 +982,7 @@ public class WindowContainerTests extends WindowTestsBase { verify(rootTask).onDisplayChanged(newDc); verify(task).onDisplayChanged(newDc); + assertTrue(task.mLocalInsetsSources.size() == 1); verify(activity).onDisplayChanged(newDc); assertEquals(newDc, rootTask.mDisplayContent); assertEquals(newDc, task.mDisplayContent); @@ -981,6 +992,7 @@ public class WindowContainerTests extends WindowTestsBase { @Test public void testOnDisplayChanged_cleanupChanging() { final Task task = createTask(mDisplayContent); + addLocalInsets(task); spyOn(task.mSurfaceFreezer); mDisplayContent.mChangingContainers.add(task); @@ -988,6 +1000,7 @@ public class WindowContainerTests extends WindowTestsBase { // This happens on display info changed. task.onDisplayChanged(mDisplayContent); + assertTrue(task.mLocalInsetsSources.size() == 1); assertTrue(mDisplayContent.mChangingContainers.contains(task)); verify(task.mSurfaceFreezer, never()).unfreeze(any()); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index fb854c5bda68..ab4decacf0ca 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -31,6 +31,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED; import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; +import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; @@ -1455,6 +1456,53 @@ public class WindowOrganizerTests extends WindowTestsBase { } @Test + public void testReorderWithParents() { + /* + root + ____|______ + | | + firstTda secondTda + | | + firstRootTask secondRootTask + + */ + final TaskDisplayArea firstTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); + final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea( + mDisplayContent, mRootWindowContainer.mWmService, "TestTaskDisplayArea", + FEATURE_VENDOR_FIRST); + final Task firstRootTask = firstTaskDisplayArea.createRootTask( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); + final Task secondRootTask = secondTaskDisplayArea.createRootTask( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); + final ActivityRecord firstActivity = new ActivityBuilder(mAtm) + .setTask(firstRootTask).build(); + final ActivityRecord secondActivity = new ActivityBuilder(mAtm) + .setTask(secondRootTask).build(); + // This assertion is just a defense to ensure that firstRootTask is not the top most + // by default + assertThat(mDisplayContent.getTopRootTask()).isEqualTo(secondRootTask); + WindowContainerTransaction wct = new WindowContainerTransaction(); + + // Reorder to top + wct.reorder(firstRootTask.mRemoteToken.toWindowContainerToken(), true /* onTop */, + true /* includingParents */); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); + + // firstRootTask can only be on the top if its TDA was also reordered to the Top which + // in-turn ensures that the reorder happened including the parents. + assertThat(mDisplayContent.getTopRootTask()).isEqualTo(firstRootTask); + + // Reorder to bottom + wct.reorder(firstRootTask.mRemoteToken.toWindowContainerToken(), false /* onTop */, + true /* includingParents */); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); + + // firstRootTask can only be on the bottom if its TDA was also reordered to the bottom + // which in-turn ensures that the reorder happened including the parents. + assertThat(mDisplayContent.getBottomMostTask()).isEqualTo(firstRootTask); + } + + @Test public void testAppearDeferThenVanish() { final ITaskOrganizer organizer = registerMockOrganizer(); final Task rootTask = createRootTask(); diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 2e93cba80386..27c383c283a1 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -403,7 +403,9 @@ public class UsageStatsService extends SystemService implements mAppStandby.addListener(mStandbyChangeListener); - mPackageMonitor.register(getContext(), null, UserHandle.ALL, true); + mPackageMonitor.register(getContext(), + /* thread= */ USE_DEDICATED_HANDLER_THREAD ? mHandler.getLooper() : null, + UserHandle.ALL, true); IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED); filter.addAction(Intent.ACTION_USER_STARTED); diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index bc8f65edaa12..09cb464198b5 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -9842,6 +9842,43 @@ public class CarrierConfigManager { public static final String KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL = "remove_satellite_plmn_in_manual_network_scan_bool"; + + /** @hide */ + @IntDef({ + SATELLITE_DATA_SUPPORT_ONLY_RESTRICTED, + SATELLITE_DATA_SUPPORT_BANDWIDTH_CONSTRAINED, + SATELLITE_DATA_SUPPORT_ALL, + }) + public @interface SATELLITE_DATA_SUPPORT_MODE {} + + /** + * Doesn't support unrestricted traffic on satellite network. + * @hide + */ + public static final int SATELLITE_DATA_SUPPORT_ONLY_RESTRICTED = 0; + /** + * Support unrestricted but bandwidth_constrained traffic on satellite network. + * @hide + */ + public static final int SATELLITE_DATA_SUPPORT_BANDWIDTH_CONSTRAINED = 1; + /** + * Support unrestricted satellite network that serves all traffic. + * @hide + */ + public static final int SATELLITE_DATA_SUPPORT_ALL = 2; + /** + * Indicates what kind of traffic an {@link NetworkCapabilities#NET_CAPABILITY_NOT_RESTRICTED} + * satellite network can possibly support. The network may subject to further + * restrictions such as entitlement etc. + * If no data is allowed on satellite network, exclude + * {@link ApnSetting#INFRASTRUCTURE_SATELLITE} from APN infrastructure_bitmask, and this + * configuration is ignored. + * By default it only supports restricted data. + * @hide + */ + public static final String KEY_SATELLITE_DATA_SUPPORT_MODE_INT = + "satellite_data_support_mode_int"; + /** * Determine whether to override roaming Wi-Fi Calling preference when device is connected to * non-terrestrial network. @@ -11084,6 +11121,8 @@ public class CarrierConfigManager { sDefaults.putInt(KEY_PARAMETERS_USED_FOR_NTN_LTE_SIGNAL_BAR_INT, CellSignalStrengthLte.USE_RSRP); sDefaults.putBoolean(KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, true); + sDefaults.putInt(KEY_SATELLITE_DATA_SUPPORT_MODE_INT, + CarrierConfigManager.SATELLITE_DATA_SUPPORT_ONLY_RESTRICTED); sDefaults.putBoolean(KEY_OVERRIDE_WFC_ROAMING_MODE_WHILE_USING_NTN_BOOL, true); sDefaults.putInt(KEY_SATELLITE_ENTITLEMENT_STATUS_REFRESH_DAYS_INT, 7); sDefaults.putBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, false); diff --git a/telephony/java/android/telephony/TelephonyFrameworkInitializer.java b/telephony/java/android/telephony/TelephonyFrameworkInitializer.java index f5688bfffa02..7356cdc8889b 100644 --- a/telephony/java/android/telephony/TelephonyFrameworkInitializer.java +++ b/telephony/java/android/telephony/TelephonyFrameworkInitializer.java @@ -83,7 +83,7 @@ public class TelephonyFrameworkInitializer { // Check SDK version of the vendor partition. final int vendorApiLevel = SystemProperties.getInt( "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT); - if (vendorApiLevel < Build.VERSION_CODES.VANILLA_ICE_CREAM) return true; + if (vendorApiLevel < Build.VENDOR_API_2024_Q2) return true; // Check SDK version of the client app. if (!Compatibility.isChangeEnabled(ENABLE_CHECKING_TELEPHONY_FEATURES)) return true; diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java index 47f53f372d33..2a359cd56d1b 100644 --- a/telephony/java/android/telephony/satellite/SatelliteManager.java +++ b/telephony/java/android/telephony/satellite/SatelliteManager.java @@ -193,6 +193,14 @@ public final class SatelliteManager { /** * Bundle key to get the response from + * {@link #requestSessionStats(Executor, OutcomeReceiver)}. + * @hide + */ + + public static final String KEY_SESSION_STATS = "session_stats"; + + /** + * Bundle key to get the response from * {@link #requestIsProvisioned(Executor, OutcomeReceiver)}. * @hide */ @@ -2493,6 +2501,65 @@ public final class SatelliteManager { } } + /** + * Request to get the {@link SatelliteSessionStats} of the satellite service. + * + * @param executor The executor on which the callback will be called. + * @param callback The callback object to which the result will be delivered. + * If the request is successful, {@link OutcomeReceiver#onResult(Object)} + * will return the {@link SatelliteSessionStats} of the satellite service. + * If the request is not successful, {@link OutcomeReceiver#onError(Throwable)} + * will return a {@link SatelliteException} with the {@link SatelliteResult}. + * + * @throws SecurityException if the caller doesn't have required permission. + * @hide + */ + @RequiresPermission(allOf = {Manifest.permission.PACKAGE_USAGE_STATS, + Manifest.permission.MODIFY_PHONE_STATE}) + @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) + public void requestSessionStats(@NonNull @CallbackExecutor Executor executor, + @NonNull OutcomeReceiver<SatelliteSessionStats, SatelliteException> callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + ResultReceiver receiver = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == SATELLITE_RESULT_SUCCESS) { + if (resultData.containsKey(KEY_SESSION_STATS)) { + SatelliteSessionStats stats = + resultData.getParcelable(KEY_SESSION_STATS, + SatelliteSessionStats.class); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onResult(stats))); + } else { + loge("KEY_SESSION_STATS does not exist."); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onError(new SatelliteException( + SATELLITE_RESULT_REQUEST_FAILED)))); + } + } else { + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onError(new SatelliteException(resultCode)))); + } + } + }; + telephony.requestSatelliteSessionStats(mSubId, receiver); + } else { + loge("requestSessionStats() invalid telephony"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE)))); + } + } catch (RemoteException ex) { + loge("requestSessionStats() RemoteException: " + ex); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE)))); + } + } + @Nullable private static ITelephony getITelephony() { ITelephony binder = ITelephony.Stub.asInterface(TelephonyFrameworkInitializer diff --git a/telephony/java/android/telephony/satellite/SatelliteSessionStats.aidl b/telephony/java/android/telephony/satellite/SatelliteSessionStats.aidl new file mode 100644 index 000000000000..417512504969 --- /dev/null +++ b/telephony/java/android/telephony/satellite/SatelliteSessionStats.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 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.telephony.satellite; + + parcelable SatelliteSessionStats;
\ No newline at end of file diff --git a/telephony/java/android/telephony/satellite/SatelliteSessionStats.java b/telephony/java/android/telephony/satellite/SatelliteSessionStats.java new file mode 100644 index 000000000000..aabb058691d8 --- /dev/null +++ b/telephony/java/android/telephony/satellite/SatelliteSessionStats.java @@ -0,0 +1,224 @@ +/* + * 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.telephony.satellite; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * SatelliteSessionStats is used to represent the usage stats of the satellite service. + * @hide + */ +public class SatelliteSessionStats implements Parcelable { + private int mCountOfSuccessfulUserMessages; + private int mCountOfUnsuccessfulUserMessages; + private int mCountOfTimedOutUserMessagesWaitingForConnection; + private int mCountOfTimedOutUserMessagesWaitingForAck; + private int mCountOfUserMessagesInQueueToBeSent; + + /** + * SatelliteSessionStats constructor + * @param builder Builder to create SatelliteSessionStats object/ + */ + public SatelliteSessionStats(@NonNull Builder builder) { + mCountOfSuccessfulUserMessages = builder.mCountOfSuccessfulUserMessages; + mCountOfUnsuccessfulUserMessages = builder.mCountOfUnsuccessfulUserMessages; + mCountOfTimedOutUserMessagesWaitingForConnection = + builder.mCountOfTimedOutUserMessagesWaitingForConnection; + mCountOfTimedOutUserMessagesWaitingForAck = + builder.mCountOfTimedOutUserMessagesWaitingForAck; + mCountOfUserMessagesInQueueToBeSent = builder.mCountOfUserMessagesInQueueToBeSent; + } + + private SatelliteSessionStats(Parcel in) { + readFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeInt(mCountOfSuccessfulUserMessages); + out.writeInt(mCountOfUnsuccessfulUserMessages); + out.writeInt(mCountOfTimedOutUserMessagesWaitingForConnection); + out.writeInt(mCountOfTimedOutUserMessagesWaitingForAck); + out.writeInt(mCountOfUserMessagesInQueueToBeSent); + } + + @NonNull + public static final Creator<SatelliteSessionStats> CREATOR = new Parcelable.Creator<>() { + + @Override + public SatelliteSessionStats createFromParcel(Parcel in) { + return new SatelliteSessionStats(in); + } + + @Override + public SatelliteSessionStats[] newArray(int size) { + return new SatelliteSessionStats[size]; + } + }; + + @Override + @NonNull + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("countOfSuccessfulUserMessages:"); + sb.append(mCountOfSuccessfulUserMessages); + sb.append(","); + + sb.append("countOfUnsuccessfulUserMessages:"); + sb.append(mCountOfUnsuccessfulUserMessages); + sb.append(","); + + sb.append("countOfTimedOutUserMessagesWaitingForConnection:"); + sb.append(mCountOfTimedOutUserMessagesWaitingForConnection); + sb.append(","); + + sb.append("countOfTimedOutUserMessagesWaitingForAck:"); + sb.append(mCountOfTimedOutUserMessagesWaitingForAck); + sb.append(","); + + sb.append("countOfUserMessagesInQueueToBeSent:"); + sb.append(mCountOfUserMessagesInQueueToBeSent); + return sb.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SatelliteSessionStats that = (SatelliteSessionStats) o; + return mCountOfSuccessfulUserMessages == that.mCountOfSuccessfulUserMessages + && mCountOfUnsuccessfulUserMessages == that.mCountOfUnsuccessfulUserMessages + && mCountOfTimedOutUserMessagesWaitingForConnection + == that.mCountOfTimedOutUserMessagesWaitingForConnection + && mCountOfTimedOutUserMessagesWaitingForAck + == that.mCountOfTimedOutUserMessagesWaitingForAck + && mCountOfUserMessagesInQueueToBeSent + == that.mCountOfUserMessagesInQueueToBeSent; + } + + @Override + public int hashCode() { + return Objects.hash(mCountOfSuccessfulUserMessages, mCountOfUnsuccessfulUserMessages, + mCountOfTimedOutUserMessagesWaitingForConnection, + mCountOfTimedOutUserMessagesWaitingForAck, + mCountOfUserMessagesInQueueToBeSent); + } + + public int getCountOfSuccessfulUserMessages() { + return mCountOfSuccessfulUserMessages; + } + + public int getCountOfUnsuccessfulUserMessages() { + return mCountOfUnsuccessfulUserMessages; + } + + public int getCountOfTimedOutUserMessagesWaitingForConnection() { + return mCountOfTimedOutUserMessagesWaitingForConnection; + } + + public int getCountOfTimedOutUserMessagesWaitingForAck() { + return mCountOfTimedOutUserMessagesWaitingForAck; + } + + public int getCountOfUserMessagesInQueueToBeSent() { + return mCountOfUserMessagesInQueueToBeSent; + } + + private void readFromParcel(Parcel in) { + mCountOfSuccessfulUserMessages = in.readInt(); + mCountOfUnsuccessfulUserMessages = in.readInt(); + mCountOfTimedOutUserMessagesWaitingForConnection = in.readInt(); + mCountOfTimedOutUserMessagesWaitingForAck = in.readInt(); + mCountOfUserMessagesInQueueToBeSent = in.readInt(); + } + + /** + * A builder class to create {@link SatelliteSessionStats} data object. + */ + public static final class Builder { + private int mCountOfSuccessfulUserMessages; + private int mCountOfUnsuccessfulUserMessages; + private int mCountOfTimedOutUserMessagesWaitingForConnection; + private int mCountOfTimedOutUserMessagesWaitingForAck; + private int mCountOfUserMessagesInQueueToBeSent; + + /** + * Sets countOfSuccessfulUserMessages value of {@link SatelliteSessionStats} + * and then returns the Builder class. + */ + @NonNull + public Builder setCountOfSuccessfulUserMessages(int count) { + mCountOfSuccessfulUserMessages = count; + return this; + } + + /** + * Sets countOfUnsuccessfulUserMessages value of {@link SatelliteSessionStats} + * and then returns the Builder class. + */ + @NonNull + public Builder setCountOfUnsuccessfulUserMessages(int count) { + mCountOfUnsuccessfulUserMessages = count; + return this; + } + + /** + * Sets countOfTimedOutUserMessagesWaitingForConnection value of + * {@link SatelliteSessionStats} and then returns the Builder class. + */ + @NonNull + public Builder setCountOfTimedOutUserMessagesWaitingForConnection(int count) { + mCountOfTimedOutUserMessagesWaitingForConnection = count; + return this; + } + + /** + * Sets countOfTimedOutUserMessagesWaitingForAck value of {@link SatelliteSessionStats} + * and then returns the Builder class. + */ + @NonNull + public Builder setCountOfTimedOutUserMessagesWaitingForAck(int count) { + mCountOfTimedOutUserMessagesWaitingForAck = count; + return this; + } + + /** + * Sets countOfUserMessagesInQueueToBeSent value of {@link SatelliteSessionStats} + * and then returns the Builder class. + */ + @NonNull + public Builder setCountOfUserMessagesInQueueToBeSent(int count) { + mCountOfUserMessagesInQueueToBeSent = count; + return this; + } + + /** Returns SatelliteSessionStats object. */ + @NonNull + public SatelliteSessionStats build() { + return new SatelliteSessionStats(this); + } + } +} diff --git a/telephony/java/android/telephony/satellite/stub/ISatelliteListener.aidl b/telephony/java/android/telephony/satellite/stub/ISatelliteListener.aidl index 5b9dfc67c68c..b4eb15fde632 100644 --- a/telephony/java/android/telephony/satellite/stub/ISatelliteListener.aidl +++ b/telephony/java/android/telephony/satellite/stub/ISatelliteListener.aidl @@ -81,4 +81,12 @@ oneway interface ISatelliteListener { * @param supported True means satellite service is supported and false means it is not. */ void onSatelliteSupportedStateChanged(in boolean supported); + + /** + * Indicates that the satellite registration failed with following failure code + * + * @param causeCode the primary failure cause code of the procedure. + * For LTE (EMM), cause codes are TS 24.301 Sec 9.9.3.9 + */ + void onRegistrationFailure(in int causeCode); } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 9af73eae48a6..9b01b71fc596 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -3390,4 +3390,14 @@ interface ITelephony { * @return {@code true} if the setting is successful, {@code false} otherwise. */ boolean setIsSatelliteCommunicationAllowedForCurrentLocationCache(in String state); + + /** + * Request to get the session stats of the satellite service. + * + * @param subId The subId of the subscription to get the session stats for. + * @param receiver Result receiver to get the error code of the request and the requested + * session stats of the satellite service. + * @hide + */ + void requestSatelliteSessionStats(int subId, in ResultReceiver receiver); } diff --git a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt index c7da778b752b..c49b509a9db3 100644 --- a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt +++ b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt @@ -21,6 +21,7 @@ import android.tools.device.apphelpers.StandardAppHelper import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.flicker.subject.layers.LayerTraceEntrySubject +import android.tools.flicker.subject.layers.LayersTraceSubject import android.tools.traces.component.ComponentNameMatcher import android.tools.traces.component.IComponentMatcher import android.tools.traces.surfaceflinger.Display @@ -46,6 +47,7 @@ abstract class RotationTransition(flicker: LegacyFlickerTest) : BaseTest(flicker flicker.assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry( ignoreLayers = + LayersTraceSubject.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS + listOf( ComponentNameMatcher.SPLASH_SCREEN, ComponentNameMatcher.SNAPSHOT, diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp index c0cbdc3f96f8..f367c38b06e9 100644 --- a/tests/Input/Android.bp +++ b/tests/Input/Android.bp @@ -18,26 +18,31 @@ android_test { "src/**/*.java", "src/**/*.kt", ], + asset_dirs: ["assets"], kotlincflags: [ "-Werror", ], platform_apis: true, certificate: "platform", static_libs: [ + "android.view.flags-aconfig-java", "androidx.test.core", "androidx.test.ext.junit", "androidx.test.ext.truth", "androidx.test.rules", "androidx.test.runner", "androidx.test.uiautomator_uiautomator", + "collector-device-lib", "compatibility-device-util-axt", "cts-input-lib", + "cts-wm-util", "flag-junit", "frameworks-base-testutils", "hamcrest-library", "kotlin-test", "mockito-target-minus-junit4", "platform-test-annotations", + "platform-screenshot-diff-core", "services.core.unboosted", "servicestests-utils", "testables", diff --git a/tests/Input/AndroidManifest.xml b/tests/Input/AndroidManifest.xml index 3b723ddf811f..a05d08ccceba 100644 --- a/tests/Input/AndroidManifest.xml +++ b/tests/Input/AndroidManifest.xml @@ -22,6 +22,8 @@ <uses-permission android:name="android.permission.MONITOR_INPUT"/> <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/> <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> + <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/> <application android:label="InputTest" android:debuggable="true"> diff --git a/tests/Input/AndroidTest.xml b/tests/Input/AndroidTest.xml index f602c5124e77..8db37058af2b 100644 --- a/tests/Input/AndroidTest.xml +++ b/tests/Input/AndroidTest.xml @@ -28,4 +28,10 @@ <!-- Take screenshot upon test failure --> <option name="screenshot-on-failure" value="true" /> </object> + <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> + <option name="pull-pattern-keys" value="input_.*" /> + <!-- Pull files created by tests, like the output of screenshot tests --> + <option name="directory-keys" value="/storage/emulated/0/InputTests" /> + <option name="collect-on-run-ended-only" value="false" /> + </metrics_collector> </configuration> diff --git a/tests/Input/assets/testPointerFillStyle.png b/tests/Input/assets/testPointerFillStyle.png Binary files differnew file mode 100644 index 000000000000..b2354f8f4799 --- /dev/null +++ b/tests/Input/assets/testPointerFillStyle.png diff --git a/tests/Input/src/com/android/test/input/AnrTest.kt b/tests/Input/src/com/android/test/input/AnrTest.kt index 6b95f5c10a1e..8d1fc508ffe7 100644 --- a/tests/Input/src/com/android/test/input/AnrTest.kt +++ b/tests/Input/src/com/android/test/input/AnrTest.kt @@ -29,6 +29,7 @@ import android.os.IInputConstants.UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLI import android.os.SystemClock import android.provider.Settings import android.provider.Settings.Global.HIDE_ERROR_DIALOGS +import android.server.wm.CtsWindowInfoUtils.waitForStableWindowGeometry import android.testing.PollingCheck import androidx.test.uiautomator.By @@ -36,13 +37,17 @@ import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiObject2 import androidx.test.uiautomator.Until +import com.android.cts.input.DebugInputRule import com.android.cts.input.UinputTouchScreen +import java.util.concurrent.TimeUnit + import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Assert.fail import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -71,6 +76,9 @@ class AnrTest { private val DISPATCHING_TIMEOUT = (UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS * Build.HW_TIMEOUT_MULTIPLIER) + @get:Rule + val debugInputRule = DebugInputRule() + @Before fun setUp() { val contentResolver = instrumentation.targetContext.contentResolver @@ -86,12 +94,14 @@ class AnrTest { } @Test + @DebugInputRule.DebugInput(bug = 339924248) fun testGestureMonitorAnr_Close() { triggerAnr() clickCloseAppOnAnrDialog() } @Test + @DebugInputRule.DebugInput(bug = 339924248) fun testGestureMonitorAnr_Wait() { triggerAnr() clickWaitOnAnrDialog() @@ -107,7 +117,7 @@ class AnrTest { val closeAppButton: UiObject2? = uiDevice.wait(Until.findObject(By.res("android:id/aerr_close")), 20000) if (closeAppButton == null) { - fail("Could not find anr dialog") + fail("Could not find anr dialog/close button") return } closeAppButton.click() @@ -183,5 +193,6 @@ class AnrTest { val flags = " -W -n " val startCmd = "am start $flags $PACKAGE_NAME/.UnresponsiveGestureMonitorActivity" instrumentation.uiAutomation.executeShellCommand(startCmd) + waitForStableWindowGeometry(5L, TimeUnit.SECONDS) } } diff --git a/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt b/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt new file mode 100644 index 000000000000..dac425329f48 --- /dev/null +++ b/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt @@ -0,0 +1,114 @@ +/* + * Copyright 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.test.input + +import android.content.Context +import android.content.res.Configuration +import android.content.res.Resources +import android.os.Environment +import android.view.ContextThemeWrapper +import android.view.PointerIcon +import android.view.flags.Flags.enableVectorCursorA11ySettings +import android.view.flags.Flags.enableVectorCursors +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assume.assumeTrue +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TestName +import org.junit.runner.RunWith +import platform.test.screenshot.GoldenPathManager +import platform.test.screenshot.PathConfig +import platform.test.screenshot.ScreenshotTestRule +import platform.test.screenshot.assertAgainstGolden +import platform.test.screenshot.matchers.BitmapMatcher +import platform.test.screenshot.matchers.PixelPerfectMatcher + +/** + * Unit tests for PointerIcon. + * + * Run with: + * atest InputTests:com.android.test.input.PointerIconLoadingTest + */ +@SmallTest +@RunWith(AndroidJUnit4::class) +class PointerIconLoadingTest { + private lateinit var context: Context + private lateinit var exactScreenshotMatcher: BitmapMatcher + + @get:Rule + val testName = TestName() + + @get:Rule + val screenshotRule = ScreenshotTestRule(GoldenPathManager( + InstrumentationRegistry.getInstrumentation().getContext(), + ASSETS_PATH, + TEST_OUTPUT_PATH, + PathConfig() + ), disableIconPool = false) + + @Before + fun setUp() { + context = InstrumentationRegistry.getInstrumentation().targetContext + val config = + Configuration(context.resources.configuration).apply { + densityDpi = DENSITY_DPI + screenWidthDp = SCREEN_WIDTH_DP + screenHeightDp = SCREEN_HEIGHT_DP + smallestScreenWidthDp = SCREEN_WIDTH_DP + } + context = context.createConfigurationContext(config) + + exactScreenshotMatcher = PixelPerfectMatcher() + } + + @Test + fun testPointerFillStyle() { + assumeTrue(enableVectorCursors()) + assumeTrue(enableVectorCursorA11ySettings()) + + val theme: Resources.Theme = context.getResources().newTheme() + theme.setTo(context.getTheme()) + theme.applyStyle( + PointerIcon.vectorFillStyleToResource(PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_GREEN), + /* force= */ true) + + val pointerIcon = + PointerIcon.getLoadedSystemIcon( + ContextThemeWrapper(context, theme), + PointerIcon.TYPE_ARROW, + /* useLargeIcons= */ false) + + pointerIcon.getBitmap().assertAgainstGolden( + screenshotRule, + testName.methodName, + exactScreenshotMatcher + ) + } + + companion object { + const val DENSITY_DPI = 160 + const val SCREEN_WIDTH_DP = 480 + const val SCREEN_HEIGHT_DP = 800 + const val ASSETS_PATH = "tests/input/assets" + val TEST_OUTPUT_PATH = Environment.getExternalStorageDirectory().absolutePath + + "/InputTests/" + + PointerIconLoadingTest::class.java.simpleName + } +} diff --git a/tests/Internal/src/com/android/internal/protolog/LegacyProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/LegacyProtoLogImplTest.java index 5cdfb2858b33..5a27593c7a36 100644 --- a/tests/Internal/src/com/android/internal/protolog/LegacyProtoLogImplTest.java +++ b/tests/Internal/src/com/android/internal/protolog/LegacyProtoLogImplTest.java @@ -393,5 +393,10 @@ public class LegacyProtoLogImplTest { this.mLogToLogcat = logToLogcat; } + @Override + public int getId() { + return ordinal(); + } + } } diff --git a/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java index f6ac080ebf73..1d7b6b348e10 100644 --- a/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java +++ b/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java @@ -725,5 +725,10 @@ public class PerfettoProtoLogImplTest { this.mLogToLogcat = logToLogcat; } + @Override + public int getId() { + return ordinal(); + } + } } diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java index 4267c2c127ae..60456f9ea10f 100644 --- a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java +++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java @@ -174,5 +174,10 @@ public class ProtoLogImplTest { this.mLogToLogcat = logToLogcat; } + @Override + public int getId() { + return ordinal(); + } + } } |