diff options
979 files changed, 14255 insertions, 4539 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 2dd16de3e188..4d9fdf041d58 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -587,6 +587,7 @@ aconfig_declarations { java_aconfig_library { name: "android.view.inputmethod.flags-aconfig-java", aconfig_declarations: "android.view.inputmethod.flags-aconfig", + host_supported: true, defaults: ["framework-minus-apex-aconfig-java-defaults"], } diff --git a/apct-tests/perftests/core/src/android/input/OWNERS b/apct-tests/perftests/core/src/android/input/OWNERS deleted file mode 100644 index 95e3f0213f49..000000000000 --- a/apct-tests/perftests/core/src/android/input/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -include platform/frameworks/base:/INPUT_OWNERS - -# Bug component: 136048 diff --git a/apct-tests/perftests/input/Android.bp b/apct-tests/perftests/input/Android.bp new file mode 100644 index 000000000000..21b66cf3245c --- /dev/null +++ b/apct-tests/perftests/input/Android.bp @@ -0,0 +1,44 @@ +// Copyright 2025 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 { + default_team: "trendy_team_input_framework", + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test { + name: "InputPerfTests", + srcs: ["src/**/*.kt"], + kotlincflags: [ + "-Werror", + ], + static_libs: [ + "androidx.annotation_annotation", + "androidx.test.rules", + "apct-perftests-utils", + "collector-device-lib", + "compatibility-device-util-axt", + "cts-input-lib", + "platform-test-annotations", + ], + test_suites: ["device-tests"], + data: [":perfetto_artifacts"], + platform_apis: true, + certificate: "platform", +} diff --git a/apct-tests/perftests/input/AndroidManifest.xml b/apct-tests/perftests/input/AndroidManifest.xml new file mode 100644 index 000000000000..e9e4fd071b47 --- /dev/null +++ b/apct-tests/perftests/input/AndroidManifest.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2025 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. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.perftests.input"> + + <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + + <application> + <uses-library android:name="android.test.runner" /> + <activity android:name="com.android.cts.input.CaptureEventActivity" + android:label="Capture events" + android:configChanges="touchscreen|uiMode|orientation|screenSize|screenLayout|keyboardHidden|uiMode|navigation|keyboard|density|fontScale|layoutDirection|locale|mcc|mnc|smallestScreenSize" + android:enableOnBackInvokedCallback="false" + android:turnScreenOn="true" + android:exported="true"> + </activity> + </application> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.perftests.input"> + <meta-data android:name="listener" android:value="android.input.InputPerfRunPrecondition" /> + </instrumentation> +</manifest> diff --git a/apct-tests/perftests/input/OWNERS b/apct-tests/perftests/input/OWNERS new file mode 100644 index 000000000000..3cffce960b1c --- /dev/null +++ b/apct-tests/perftests/input/OWNERS @@ -0,0 +1,2 @@ +# Bug component: 136048 +include /core/java/android/hardware/input/OWNERS diff --git a/apct-tests/perftests/input/src/android/input/InputPerfRunPrecondition.kt b/apct-tests/perftests/input/src/android/input/InputPerfRunPrecondition.kt new file mode 100644 index 000000000000..d992380241a4 --- /dev/null +++ b/apct-tests/perftests/input/src/android/input/InputPerfRunPrecondition.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2025 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.input + +import android.perftests.utils.WindowPerfRunPreconditionBase + +/** Prepare the preconditions before running performance test. */ +class InputPerfRunPrecondition : WindowPerfRunPreconditionBase() diff --git a/apct-tests/perftests/core/src/android/input/MotionPredictorBenchmark.kt b/apct-tests/perftests/input/src/android/input/MotionPredictorBenchmark.kt index cf93331d87c2..cf93331d87c2 100644 --- a/apct-tests/perftests/core/src/android/input/MotionPredictorBenchmark.kt +++ b/apct-tests/perftests/input/src/android/input/MotionPredictorBenchmark.kt diff --git a/apct-tests/perftests/input/src/android/input/TouchPerfTest.kt b/apct-tests/perftests/input/src/android/input/TouchPerfTest.kt new file mode 100644 index 000000000000..26f101d91573 --- /dev/null +++ b/apct-tests/perftests/input/src/android/input/TouchPerfTest.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2025 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.input + +import android.cts.input.EventVerifier +import android.perftests.utils.PerfStatusReporter +import android.view.MotionEvent.ACTION_DOWN +import android.view.MotionEvent.ACTION_MOVE +import android.view.MotionEvent.ACTION_UP +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import com.android.cts.input.CaptureEventActivity +import com.android.cts.input.UinputTouchScreen +import com.android.cts.input.VirtualDisplayActivityScenario +import com.android.cts.input.inputeventmatchers.withMotionAction +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TestName +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class TouchPerfTest { + @get:Rule val testName = TestName() + @get:Rule val perfStatusReporter = PerfStatusReporter() + @get:Rule + val virtualDisplayRule = VirtualDisplayActivityScenario.Rule<CaptureEventActivity>(testName) + + private val instrumentation = InstrumentationRegistry.getInstrumentation() + + @Test + fun testDownMoveUp() { + UinputTouchScreen(instrumentation, virtualDisplayRule.virtualDisplay.display).use { + touchScreen -> + val verifier = EventVerifier(virtualDisplayRule.activity::getInputEvent) + val state = perfStatusReporter.benchmarkState + + while (state.keepRunning()) { + val x = 100 + val y = 100 + + val pointer = touchScreen.touchDown(x, y) + verifier.assertReceivedMotion(withMotionAction(ACTION_DOWN)) + + pointer.moveTo(x + 1, y + 1) + verifier.assertReceivedMotion(withMotionAction(ACTION_MOVE)) + + pointer.lift() + verifier.assertReceivedMotion(withMotionAction(ACTION_UP)) + } + } + } +} diff --git a/apct-tests/perftests/core/src/android/input/VelocityTrackerBenchmarkTest.kt b/apct-tests/perftests/input/src/android/input/VelocityTrackerBenchmarkTest.kt index c6fe32467099..df58cca42d44 100644 --- a/apct-tests/perftests/core/src/android/input/VelocityTrackerBenchmarkTest.kt +++ b/apct-tests/perftests/input/src/android/input/VelocityTrackerBenchmarkTest.kt @@ -19,8 +19,8 @@ import android.perftests.utils.PerfStatusReporter import android.view.InputDevice import android.view.MotionEvent import android.view.VelocityTracker +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.LargeTest -import androidx.test.runner.AndroidJUnit4 import java.time.Duration import org.junit.Assert import org.junit.Before diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java index 251776e907d8..44e4999ccf44 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java @@ -5369,7 +5369,9 @@ public class AlarmManagerService extends SystemService { // to do any wakelock or stats tracking, so we have nothing // left to do here but go on to the next thing. mSendFinishCount++; - if (Flags.acquireWakelockBeforeSend()) { + if (Flags.acquireWakelockBeforeSend() && mBroadcastRefCount == 0) { + // No other alarms are in-flight and this dispatch failed. We will + // acquire the wakelock again before the next dispatch. mWakeLock.release(); } return; @@ -5409,7 +5411,9 @@ public class AlarmManagerService extends SystemService { // stats management to do. It threw before we posted the delayed // timeout message, so we're done here. mListenerFinishCount++; - if (Flags.acquireWakelockBeforeSend()) { + if (Flags.acquireWakelockBeforeSend() && mBroadcastRefCount == 0) { + // No other alarms are in-flight and this dispatch failed. We will + // acquire the wakelock again before the next dispatch. mWakeLock.release(); } return; diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java index ae150aece432..378bb2d8e6b7 100644 --- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java +++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java @@ -1138,6 +1138,10 @@ public class Bmgr { } out.append("]"); } + if (event.containsKey(BackupManagerMonitor.EXTRA_LOG_CANCELLATION_REASON)) { + out.append(" cancellationReason: "); + out.append(event.getInt(BackupManagerMonitor.EXTRA_LOG_CANCELLATION_REASON)); + } if (mVerbose) { Set<String> remainingKeys = new ArraySet<>(event.keySet()); remainingKeys.remove(BackupManagerMonitor.EXTRA_LOG_EVENT_ID); diff --git a/cmds/svc/src/com/android/commands/svc/UsbCommand.java b/cmds/svc/src/com/android/commands/svc/UsbCommand.java index 26e20f601c7a..6542d08d6384 100644 --- a/cmds/svc/src/com/android/commands/svc/UsbCommand.java +++ b/cmds/svc/src/com/android/commands/svc/UsbCommand.java @@ -89,6 +89,11 @@ public class UsbCommand extends Svc.Command { IUsbManager usbMgr = IUsbManager.Stub.asInterface(ServiceManager.getService( Context.USB_SERVICE)); + if (usbMgr == null) { + System.err.println("Could not obtain USB service. Try again later."); + return; + } + Executor executor = context.getMainExecutor(); Consumer<Integer> consumer = new Consumer<Integer>(){ public void accept(Integer status){ diff --git a/core/api/test-current.txt b/core/api/test-current.txt index bb023f25094e..12bfccf2172c 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -4507,7 +4507,7 @@ package android.window { method @NonNull public android.window.WindowContainerTransaction requestFocusOnTaskFragment(@NonNull android.os.IBinder); method @NonNull public android.window.WindowContainerTransaction scheduleFinishEnterPip(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect); method @NonNull public android.window.WindowContainerTransaction setActivityWindowingMode(@NonNull android.window.WindowContainerToken, int); - method @NonNull public android.window.WindowContainerTransaction setAdjacentRoots(@NonNull android.window.WindowContainerToken, @NonNull android.window.WindowContainerToken); + method @Deprecated @NonNull public android.window.WindowContainerTransaction setAdjacentRoots(@NonNull android.window.WindowContainerToken, @NonNull android.window.WindowContainerToken); method @NonNull public android.window.WindowContainerTransaction setAdjacentTaskFragments(@NonNull android.os.IBinder, @NonNull android.os.IBinder, @Nullable android.window.WindowContainerTransaction.TaskFragmentAdjacentParams); method @NonNull public android.window.WindowContainerTransaction setAppBounds(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect); method @NonNull public android.window.WindowContainerTransaction setBounds(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect); diff --git a/core/java/android/animation/AnimationHandler.java b/core/java/android/animation/AnimationHandler.java index 5f57a41675c9..d5b2f980e1a6 100644 --- a/core/java/android/animation/AnimationHandler.java +++ b/core/java/android/animation/AnimationHandler.java @@ -110,8 +110,7 @@ public class AnimationHandler { } }; - public static final ThreadLocal<AnimationHandler> sAnimatorHandler = - ThreadLocal.withInitial(AnimationHandler::new); + public final static ThreadLocal<AnimationHandler> sAnimatorHandler = new ThreadLocal<>(); private static AnimationHandler sTestHandler = null; private boolean mListDirty = false; @@ -119,6 +118,9 @@ public class AnimationHandler { if (sTestHandler != null) { return sTestHandler; } + if (sAnimatorHandler.get() == null) { + sAnimatorHandler.set(new AnimationHandler()); + } return sAnimatorHandler.get(); } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 2c1df73cc6cc..0a2b1eaaad6b 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -273,6 +273,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.lang.ref.WeakReference; +import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.net.InetAddress; import java.nio.file.DirectoryStream; @@ -2268,10 +2269,16 @@ public final class ActivityThread extends ClientTransactionHandler public void getExecutableMethodFileOffsets( @NonNull MethodDescriptor methodDescriptor, @NonNull IOffsetCallback resultCallback) { - Method method = MethodDescriptorParser.parseMethodDescriptor( + Executable executable = MethodDescriptorParser.parseMethodDescriptor( getClass().getClassLoader(), methodDescriptor); - VMDebug.ExecutableMethodFileOffsets location = - VMDebug.getExecutableMethodFileOffsets(method); + VMDebug.ExecutableMethodFileOffsets location; + if (com.android.art.flags.Flags.executableMethodFileOffsetsV2()) { + location = VMDebug.getExecutableMethodFileOffsets(executable); + } else if (executable instanceof Method) { + location = VMDebug.getExecutableMethodFileOffsets((Method) executable); + } else { + throw new UnsupportedOperationException(); + } try { if (location == null) { resultCallback.onResult(null); @@ -3995,6 +4002,10 @@ public final class ActivityThread extends ClientTransactionHandler + (fromIpc ? " (from ipc" : "")); } } + if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) { + Trace.instant(Trace.TRACE_TAG_ACTIVITY_MANAGER, + "updateProcessState: processState=" + processState); + } } /** Converts a process state to a VM process state. */ diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 127a08b04e87..feaa98f644a0 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -6453,45 +6453,47 @@ public class Notification implements Parcelable return mN.showsTime() || mN.showsChronometer(); } - private void resetStandardTemplateWithActions(RemoteViews big) { + private void resetStandardTemplateWithActions(RemoteViews contentView) { // actions_container is only reset when there are no actions to avoid focus issues with // remote inputs. - big.setViewVisibility(R.id.actions, View.GONE); - big.removeAllViews(R.id.actions); - - big.setViewVisibility(R.id.notification_material_reply_container, View.GONE); - big.setTextViewText(R.id.notification_material_reply_text_1, null); - big.setViewVisibility(R.id.notification_material_reply_text_1_container, View.GONE); - big.setViewVisibility(R.id.notification_material_reply_progress, View.GONE); - - big.setViewVisibility(R.id.notification_material_reply_text_2, View.GONE); - big.setTextViewText(R.id.notification_material_reply_text_2, null); - big.setViewVisibility(R.id.notification_material_reply_text_3, View.GONE); - big.setTextViewText(R.id.notification_material_reply_text_3, null); - - // This may get erased by bindSnoozeAction - big.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target, + contentView.setViewVisibility(R.id.actions, View.GONE); + contentView.removeAllViews(R.id.actions); + + contentView.setViewVisibility(R.id.notification_material_reply_container, View.GONE); + contentView.setTextViewText(R.id.notification_material_reply_text_1, null); + contentView.setViewVisibility(R.id.notification_material_reply_text_1_container, + View.GONE); + contentView.setViewVisibility(R.id.notification_material_reply_progress, View.GONE); + + contentView.setViewVisibility(R.id.notification_material_reply_text_2, View.GONE); + contentView.setTextViewText(R.id.notification_material_reply_text_2, null); + contentView.setViewVisibility(R.id.notification_material_reply_text_3, View.GONE); + contentView.setTextViewText(R.id.notification_material_reply_text_3, null); + + // This may get erased by bindSnoozeAction, or if we're showing the bubble icon + contentView.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target, RemoteViews.MARGIN_BOTTOM, R.dimen.notification_content_margin); } - private void bindSnoozeAction(RemoteViews big, StandardTemplateParams p) { + private boolean bindSnoozeAction(RemoteViews contentView, StandardTemplateParams p) { boolean hideSnoozeButton = mN.isFgsOrUij() || mN.fullScreenIntent != null || isBackgroundColorized(p) || p.mViewType != StandardTemplateParams.VIEW_TYPE_EXPANDED; - big.setBoolean(R.id.snooze_button, "setEnabled", !hideSnoozeButton); + contentView.setBoolean(R.id.snooze_button, "setEnabled", !hideSnoozeButton); if (hideSnoozeButton) { // Only hide; NotificationContentView will show it when it adds the click listener - big.setViewVisibility(R.id.snooze_button, View.GONE); + contentView.setViewVisibility(R.id.snooze_button, View.GONE); } final boolean snoozeEnabled = !hideSnoozeButton && mContext.getContentResolver() != null && isSnoozeSettingEnabled(); if (snoozeEnabled) { - big.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target, + contentView.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target, RemoteViews.MARGIN_BOTTOM, 0); } + return snoozeEnabled; } private boolean isSnoozeSettingEnabled() { @@ -6526,16 +6528,14 @@ public class Notification implements Parcelable private RemoteViews applyStandardTemplateWithActions(int layoutId, StandardTemplateParams p, TemplateBindResult result) { - RemoteViews big = applyStandardTemplate(layoutId, p, result); + RemoteViews contentView = applyStandardTemplate(layoutId, p, result); - resetStandardTemplateWithActions(big); - bindSnoozeAction(big, p); + resetStandardTemplateWithActions(contentView); + boolean snoozeEnabled = bindSnoozeAction(contentView, p); // color the snooze and bubble actions with the theme color ColorStateList actionColor = ColorStateList.valueOf(getStandardActionColor(p)); - big.setColorStateList(R.id.snooze_button, "setImageTintList", actionColor); - big.setColorStateList(R.id.bubble_button, "setImageTintList", actionColor); - - boolean validRemoteInput = false; + contentView.setColorStateList(R.id.snooze_button, "setImageTintList", actionColor); + contentView.setColorStateList(R.id.bubble_button, "setImageTintList", actionColor); // In the UI, contextual actions appear separately from the standard actions, so we // filter them out here. @@ -6549,47 +6549,64 @@ public class Notification implements Parcelable if (p.mCallStyleActions) { // Clear view padding to allow buttons to start on the left edge. // This must be done before 'setEmphasizedMode' which sets top/bottom margins. - big.setViewPadding(R.id.actions, 0, 0, 0, 0); + contentView.setViewPadding(R.id.actions, 0, 0, 0, 0); if (!Flags.notificationsRedesignTemplates()) { // Add an optional indent that will make buttons start at the correct column // when there is enough space to do so (and fall back to the left edge if not). // This is handled directly in NotificationActionListLayout in the new design. - big.setInt(R.id.actions, "setCollapsibleIndentDimen", + contentView.setInt(R.id.actions, "setCollapsibleIndentDimen", R.dimen.call_notification_collapsible_indent); } if (evenlyDividedCallStyleActionLayout()) { if (CallStyle.DEBUG_NEW_ACTION_LAYOUT) { Log.d(TAG, "setting evenly divided mode on action list"); } - big.setBoolean(R.id.actions, "setEvenlyDividedMode", true); + contentView.setBoolean(R.id.actions, "setEvenlyDividedMode", true); } } - big.setBoolean(R.id.actions, "setEmphasizedMode", emphasizedMode); + if (!notificationsRedesignTemplates()) { + contentView.setBoolean(R.id.actions, "setEmphasizedMode", emphasizedMode); + } + + boolean validRemoteInput = false; if (numActions > 0 && !p.mHideActions) { - big.setViewVisibility(R.id.actions_container, View.VISIBLE); - big.setViewVisibility(R.id.actions, View.VISIBLE); - big.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target, + contentView.setViewVisibility(R.id.actions_container, View.VISIBLE); + contentView.setViewVisibility(R.id.actions, View.VISIBLE); + contentView.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target, RemoteViews.MARGIN_BOTTOM, 0); - for (int i = 0; i < numActions; i++) { - Action action = nonContextualActions.get(i); - - boolean actionHasValidInput = hasValidRemoteInput(action); - validRemoteInput |= actionHasValidInput; - - final RemoteViews button = generateActionButton(action, emphasizedMode, p); - if (actionHasValidInput && !emphasizedMode) { - // Clear the drawable - button.setInt(R.id.action0, "setBackgroundResource", 0); - } - if (emphasizedMode && i > 0) { - // Clear start margin from non-first buttons to reduce the gap between them. - // (8dp remaining gap is from all buttons' standard 4dp inset). - button.setViewLayoutMarginDimen(R.id.action0, RemoteViews.MARGIN_START, 0); + if (notificationsRedesignTemplates()) { + // No need for additional space under smart replies/smart actions. + contentView.setViewLayoutMarginDimen(R.id.smart_reply_container, + RemoteViews.MARGIN_BOTTOM, 0); + if (emphasizedMode) { + // Emphasized actions look similar to smart replies, so let's use the same + // margins. + contentView.setViewLayoutMarginDimen(R.id.actions_container, + RemoteViews.MARGIN_TOP, + R.dimen.notification_2025_smart_reply_container_margin); + contentView.setViewLayoutMarginDimen(R.id.actions_container, + RemoteViews.MARGIN_BOTTOM, + R.dimen.notification_2025_smart_reply_container_margin); + } else { + contentView.setViewLayoutMarginDimen(R.id.actions_container, + RemoteViews.MARGIN_TOP, 0); + contentView.setViewLayoutMarginDimen(R.id.actions_container, + RemoteViews.MARGIN_BOTTOM, + R.dimen.notification_2025_action_list_margin_bottom); } - big.addView(R.id.actions, button); } + validRemoteInput = populateActionsContainer(contentView, p, nonContextualActions, + numActions, emphasizedMode); } else { - big.setViewVisibility(R.id.actions_container, View.GONE); + contentView.setViewVisibility(R.id.actions_container, View.GONE); + if (notificationsRedesignTemplates() && !snoozeEnabled) { + // Make sure smart replies & smart actions have enough space at the bottom + // (if present) when there are no actions. This should be set to 0 if we're + // showing the snooze or bubble buttons. + contentView.setViewLayoutMarginDimen(R.id.smart_reply_container, + RemoteViews.MARGIN_BOTTOM, + R.dimen.notification_2025_smart_reply_container_margin); + } } RemoteInputHistoryItem[] replyText = getParcelableArrayFromBundle( @@ -6598,37 +6615,65 @@ public class Notification implements Parcelable && !TextUtils.isEmpty(replyText[0].getText()) && p.maxRemoteInputHistory > 0) { boolean showSpinner = mN.extras.getBoolean(EXTRA_SHOW_REMOTE_INPUT_SPINNER); - big.setViewVisibility(R.id.notification_material_reply_container, View.VISIBLE); - big.setViewVisibility(R.id.notification_material_reply_text_1_container, + contentView.setViewVisibility(R.id.notification_material_reply_container, + View.VISIBLE); + contentView.setViewVisibility(R.id.notification_material_reply_text_1_container, View.VISIBLE); - big.setTextViewText(R.id.notification_material_reply_text_1, + contentView.setTextViewText(R.id.notification_material_reply_text_1, ensureColorSpanContrastOrStripStyling(replyText[0].getText(), p)); - setTextViewColorSecondary(big, R.id.notification_material_reply_text_1, p); - big.setViewVisibility(R.id.notification_material_reply_progress, + setTextViewColorSecondary(contentView, R.id.notification_material_reply_text_1, p); + contentView.setViewVisibility(R.id.notification_material_reply_progress, showSpinner ? View.VISIBLE : View.GONE); - big.setProgressIndeterminateTintList( + contentView.setProgressIndeterminateTintList( R.id.notification_material_reply_progress, ColorStateList.valueOf(getPrimaryAccentColor(p))); if (replyText.length > 1 && !TextUtils.isEmpty(replyText[1].getText()) && p.maxRemoteInputHistory > 1) { - big.setViewVisibility(R.id.notification_material_reply_text_2, View.VISIBLE); - big.setTextViewText(R.id.notification_material_reply_text_2, + contentView.setViewVisibility(R.id.notification_material_reply_text_2, + View.VISIBLE); + contentView.setTextViewText(R.id.notification_material_reply_text_2, ensureColorSpanContrastOrStripStyling(replyText[1].getText(), p)); - setTextViewColorSecondary(big, R.id.notification_material_reply_text_2, p); + setTextViewColorSecondary(contentView, R.id.notification_material_reply_text_2, + p); if (replyText.length > 2 && !TextUtils.isEmpty(replyText[2].getText()) && p.maxRemoteInputHistory > 2) { - big.setViewVisibility( + contentView.setViewVisibility( R.id.notification_material_reply_text_3, View.VISIBLE); - big.setTextViewText(R.id.notification_material_reply_text_3, + contentView.setTextViewText(R.id.notification_material_reply_text_3, ensureColorSpanContrastOrStripStyling(replyText[2].getText(), p)); - setTextViewColorSecondary(big, R.id.notification_material_reply_text_3, p); + setTextViewColorSecondary(contentView, + R.id.notification_material_reply_text_3, p); } } } - return big; + return contentView; + } + + private boolean populateActionsContainer(RemoteViews contentView, StandardTemplateParams p, + List<Action> nonContextualActions, int numActions, boolean emphasizedMode) { + boolean validRemoteInput = false; + for (int i = 0; i < numActions; i++) { + Action action = nonContextualActions.get(i); + + boolean actionHasValidInput = hasValidRemoteInput(action); + validRemoteInput |= actionHasValidInput; + + final RemoteViews button = generateActionButton(action, emphasizedMode, p); + if (actionHasValidInput && !emphasizedMode) { + // Clear the drawable + button.setInt(R.id.action0, "setBackgroundResource", 0); + } + if (emphasizedMode && i > 0) { + // Clear start margin from non-first buttons to reduce the gap between them. + // (8dp remaining gap is from all buttons' standard 4dp inset). + button.setViewLayoutMarginDimen(R.id.action0, RemoteViews.MARGIN_START, 0); + } + contentView.addView(R.id.actions, button); + } + return validRemoteInput; } /** diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 73de1b67dc66..c74bd1a092ee 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -6981,6 +6981,8 @@ public class DevicePolicyManager { * <p>The caller must hold the * {@link android.Manifest.permission#TRIGGER_LOST_MODE} permission. * + * <p>This API accesses the device's location and will only be used when a device is lost. + * * <p>Register a broadcast receiver to receive lost mode location updates. This receiver should * subscribe to the {@link #ACTION_LOST_MODE_LOCATION_UPDATE} action and receive the location * from an intent extra {@link #EXTRA_LOST_MODE_LOCATION}. diff --git a/core/java/android/app/backup/BackupManagerMonitor.java b/core/java/android/app/backup/BackupManagerMonitor.java index 19c24cd8a14a..ca14fce6706a 100644 --- a/core/java/android/app/backup/BackupManagerMonitor.java +++ b/core/java/android/app/backup/BackupManagerMonitor.java @@ -164,6 +164,15 @@ public class BackupManagerMonitor { public static final String EXTRA_LOG_V_TO_U_ALLOWLIST = "android.app.backup.extra.V_TO_U_ALLOWLIST"; + /** + * An int indicating why a backup was cancelled. One of {@link + * com.android.server.backup.BackupRestoreTask.CancellationReason}. + * + * @hide + */ + public static final String EXTRA_LOG_CANCELLATION_REASON = + "android.app.backup.extra.CANCELLATION_REASON"; + // TODO complete this list with all log messages. And document properly. public static final int LOG_EVENT_ID_FULL_BACKUP_CANCEL = 4; public static final int LOG_EVENT_ID_ILLEGAL_KEY = 5; diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig index 5c267c9f6475..3eaf2c40daca 100644 --- a/core/java/android/app/notification.aconfig +++ b/core/java/android/app/notification.aconfig @@ -63,6 +63,16 @@ flag { } flag { + name: "modes_ui_dnd_tile" + namespace: "systemui" + description: "Shows a dedicated tile for the DND mode; dependent on modes_ui" + bug: "401217520" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "modes_hsum" namespace: "systemui" description: "Fixes for modes (and DND/Zen in general) with HSUM or secondary users" @@ -265,6 +275,16 @@ flag { } flag { + name: "expanding_public_view" + namespace: "systemui" + description: "enables user expanding the public view of a notification" + bug: "398853084" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "api_rich_ongoing" is_exported: true namespace: "systemui" diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 55d78f9b8c48..cc288b1f5601 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -744,15 +744,22 @@ public abstract class Context { */ public static final long BIND_MATCH_QUARANTINED_COMPONENTS = 0x2_0000_0000L; + /** + * Flag for {@link #bindService} that allows the bound app to be frozen if it is eligible. + * + * @hide + */ + public static final long BIND_ALLOW_FREEZE = 0x4_0000_0000L; /** * These bind flags reduce the strength of the binding such that we shouldn't * consider it as pulling the process up to the level of the one that is bound to it. * @hide */ - public static final int BIND_REDUCTION_FLAGS = + public static final long BIND_REDUCTION_FLAGS = Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_WAIVE_PRIORITY - | Context.BIND_NOT_PERCEPTIBLE | Context.BIND_NOT_VISIBLE; + | Context.BIND_NOT_PERCEPTIBLE | Context.BIND_NOT_VISIBLE + | Context.BIND_ALLOW_FREEZE; /** @hide */ @IntDef(flag = true, prefix = { "RECEIVER_VISIBLE" }, value = { diff --git a/core/java/android/hardware/input/IKeyGestureHandler.aidl b/core/java/android/hardware/input/IKeyGestureHandler.aidl index 509b9482154e..4da991ee85b1 100644 --- a/core/java/android/hardware/input/IKeyGestureHandler.aidl +++ b/core/java/android/hardware/input/IKeyGestureHandler.aidl @@ -28,15 +28,4 @@ interface IKeyGestureHandler { * to that gesture. */ boolean handleKeyGesture(in AidlKeyGestureEvent event, in IBinder focusedToken); - - /** - * Called to know if a particular gesture type is supported by the handler. - * - * TODO(b/358569822): Remove this call to reduce the binder calls to single call for - * handleKeyGesture. For this we need to remove dependency of multi-key gestures to identify if - * a key gesture is supported on first relevant key down. - * Also, for now we prioritize handlers in the system server process above external handlers to - * reduce IPC binder calls. - */ - boolean isKeyGestureSupported(int gestureType); } diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 49db54d81e65..d6419afb2a5a 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -1758,13 +1758,6 @@ public final class InputManager { */ boolean handleKeyGestureEvent(@NonNull KeyGestureEvent event, @Nullable IBinder focusedToken); - - /** - * Called to identify if a particular gesture is of interest to a handler. - * - * NOTE: If no active handler supports certain gestures, the gestures will not be captured. - */ - boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType); } /** @hide */ diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java index a9a45ae45ec3..c4b4831ba76e 100644 --- a/core/java/android/hardware/input/InputManagerGlobal.java +++ b/core/java/android/hardware/input/InputManagerGlobal.java @@ -1193,23 +1193,6 @@ public final class InputManagerGlobal { } return false; } - - @Override - public boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType) { - synchronized (mKeyGestureEventHandlerLock) { - if (mKeyGestureEventHandlers == null) { - return false; - } - final int numHandlers = mKeyGestureEventHandlers.size(); - for (int i = 0; i < numHandlers; i++) { - KeyGestureEventHandler handler = mKeyGestureEventHandlers.get(i); - if (handler.isKeyGestureSupported(gestureType)) { - return true; - } - } - } - return false; - } } /** diff --git a/core/java/android/hardware/input/KeyGestureEvent.java b/core/java/android/hardware/input/KeyGestureEvent.java index 1a712d2b3f31..9dd1fed4a85a 100644 --- a/core/java/android/hardware/input/KeyGestureEvent.java +++ b/core/java/android/hardware/input/KeyGestureEvent.java @@ -108,7 +108,8 @@ public final class KeyGestureEvent { public static final int KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD = 55; public static final int KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD = 56; public static final int KEY_GESTURE_TYPE_GLOBAL_ACTIONS = 57; - public static final int KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD = 58; + @Deprecated + public static final int DEPRECATED_KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD = 58; public static final int KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT = 59; public static final int KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT = 60; public static final int KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS = 61; @@ -200,7 +201,6 @@ public final class KeyGestureEvent { KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD, KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD, KEY_GESTURE_TYPE_GLOBAL_ACTIONS, - KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD, KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT, KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT, KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS, @@ -777,8 +777,6 @@ public final class KeyGestureEvent { return "KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD"; case KEY_GESTURE_TYPE_GLOBAL_ACTIONS: return "KEY_GESTURE_TYPE_GLOBAL_ACTIONS"; - case KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD: - return "KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD"; case KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT: return "KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT"; case KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT: diff --git a/core/java/android/os/LegacyMessageQueue/MessageQueue.java b/core/java/android/os/LegacyMessageQueue/MessageQueue.java index 132bdd1e56b8..1cf57de08d5f 100644 --- a/core/java/android/os/LegacyMessageQueue/MessageQueue.java +++ b/core/java/android/os/LegacyMessageQueue/MessageQueue.java @@ -786,8 +786,8 @@ public final class MessageQueue { } /** - * Get the timestamp of the next executable message in our priority queue. - * Returns null if there are no messages ready for delivery. + * Get the timestamp of the next message in our priority queue. + * Returns null if there are no messages in the queue. * * Caller must ensure that this doesn't race 'next' from the Looper thread. */ @@ -799,8 +799,8 @@ public final class MessageQueue { } /** - * Return the next executable message in our priority queue. - * Returns null if there are no messages ready for delivery + * Return the next message in our priority queue. + * Returns null if there are no messages in the queue. * * Caller must ensure that this doesn't race 'next' from the Looper thread. */ diff --git a/core/java/android/os/TestLooperManager.java b/core/java/android/os/TestLooperManager.java index 1a54f4df58fb..204e3444c547 100644 --- a/core/java/android/os/TestLooperManager.java +++ b/core/java/android/os/TestLooperManager.java @@ -96,8 +96,8 @@ public class TestLooperManager { } /** - * Retrieves and removes the next message that should be executed by this queue. - * If the queue is empty or no messages are deliverable, returns null. + * Retrieves and removes the next message in this queue. + * If the queue is empty, returns null. * This method never blocks. * * <p>Callers should always call {@link #recycle(Message)} on the message when all interactions @@ -112,9 +112,9 @@ public class TestLooperManager { } /** - * Retrieves, but does not remove, the values of {@link Message#when} of next message that - * should be executed by this queue. - * If the queue is empty or no messages are deliverable, returns null. + * Retrieves, but does not remove, the values of {@link Message#when} of next message in the + * queue. + * If the queue is empty, returns null. * This method never blocks. */ @FlaggedApi(Flags.FLAG_MESSAGE_QUEUE_TESTABILITY) diff --git a/core/java/android/os/instrumentation/MethodDescriptorParser.java b/core/java/android/os/instrumentation/MethodDescriptorParser.java index 57fc44ff623e..3264c041213b 100644 --- a/core/java/android/os/instrumentation/MethodDescriptorParser.java +++ b/core/java/android/os/instrumentation/MethodDescriptorParser.java @@ -18,7 +18,7 @@ package android.os.instrumentation; import android.annotation.NonNull; -import java.lang.reflect.Method; +import java.lang.reflect.Executable; /** * A utility class for dynamic instrumentation / uprobestats. @@ -28,9 +28,9 @@ import java.lang.reflect.Method; public final class MethodDescriptorParser { /** - * Parses a {@link MethodDescriptor} (in string representation) into a {@link Method}. + * Parses a {@link MethodDescriptor} (in string representation) into a {@link Executable}. */ - public static Method parseMethodDescriptor(ClassLoader classLoader, + public static Executable parseMethodDescriptor(ClassLoader classLoader, @NonNull MethodDescriptor descriptor) { try { Class<?> javaClass = classLoader.loadClass(descriptor.fullyQualifiedClassName); @@ -72,6 +72,10 @@ public final class MethodDescriptorParser { } } + if (com.android.art.flags.Flags.executableMethodFileOffsetsV2() + && descriptor.methodName.equals("<init>")) { + return javaClass.getDeclaredConstructor(parameters); + } return javaClass.getDeclaredMethod(descriptor.methodName, parameters); } catch (ClassNotFoundException | NoSuchMethodException e) { throw new IllegalArgumentException( diff --git a/core/java/android/service/chooser/flags.aconfig b/core/java/android/service/chooser/flags.aconfig index ae0b56e6f009..45a21beabd89 100644 --- a/core/java/android/service/chooser/flags.aconfig +++ b/core/java/android/service/chooser/flags.aconfig @@ -44,6 +44,16 @@ flag { } flag { + name: "notify_single_item_change_on_icon_load" + namespace: "intentresolver" + description: "ChooserGridAdapter to notify specific items change when the target icon is loaded (instead of all-item change)." + bug: "298193161" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "fix_resolver_memory_leak" is_exported: true namespace: "intentresolver" diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index ce31e1ea7e38..df3b8baa40c8 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -455,7 +455,7 @@ public class DreamService extends Service implements Window.Callback { // Simply wake up in the case the device is not locked. if (!keyguardManager.isKeyguardLocked()) { - wakeUp(); + wakeUp(false); return true; } @@ -477,11 +477,11 @@ public class DreamService extends Service implements Window.Callback { if (!mInteractive) { if (mDebug) Slog.v(mTag, "Waking up on keyEvent"); - wakeUp(); + wakeUp(false); return true; } else if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { if (mDebug) Slog.v(mTag, "Waking up on back key"); - wakeUp(); + wakeUp(false); return true; } return mWindow.superDispatchKeyEvent(event); @@ -492,7 +492,7 @@ public class DreamService extends Service implements Window.Callback { public boolean dispatchKeyShortcutEvent(KeyEvent event) { if (!mInteractive) { if (mDebug) Slog.v(mTag, "Waking up on keyShortcutEvent"); - wakeUp(); + wakeUp(false); return true; } return mWindow.superDispatchKeyShortcutEvent(event); @@ -505,7 +505,7 @@ public class DreamService extends Service implements Window.Callback { // but finish()es on any other kind of activity if (!mInteractive && event.getActionMasked() == MotionEvent.ACTION_UP) { if (mDebug) Slog.v(mTag, "Waking up on touchEvent"); - wakeUp(); + wakeUp(false); return true; } return mWindow.superDispatchTouchEvent(event); @@ -516,7 +516,7 @@ public class DreamService extends Service implements Window.Callback { public boolean dispatchTrackballEvent(MotionEvent event) { if (!mInteractive) { if (mDebug) Slog.v(mTag, "Waking up on trackballEvent"); - wakeUp(); + wakeUp(false); return true; } return mWindow.superDispatchTrackballEvent(event); @@ -527,7 +527,7 @@ public class DreamService extends Service implements Window.Callback { public boolean dispatchGenericMotionEvent(MotionEvent event) { if (!mInteractive) { if (mDebug) Slog.v(mTag, "Waking up on genericMotionEvent"); - wakeUp(); + wakeUp(false); return true; } return mWindow.superDispatchGenericMotionEvent(event); @@ -925,32 +925,37 @@ public class DreamService extends Service implements Window.Callback { } } - private synchronized void updateDoze() { - if (mDreamToken == null) { - Slog.w(mTag, "Updating doze without a dream token."); - return; - } + /** + * Updates doze state. Note that this must be called on the mHandler. + */ + private void updateDoze() { + mHandler.post(() -> { + if (mDreamToken == null) { + Slog.w(mTag, "Updating doze without a dream token."); + return; + } - if (mDozing) { - try { - Slog.v(mTag, "UpdateDoze mDozeScreenState=" + mDozeScreenState - + " mDozeScreenBrightness=" + mDozeScreenBrightness - + " mDozeScreenBrightnessFloat=" + mDozeScreenBrightnessFloat); - if (startAndStopDozingInBackground()) { - mDreamManager.startDozingOneway( - mDreamToken, mDozeScreenState, mDozeScreenStateReason, - mDozeScreenBrightnessFloat, mDozeScreenBrightness, - mUseNormalBrightnessForDoze); - } else { - mDreamManager.startDozing( - mDreamToken, mDozeScreenState, mDozeScreenStateReason, - mDozeScreenBrightnessFloat, mDozeScreenBrightness, - mUseNormalBrightnessForDoze); + if (mDozing) { + try { + Slog.v(mTag, "UpdateDoze mDozeScreenState=" + mDozeScreenState + + " mDozeScreenBrightness=" + mDozeScreenBrightness + + " mDozeScreenBrightnessFloat=" + mDozeScreenBrightnessFloat); + if (startAndStopDozingInBackground()) { + mDreamManager.startDozingOneway( + mDreamToken, mDozeScreenState, mDozeScreenStateReason, + mDozeScreenBrightnessFloat, mDozeScreenBrightness, + mUseNormalBrightnessForDoze); + } else { + mDreamManager.startDozing( + mDreamToken, mDozeScreenState, mDozeScreenStateReason, + mDozeScreenBrightnessFloat, mDozeScreenBrightness, + mUseNormalBrightnessForDoze); + } + } catch (RemoteException ex) { + // system server died } - } catch (RemoteException ex) { - // system server died } - } + }); } /** @@ -966,14 +971,20 @@ public class DreamService extends Service implements Window.Callback { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public void stopDozing() { - if (mDozing) { - mDozing = false; - try { - mDreamManager.stopDozing(mDreamToken); - } catch (RemoteException ex) { - // system server died + mHandler.post(() -> { + if (mDreamToken == null) { + return; } - } + + if (mDozing) { + mDozing = false; + try { + mDreamManager.stopDozing(mDreamToken); + } catch (RemoteException ex) { + // system server died + } + } + }); } /** @@ -1201,7 +1212,7 @@ public class DreamService extends Service implements Window.Callback { @Override public void onExitRequested() { // Simply finish dream when exit is requested. - mHandler.post(() -> finish()); + mHandler.post(() -> finishInternal()); } @Override @@ -1299,9 +1310,13 @@ public class DreamService extends Service implements Window.Callback { * </p> */ public final void finish() { + mHandler.post(this::finishInternal); + } + + private void finishInternal() { // If there is an active overlay connection, signal that the dream is ending before - // continuing. Note that the overlay cannot rely on the unbound state, since another dream - // might have bound to it in the meantime. + // continuing. Note that the overlay cannot rely on the unbound state, since another + // dream might have bound to it in the meantime. if (mOverlayConnection != null) { mOverlayConnection.addConsumer(overlay -> { try { @@ -1357,7 +1372,7 @@ public class DreamService extends Service implements Window.Callback { * </p> */ public final void wakeUp() { - wakeUp(false); + mHandler.post(()-> wakeUp(false)); } /** @@ -1559,7 +1574,7 @@ public class DreamService extends Service implements Window.Callback { if (mActivity != null && !mActivity.isFinishing()) { mActivity.finishAndRemoveTask(); } else { - finish(); + finishInternal(); } mDreamToken = null; @@ -1719,7 +1734,7 @@ public class DreamService extends Service implements Window.Callback { // the window reference in order to fully release the DreamActivity. mWindow = null; mActivity = null; - finish(); + finishInternal(); } if (mOverlayConnection != null && mDreamStartOverlayConsumer != null) { diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index 44c3f9a8244e..0152c52a6753 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -75,9 +75,12 @@ public abstract class Layout { // These should match the constants in framework/base/libs/hwui/hwui/DrawTextFunctor.h private static final float HIGH_CONTRAST_TEXT_BORDER_WIDTH_MIN_PX = 0f; private static final float HIGH_CONTRAST_TEXT_BORDER_WIDTH_FACTOR = 0f; - private static final float HIGH_CONTRAST_TEXT_BACKGROUND_CORNER_RADIUS_DP = 5f; // since we're not using soft light yet, this needs to be much lower than the spec'd 0.8 private static final float HIGH_CONTRAST_TEXT_BACKGROUND_ALPHA_PERCENTAGE = 0.7f; + @VisibleForTesting + static final float HIGH_CONTRAST_TEXT_BACKGROUND_CORNER_RADIUS_MIN_DP = 5f; + @VisibleForTesting + static final float HIGH_CONTRAST_TEXT_BACKGROUND_CORNER_RADIUS_FACTOR = 0.5f; /** @hide */ @IntDef(prefix = { "BREAK_STRATEGY_" }, value = { @@ -1030,7 +1033,9 @@ public abstract class Layout { var padding = Math.max(HIGH_CONTRAST_TEXT_BORDER_WIDTH_MIN_PX, mPaint.getTextSize() * HIGH_CONTRAST_TEXT_BORDER_WIDTH_FACTOR); - var cornerRadius = mPaint.density * HIGH_CONTRAST_TEXT_BACKGROUND_CORNER_RADIUS_DP; + var cornerRadius = Math.max( + mPaint.density * HIGH_CONTRAST_TEXT_BACKGROUND_CORNER_RADIUS_MIN_DP, + mPaint.getTextSize() * HIGH_CONTRAST_TEXT_BACKGROUND_CORNER_RADIUS_FACTOR); // We set the alpha on the color itself instead of Paint.setAlpha(), because that function // actually mutates the color in... *ehem* very strange ways. Also the color might get reset diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index 7c1e4976b9d3..3a2ec91b3b20 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -967,8 +967,11 @@ public final class Choreographer { DisplayEventReceiver.VsyncEventData vsyncEventData) { final long startNanos; final long frameIntervalNanos = vsyncEventData.frameInterval; - boolean resynced = false; + // Original intended vsync time that is not adjusted by jitter + // or buffer stuffing recovery. Reported for jank tracking. + final long intendedFrameTimeNanos = frameTimeNanos; long offsetFrameTimeNanos = frameTimeNanos; + boolean resynced = false; // Evaluate if buffer stuffing recovery needs to start or end, and // what actions need to be taken for recovery. @@ -1012,7 +1015,6 @@ public final class Choreographer { + ((offsetFrameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms"); } - long intendedFrameTimeNanos = offsetFrameTimeNanos; startNanos = System.nanoTime(); // Calculating jitter involves using the original frame time without // adjustments from buffer stuffing diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 6f346bdae70a..394ac8f8c6e9 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -1986,7 +1986,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation // report its requested visibility at the end of the animation, otherwise we would // lose the leash, and it would disappear during the animation // TODO(b/326377046) revisit this part and see if we can make it more general - typesToReport = mRequestedVisibleTypes | (mAnimatingTypes & ime()); + if (Flags.reportAnimatingInsetsTypes()) { + typesToReport = mRequestedVisibleTypes; + } else { + typesToReport = mRequestedVisibleTypes | (mAnimatingTypes & ime()); + } } else { typesToReport = mRequestedVisibleTypes; } diff --git a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java index eca798d6eb4f..290885593ee6 100644 --- a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java +++ b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java @@ -379,7 +379,7 @@ final class IInputMethodManagerGlobalInvoker { @Nullable IRemoteInputConnection remoteInputConnection, @Nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, int unverifiedTargetSdkVersion, @UserIdInt int userId, - @NonNull ImeOnBackInvokedDispatcher imeDispatcher) { + @NonNull ImeOnBackInvokedDispatcher imeDispatcher, boolean imeRequestedVisible) { final IInputMethodManager service = getService(); if (service == null) { return InputBindResult.NULL; @@ -388,7 +388,7 @@ final class IInputMethodManagerGlobalInvoker { return service.startInputOrWindowGainedFocus(startInputReason, client, windowToken, startInputFlags, softInputMode, windowFlags, editorInfo, remoteInputConnection, remoteAccessibilityInputConnection, unverifiedTargetSdkVersion, userId, - imeDispatcher); + imeDispatcher, imeRequestedVisible); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -408,7 +408,8 @@ final class IInputMethodManagerGlobalInvoker { @Nullable IRemoteInputConnection remoteInputConnection, @Nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, int unverifiedTargetSdkVersion, @UserIdInt int userId, - @NonNull ImeOnBackInvokedDispatcher imeDispatcher, boolean useAsyncShowHideMethod) { + @NonNull ImeOnBackInvokedDispatcher imeDispatcher, boolean imeRequestedVisible, + boolean useAsyncShowHideMethod) { final IInputMethodManager service = getService(); if (service == null) { return -1; @@ -417,7 +418,8 @@ final class IInputMethodManagerGlobalInvoker { service.startInputOrWindowGainedFocusAsync(startInputReason, client, windowToken, startInputFlags, softInputMode, windowFlags, editorInfo, remoteInputConnection, remoteAccessibilityInputConnection, unverifiedTargetSdkVersion, userId, - imeDispatcher, advanceAngGetStartInputSequenceNumber(), useAsyncShowHideMethod); + imeDispatcher, imeRequestedVisible, advanceAngGetStartInputSequenceNumber(), + useAsyncShowHideMethod); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 0b34600f4104..a41ab368aed8 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -871,6 +871,19 @@ public final class InputMethodManager { IInputMethodManagerGlobalInvoker.reportPerceptibleAsync(windowToken, perceptible); } + private static boolean hasViewImeRequestedVisible(View view) { + // before the refactor, the requestedVisibleTypes for the IME were not in sync with + // the state that was actually requested. + if (Flags.refactorInsetsController() && view != null) { + final var controller = view.getWindowInsetsController(); + if (controller != null) { + return (view.getWindowInsetsController() + .getRequestedVisibleTypes() & WindowInsets.Type.ime()) != 0; + } + } + return false; + } + private final class DelegateImpl implements ImeFocusController.InputMethodManagerDelegate { @@ -941,6 +954,9 @@ public final class InputMethodManager { Log.v(TAG, "Reporting focus gain, without startInput"); } + final boolean imeRequestedVisible = hasViewImeRequestedVisible( + mCurRootView.getView()); + // ignore the result Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMM.startInputOrWindowGainedFocus"); IInputMethodManagerGlobalInvoker.startInputOrWindowGainedFocus( @@ -950,7 +966,7 @@ public final class InputMethodManager { null, null, null, mCurRootView.mContext.getApplicationInfo().targetSdkVersion, - UserHandle.myUserId(), mImeDispatcher); + UserHandle.myUserId(), mImeDispatcher, imeRequestedVisible); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } } @@ -2441,9 +2457,8 @@ public final class InputMethodManager { ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_NO_ONGOING_USER_ANIMATION); if (resultReceiver != null) { - final boolean imeReqVisible = - (viewRootImpl.getInsetsController().getRequestedVisibleTypes() - & WindowInsets.Type.ime()) != 0; + final boolean imeReqVisible = hasViewImeRequestedVisible( + viewRootImpl.getView()); resultReceiver.send( imeReqVisible ? InputMethodManager.RESULT_UNCHANGED_SHOWN : InputMethodManager.RESULT_SHOWN, null); @@ -2656,9 +2671,8 @@ public final class InputMethodManager { ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_HANDLER_AVAILABLE); - final boolean imeReqVisible = - (viewRootImpl.getInsetsController().getRequestedVisibleTypes() - & WindowInsets.Type.ime()) != 0; + final boolean imeReqVisible = hasViewImeRequestedVisible( + viewRootImpl.getView()); if (resultReceiver != null) { resultReceiver.send( !imeReqVisible ? InputMethodManager.RESULT_UNCHANGED_HIDDEN @@ -3412,6 +3426,7 @@ public final class InputMethodManager { final Handler icHandler; InputBindResult res = null; final boolean hasServedView; + final boolean imeRequestedVisible; synchronized (mH) { // Now that we are locked again, validate that our state hasn't // changed. @@ -3479,10 +3494,13 @@ public final class InputMethodManager { } mServedInputConnection = servedInputConnection; + imeRequestedVisible = hasViewImeRequestedVisible(servedView); + if (DEBUG) { Log.v(TAG, "START INPUT: view=" + InputMethodDebug.dumpViewInfo(view) + " ic=" + ic + " editorInfo=" + editorInfo + " startInputFlags=" - + InputMethodDebug.startInputFlagsToString(startInputFlags)); + + InputMethodDebug.startInputFlagsToString(startInputFlags) + + " imeRequestedVisible=" + imeRequestedVisible); } // When we switch between non-editable views, do not call into the IMMS. @@ -3513,7 +3531,7 @@ public final class InputMethodManager { servedInputConnection == null ? null : servedInputConnection.asIRemoteAccessibilityInputConnection(), view.getContext().getApplicationInfo().targetSdkVersion, targetUserId, - mImeDispatcher, mAsyncShowHideMethodEnabled); + mImeDispatcher, imeRequestedVisible, mAsyncShowHideMethodEnabled); } else { res = IInputMethodManagerGlobalInvoker.startInputOrWindowGainedFocus( startInputReason, mClient, windowGainingFocus, startInputFlags, @@ -3521,7 +3539,7 @@ public final class InputMethodManager { servedInputConnection == null ? null : servedInputConnection.asIRemoteAccessibilityInputConnection(), view.getContext().getApplicationInfo().targetSdkVersion, targetUserId, - mImeDispatcher); + mImeDispatcher, imeRequestedVisible); } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); if (Flags.useZeroJankProxy()) { diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 3f611c7efbdd..a328c78f3738 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -72,7 +72,7 @@ import java.util.function.Predicate; /** * <p>Displays a vertically-scrollable collection of views, where each view is positioned - * immediatelybelow the previous view in the list. For a more modern, flexible, and performant + * immediately below the previous view in the list. For a more modern, flexible, and performant * approach to displaying lists, use {@link androidx.recyclerview.widget.RecyclerView}.</p> * * <p>To display a list, you can include a list view in your layout XML file:</p> diff --git a/core/java/android/window/DesktopModeFlags.java b/core/java/android/window/DesktopModeFlags.java index 17165cdcf7b1..aecf6eb261b1 100644 --- a/core/java/android/window/DesktopModeFlags.java +++ b/core/java/android/window/DesktopModeFlags.java @@ -113,7 +113,7 @@ public enum DesktopModeFlags { ENABLE_MINIMIZE_BUTTON(Flags::enableMinimizeButton, true), ENABLE_MODALS_FULLSCREEN_WITH_PERMISSIONS(Flags::enableModalsFullscreenWithPermission, false), ENABLE_OPAQUE_BACKGROUND_FOR_TRANSPARENT_WINDOWS( - Flags::enableOpaqueBackgroundForTransparentWindows, false), + Flags::enableOpaqueBackgroundForTransparentWindows, true), ENABLE_QUICKSWITCH_DESKTOP_SPLIT_BUGFIX(Flags::enableQuickswitchDesktopSplitBugfix, true), ENABLE_RESIZING_METRICS(Flags::enableResizingMetrics, true), ENABLE_RESTORE_TO_PREVIOUS_SIZE_FROM_DESKTOP_IMMERSIVE( diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index ea345a5ef46a..485e7b33f3a7 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -684,7 +684,10 @@ public final class WindowContainerTransaction implements Parcelable { * organizer. * @param root1 the first root. * @param root2 the second root. + * @deprecated replace with {@link #setAdjacentRootSet} */ + @SuppressWarnings("UnflaggedApi") // @TestApi without associated feature. + @Deprecated @NonNull public WindowContainerTransaction setAdjacentRoots( @NonNull WindowContainerToken root1, @NonNull WindowContainerToken root2) { @@ -704,7 +707,7 @@ public final class WindowContainerTransaction implements Parcelable { * * @param roots the Tasks that should be adjacent to each other. * @throws IllegalArgumentException if roots have size < 2. - * @hide // TODO(b/373709676) Rename to setAdjacentRoots and update CTS. + * @hide // TODO(b/373709676) Rename to setAdjacentRoots and update CTS in 25Q4. */ @NonNull public WindowContainerTransaction setAdjacentRootSet(@NonNull WindowContainerToken... roots) { @@ -1003,7 +1006,7 @@ public final class WindowContainerTransaction implements Parcelable { /** * Sets to TaskFragments adjacent to each other. Containers below two visible adjacent * TaskFragments will be made invisible. This is similar to - * {@link #setAdjacentRoots(WindowContainerToken, WindowContainerToken)}, but can be used with + * {@link #setAdjacentRootSet(WindowContainerToken...)}, but can be used with * fragmentTokens when that TaskFragments haven't been created (but will be created in the same * {@link WindowContainerTransaction}). * @param fragmentToken1 client assigned unique token to create TaskFragment with specified diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig index cbeaeda65fca..94e87c7a034b 100644 --- a/core/java/android/window/flags/windowing_sdk.aconfig +++ b/core/java/android/window/flags/windowing_sdk.aconfig @@ -105,17 +105,6 @@ flag { flag { namespace: "windowing_sdk" - name: "allow_multiple_adjacent_task_fragments" - description: "Refactor to allow more than 2 adjacent TaskFragments" - bug: "373709676" - is_fixed_read_only: true - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { - namespace: "windowing_sdk" name: "track_system_ui_context_before_wms" description: "Keep track of SystemUiContext before WMS is initialized" bug: "384428048" diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index c009fc3b7e63..9bc6671bbc31 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -23,6 +23,7 @@ import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CROSS_PROFILE_BLOCKED_TITLE; import static android.content.ContentProvider.getUriWithoutUserId; import static android.content.ContentProvider.getUserIdFromUri; +import static android.service.chooser.Flags.notifySingleItemChangeOnIconLoad; import static android.stats.devicepolicy.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL; import static android.stats.devicepolicy.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK; @@ -163,9 +164,11 @@ import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -3212,6 +3215,8 @@ public class ChooserActivity extends ResolverActivity implements private static final int NUM_EXPANSIONS_TO_HIDE_AZ_LABEL = 20; + private final Set<ViewHolderBase> mBoundViewHolders = new HashSet<>(); + ChooserGridAdapter(ChooserListAdapter wrappedAdapter) { super(); mChooserListAdapter = wrappedAdapter; @@ -3232,6 +3237,31 @@ public class ChooserActivity extends ResolverActivity implements notifyDataSetChanged(); } }); + if (notifySingleItemChangeOnIconLoad()) { + wrappedAdapter.setOnIconLoadedListener(this::onTargetIconLoaded); + } + } + + private void onTargetIconLoaded(DisplayResolveInfo info) { + for (ViewHolderBase holder : mBoundViewHolders) { + switch (holder.getViewType()) { + case VIEW_TYPE_NORMAL: + TargetInfo itemInfo = + mChooserListAdapter.getItem( + ((ItemViewHolder) holder).mListPosition); + if (info == itemInfo) { + notifyItemChanged(holder.getAdapterPosition()); + } + break; + case VIEW_TYPE_CALLER_AND_RANK: + ItemGroupViewHolder groupHolder = (ItemGroupViewHolder) holder; + if (suggestedAppsGroupContainsTarget(groupHolder, info)) { + notifyItemChanged(holder.getAdapterPosition()); + } + break; + } + + } } public void setFooterHeight(int height) { @@ -3382,6 +3412,9 @@ public class ChooserActivity extends ResolverActivity implements @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + if (notifySingleItemChangeOnIconLoad()) { + mBoundViewHolders.add((ViewHolderBase) holder); + } int viewType = ((ViewHolderBase) holder).getViewType(); switch (viewType) { case VIEW_TYPE_DIRECT_SHARE: @@ -3396,6 +3429,22 @@ public class ChooserActivity extends ResolverActivity implements } @Override + public void onViewRecycled(RecyclerView.ViewHolder holder) { + if (notifySingleItemChangeOnIconLoad()) { + mBoundViewHolders.remove((ViewHolderBase) holder); + } + super.onViewRecycled(holder); + } + + @Override + public boolean onFailedToRecycleView(RecyclerView.ViewHolder holder) { + if (notifySingleItemChangeOnIconLoad()) { + mBoundViewHolders.remove((ViewHolderBase) holder); + } + return super.onFailedToRecycleView(holder); + } + + @Override public int getItemViewType(int position) { int count; @@ -3604,6 +3653,33 @@ public class ChooserActivity extends ResolverActivity implements } } + /** + * Checks whether the suggested apps group, {@code holder}, contains the target, + * {@code info}. + */ + private boolean suggestedAppsGroupContainsTarget( + ItemGroupViewHolder holder, DisplayResolveInfo info) { + + int position = holder.getAdapterPosition(); + int start = getListPosition(position); + int startType = getRowType(start); + + int columnCount = holder.getColumnCount(); + int end = start + columnCount - 1; + while (getRowType(end) != startType && end >= start) { + end--; + } + + for (int i = 0; i < columnCount; i++) { + if (start + i <= end) { + if (mChooserListAdapter.getItem(holder.getItemIndex(i)) == info) { + return true; + } + } + } + return false; + } + int getListPosition(int position) { position -= getSystemRowCount() + getProfileRowCount(); diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java index d38689c7505b..1b8c36db3908 100644 --- a/core/java/com/android/internal/app/ChooserListAdapter.java +++ b/core/java/com/android/internal/app/ChooserListAdapter.java @@ -16,9 +16,12 @@ package com.android.internal.app; +import static android.service.chooser.Flags.notifySingleItemChangeOnIconLoad; + import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE; import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER; +import android.annotation.Nullable; import android.app.prediction.AppPredictor; import android.content.ComponentName; import android.content.Context; @@ -56,6 +59,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; public class ChooserListAdapter extends ResolverListAdapter { private static final String TAG = "ChooserListAdapter"; @@ -108,6 +112,9 @@ public class ChooserListAdapter extends ResolverListAdapter { // Represents the UserSpace in which the Initial Intents should be resolved. private final UserHandle mInitialIntentsUserSpace; + @Nullable + private Consumer<DisplayResolveInfo> mOnIconLoadedListener; + // For pinned direct share labels, if the text spans multiple lines, the TextView will consume // the full width, even if the characters actually take up less than that. Measure the actual // line widths and constrain the View's width based upon that so that the pin doesn't end up @@ -218,6 +225,10 @@ public class ChooserListAdapter extends ResolverListAdapter { true); } + public void setOnIconLoadedListener(Consumer<DisplayResolveInfo> onIconLoadedListener) { + mOnIconLoadedListener = onIconLoadedListener; + } + AppPredictor getAppPredictor() { return mAppPredictor; } @@ -329,6 +340,15 @@ public class ChooserListAdapter extends ResolverListAdapter { } } + @Override + protected void onIconLoaded(DisplayResolveInfo info) { + if (notifySingleItemChangeOnIconLoad() && mOnIconLoadedListener != null) { + mOnIconLoadedListener.accept(info); + } else { + notifyDataSetChanged(); + } + } + private void loadDirectShareIcon(SelectableTargetInfo info) { LoadDirectShareIconTask task = (LoadDirectShareIconTask) mIconLoaders.get(info); if (task == null) { diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java index 54c0e61fd5cd..4d9ce86096c7 100644 --- a/core/java/com/android/internal/app/ResolverListAdapter.java +++ b/core/java/com/android/internal/app/ResolverListAdapter.java @@ -680,6 +680,10 @@ public class ResolverListAdapter extends BaseAdapter { } } + protected void onIconLoaded(DisplayResolveInfo info) { + notifyDataSetChanged(); + } + private void loadLabel(DisplayResolveInfo info) { LoadLabelTask task = mLabelLoaders.get(info); if (task == null) { @@ -1004,7 +1008,7 @@ public class ResolverListAdapter extends BaseAdapter { mResolverListCommunicator.updateProfileViewButton(); } else if (!mDisplayResolveInfo.hasDisplayIcon()) { mDisplayResolveInfo.setDisplayIcon(d); - notifyDataSetChanged(); + onIconLoaded(mDisplayResolveInfo); } } } diff --git a/core/java/com/android/internal/policy/SystemBarUtils.java b/core/java/com/android/internal/policy/SystemBarUtils.java index 4ed15faf8b89..783c68695fb3 100644 --- a/core/java/com/android/internal/policy/SystemBarUtils.java +++ b/core/java/com/android/internal/policy/SystemBarUtils.java @@ -16,6 +16,8 @@ package com.android.internal.policy; +import android.annotation.DimenRes; +import android.annotation.NonNull; import android.content.Context; import android.content.res.Resources; import android.graphics.Insets; @@ -99,4 +101,19 @@ public final class SystemBarUtils { public static int getTaskbarHeight(Resources res) { return res.getDimensionPixelSize(R.dimen.taskbar_frame_height); } + + /** + * Gets the default app header height in desktop view in pixels. + */ + public static int getDesktopViewAppHeaderHeightPx(@NonNull Context context) { + return context.getResources().getDimensionPixelSize(getDesktopViewAppHeaderHeightId()); + } + + /** + * Gets the dimen resource id of the default app header height in desktop view. + */ + @DimenRes + public static int getDesktopViewAppHeaderHeightId() { + return R.dimen.desktop_view_default_header_height; + } } diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index 9380d99b7de3..0791612fa0e8 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -105,7 +105,7 @@ interface IInputMethodManager { in @nullable EditorInfo editorInfo, in @nullable IRemoteInputConnection inputConnection, in @nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, int unverifiedTargetSdkVersion, int userId, - in ImeOnBackInvokedDispatcher imeDispatcher); + in ImeOnBackInvokedDispatcher imeDispatcher, boolean imeRequestedVisible); // If windowToken is null, this just does startInput(). Otherwise this reports that a window // has gained focus, and if 'editorInfo' is non-null then also does startInput. @@ -120,8 +120,8 @@ interface IInputMethodManager { in @nullable EditorInfo editorInfo, in @nullable IRemoteInputConnection inputConnection, in @nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, int unverifiedTargetSdkVersion, int userId, - in ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq, - boolean useAsyncShowHideMethod); + in ImeOnBackInvokedDispatcher imeDispatcher, boolean imeRequestedVisible, + int startInputSeq, boolean useAsyncShowHideMethod); void showInputMethodPickerFromClient(in IInputMethodClient client, int auxiliarySubtypeMode); @@ -224,7 +224,7 @@ interface IInputMethodManager { * async **/ oneway void acceptStylusHandwritingDelegationAsync(in IInputMethodClient client, in int userId, in String delegatePackageName, in String delegatorPackageName, int flags, - in IBooleanListener callback); + in IBooleanListener callback); /** Returns {@code true} if currently selected IME supports Stylus handwriting. */ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java index cac2024f548d..cf9f1c8b380a 100644 --- a/core/java/com/android/internal/widget/NotificationActionListLayout.java +++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java @@ -16,6 +16,7 @@ package com.android.internal.widget; +import static android.app.Flags.notificationsRedesignTemplates; import static android.app.Notification.CallStyle.DEBUG_NEW_ACTION_LAYOUT; import static android.app.Flags.evenlyDividedCallStyleActionLayout; @@ -368,12 +369,17 @@ public class NotificationActionListLayout extends LinearLayout { @Override protected void onFinishInflate() { super.onFinishInflate(); - mDefaultPaddingBottom = getPaddingBottom(); - mDefaultPaddingTop = getPaddingTop(); - updateHeights(); + if (!notificationsRedesignTemplates()) { + mDefaultPaddingBottom = getPaddingBottom(); + mDefaultPaddingTop = getPaddingTop(); + updateHeights(); + } } private void updateHeights() { + if (notificationsRedesignTemplates()) { + return; + } int inset = getResources().getDimensionPixelSize( com.android.internal.R.dimen.button_inset_vertical_material); mEmphasizedPaddingTop = getResources().getDimensionPixelSize( @@ -440,6 +446,9 @@ public class NotificationActionListLayout extends LinearLayout { */ @RemotableViewMethod public void setEmphasizedMode(boolean emphasizedMode) { + if (notificationsRedesignTemplates()) { + return; + } mEmphasizedMode = emphasizedMode; int height; if (emphasizedMode) { @@ -462,7 +471,9 @@ public class NotificationActionListLayout extends LinearLayout { } public int getExtraMeasureHeight() { - if (mEmphasizedMode) { + // Note: the emphasized height is no longer different from the regular height when the + // notificationsRedesignTemplates flag is on. + if (!notificationsRedesignTemplates() && mEmphasizedMode) { return mEmphasizedHeight - mRegularHeight; } return 0; diff --git a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java index 796ea8d1538f..3cc998576741 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java +++ b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java @@ -20,6 +20,7 @@ import android.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.widget.remotecompose.core.operations.ComponentValue; +import com.android.internal.widget.remotecompose.core.operations.DrawContent; import com.android.internal.widget.remotecompose.core.operations.FloatExpression; import com.android.internal.widget.remotecompose.core.operations.Header; import com.android.internal.widget.remotecompose.core.operations.IntegerExpression; @@ -28,9 +29,11 @@ import com.android.internal.widget.remotecompose.core.operations.RootContentBeha import com.android.internal.widget.remotecompose.core.operations.ShaderData; import com.android.internal.widget.remotecompose.core.operations.TextData; import com.android.internal.widget.remotecompose.core.operations.Theme; +import com.android.internal.widget.remotecompose.core.operations.layout.CanvasOperations; import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.layout.Container; import com.android.internal.widget.remotecompose.core.operations.layout.ContainerEnd; +import com.android.internal.widget.remotecompose.core.operations.layout.LayoutComponent; import com.android.internal.widget.remotecompose.core.operations.layout.LoopOperation; import com.android.internal.widget.remotecompose.core.operations.layout.RootLayoutComponent; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ComponentModifiers; @@ -65,7 +68,7 @@ public class CoreDocument implements Serializable { // We also keep a more fine-grained BUILD number, exposed as // ID_API_LEVEL = DOCUMENT_API_LEVEL + BUILD - static final float BUILD = 0.3f; + static final float BUILD = 0.4f; @NonNull ArrayList<Operation> mOperations = new ArrayList<>(); @@ -102,6 +105,8 @@ public class CoreDocument implements Serializable { private IntMap<Object> mDocProperties; + boolean mFirstPaint = true; + /** Returns a version number that is monotonically increasing. */ public static int getDocumentApiLevel() { return DOCUMENT_API_LEVEL; @@ -678,6 +683,7 @@ public class CoreDocument implements Serializable { ArrayList<Operation> ops = finalOperationsList; ArrayList<Container> containers = new ArrayList<>(); + LayoutComponent lastLayoutComponent = null; mLastId = -1; for (Operation o : operations) { @@ -697,6 +703,9 @@ public class CoreDocument implements Serializable { if (component.getComponentId() < mLastId) { mLastId = component.getComponentId(); } + if (component instanceof LayoutComponent) { + lastLayoutComponent = (LayoutComponent) component; + } } containers.add(container); ops = container.getList(); @@ -723,7 +732,13 @@ public class CoreDocument implements Serializable { } ops.add((Operation) container); } + if (container instanceof CanvasOperations) { + ((CanvasOperations) container).setComponent(lastLayoutComponent); + } } else { + if (o instanceof DrawContent) { + ((DrawContent) o).setComponent(lastLayoutComponent); + } ops.add(o); } } @@ -784,6 +799,7 @@ public class CoreDocument implements Serializable { registerVariables(context, mOperations); context.mMode = RemoteContext.ContextMode.UNSET; + mFirstPaint = true; } /////////////////////////////////////////////////////////////////////////////////////////////// @@ -1093,6 +1109,28 @@ public class CoreDocument implements Serializable { } /** + * Traverse the list of operations to update the variables. TODO: this should walk the + * dependency tree instead + * + * @param context + * @param operations + */ + private void updateVariables( + @NonNull RemoteContext context, int theme, List<Operation> operations) { + for (int i = 0; i < operations.size(); i++) { + Operation op = operations.get(i); + if (op.isDirty() && op instanceof VariableSupport) { + ((VariableSupport) op).updateVariables(context); + op.apply(context); + op.markNotDirty(); + } + if (op instanceof Container) { + updateVariables(context, theme, ((Container) op).getList()); + } + } + } + + /** * Paint the document * * @param context the provided PaintContext @@ -1110,6 +1148,13 @@ public class CoreDocument implements Serializable { context.mRemoteComposeState = mRemoteComposeState; context.mRemoteComposeState.setContext(context); + // Update any dirty variables + if (mFirstPaint) { + mFirstPaint = false; + } else { + updateVariables(context, theme, mOperations); + } + // If we have a content sizing set, we are going to take the original document // dimension into account and apply scale+translate according to the RootContentBehavior // rules. diff --git a/core/java/com/android/internal/widget/remotecompose/core/Operations.java b/core/java/com/android/internal/widget/remotecompose/core/Operations.java index 9cbafab07a43..20897ba77de4 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/Operations.java +++ b/core/java/com/android/internal/widget/remotecompose/core/Operations.java @@ -25,6 +25,7 @@ import com.android.internal.widget.remotecompose.core.operations.ClipRect; import com.android.internal.widget.remotecompose.core.operations.ColorConstant; import com.android.internal.widget.remotecompose.core.operations.ColorExpression; import com.android.internal.widget.remotecompose.core.operations.ComponentValue; +import com.android.internal.widget.remotecompose.core.operations.ConditionalOperations; import com.android.internal.widget.remotecompose.core.operations.DataListFloat; import com.android.internal.widget.remotecompose.core.operations.DataListIds; import com.android.internal.widget.remotecompose.core.operations.DataMapIds; @@ -50,6 +51,7 @@ import com.android.internal.widget.remotecompose.core.operations.FloatConstant; import com.android.internal.widget.remotecompose.core.operations.FloatExpression; import com.android.internal.widget.remotecompose.core.operations.FloatFunctionCall; import com.android.internal.widget.remotecompose.core.operations.FloatFunctionDefine; +import com.android.internal.widget.remotecompose.core.operations.HapticFeedback; import com.android.internal.widget.remotecompose.core.operations.Header; import com.android.internal.widget.remotecompose.core.operations.ImageAttribute; import com.android.internal.widget.remotecompose.core.operations.IntegerExpression; @@ -64,6 +66,7 @@ import com.android.internal.widget.remotecompose.core.operations.PaintData; import com.android.internal.widget.remotecompose.core.operations.ParticlesCreate; import com.android.internal.widget.remotecompose.core.operations.ParticlesLoop; import com.android.internal.widget.remotecompose.core.operations.PathAppend; +import com.android.internal.widget.remotecompose.core.operations.PathCombine; import com.android.internal.widget.remotecompose.core.operations.PathCreate; import com.android.internal.widget.remotecompose.core.operations.PathData; import com.android.internal.widget.remotecompose.core.operations.PathTween; @@ -222,6 +225,9 @@ public class Operations { public static final int ATTRIBUTE_TIME = 172; public static final int CANVAS_OPERATIONS = 173; public static final int MODIFIER_DRAW_CONTENT = 174; + public static final int PATH_COMBINE = 175; + public static final int HAPTIC_FEEDBACK = 177; + public static final int CONDITIONAL_OPERATIONS = 178; ///////////////////////////////////////// ====================== @@ -426,6 +432,9 @@ public class Operations { map.put(ATTRIBUTE_IMAGE, ImageAttribute::read); map.put(ATTRIBUTE_TEXT, TextAttribute::read); map.put(ATTRIBUTE_TIME, TimeAttribute::read); + map.put(PATH_COMBINE, PathCombine::read); + map.put(HAPTIC_FEEDBACK, HapticFeedback::read); + map.put(CONDITIONAL_OPERATIONS, ConditionalOperations::read); // map.put(ACCESSIBILITY_CUSTOM_ACTION, CoreSemantics::read); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java index 1b0b9d783dff..e61ca4c1ee13 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java +++ b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java @@ -340,6 +340,17 @@ public abstract class PaintContext { public abstract void tweenPath(int out, int path1, int path2, float tween); /** + * Perform a between two path and return the resulting path + * + * @param out the interpolated path + * @param path1 start path + * @param path2 end path + * @param operation 0 = difference , 1 = intersection, 2 = reverse_difference, 3 = union, 4 = + * xor + */ + public abstract void combinePath(int out, int path1, int path2, byte operation); + + /** * This applies changes to the current paint * * @param mPaintData the list of changes diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java index c249adf5bd58..161a5f17ef23 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java +++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java @@ -28,6 +28,7 @@ import com.android.internal.widget.remotecompose.core.operations.ClipRect; import com.android.internal.widget.remotecompose.core.operations.ColorConstant; import com.android.internal.widget.remotecompose.core.operations.ColorExpression; import com.android.internal.widget.remotecompose.core.operations.ComponentValue; +import com.android.internal.widget.remotecompose.core.operations.ConditionalOperations; import com.android.internal.widget.remotecompose.core.operations.DataListFloat; import com.android.internal.widget.remotecompose.core.operations.DataListIds; import com.android.internal.widget.remotecompose.core.operations.DataMapIds; @@ -53,6 +54,7 @@ import com.android.internal.widget.remotecompose.core.operations.FloatConstant; import com.android.internal.widget.remotecompose.core.operations.FloatExpression; import com.android.internal.widget.remotecompose.core.operations.FloatFunctionCall; import com.android.internal.widget.remotecompose.core.operations.FloatFunctionDefine; +import com.android.internal.widget.remotecompose.core.operations.HapticFeedback; import com.android.internal.widget.remotecompose.core.operations.Header; import com.android.internal.widget.remotecompose.core.operations.ImageAttribute; import com.android.internal.widget.remotecompose.core.operations.IntegerExpression; @@ -67,6 +69,7 @@ import com.android.internal.widget.remotecompose.core.operations.PaintData; import com.android.internal.widget.remotecompose.core.operations.ParticlesCreate; import com.android.internal.widget.remotecompose.core.operations.ParticlesLoop; import com.android.internal.widget.remotecompose.core.operations.PathAppend; +import com.android.internal.widget.remotecompose.core.operations.PathCombine; import com.android.internal.widget.remotecompose.core.operations.PathCreate; import com.android.internal.widget.remotecompose.core.operations.PathData; import com.android.internal.widget.remotecompose.core.operations.PathTween; @@ -890,7 +893,7 @@ public class RemoteComposeBuffer { * @return new id that merges the two text */ public int textMerge(int id1, int id2) { - int textId = addText(id1 + "+" + id2); + int textId = nextId(); TextMerge.apply(mBuffer, textId, id1, id2); return textId; } @@ -2273,8 +2276,6 @@ public class RemoteComposeBuffer { return mRemoteComposeState.nextId(); } - private boolean mInImpulseProcess = false; - /** * add an impulse. (must be followed by impulse end) * @@ -2283,22 +2284,16 @@ public class RemoteComposeBuffer { */ public void addImpulse(float duration, float start) { ImpulseOperation.apply(mBuffer, duration, start); - mInImpulseProcess = false; } /** add an impulse process */ public void addImpulseProcess() { ImpulseProcess.apply(mBuffer); - mInImpulseProcess = true; } /** Add an impulse end */ public void addImpulseEnd() { ContainerEnd.apply(mBuffer); - if (mInImpulseProcess) { - ContainerEnd.apply(mBuffer); - } - mInImpulseProcess = false; } /** @@ -2422,4 +2417,37 @@ public class RemoteComposeBuffer { return imageId; } + + /** + * Combine two paths + * + * @param id output id + * @param path1 first path + * @param path2 second path + * @param op operation to perform OP_DIFFERENCE, OP_INTERSECT, OP_REVERSE_DIFFERENCE, OP_UNION, + * OP_XOR + */ + public void pathCombine(int id, int path1, int path2, byte op) { + PathCombine.apply(mBuffer, id, path1, path2, op); + } + + /** + * Perform a haptic feedback + * + * @param feedbackConstant + */ + public void performHaptic(int feedbackConstant) { + HapticFeedback.apply(mBuffer, feedbackConstant); + } + + /** + * Add a conditional operation + * + * @param type type of comparison + * @param a first value + * @param b second value + */ + public void addConditionalOperations(byte type, float a, float b) { + ConditionalOperations.apply(mBuffer, type, a, b); + } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java index c6b17e4116d6..e37833f33fa5 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java +++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java @@ -552,6 +552,14 @@ public abstract class RemoteContext { public abstract int getInteger(int id); /** + * Get a Long given an id + * + * @param id of the long + * @return the value + */ + public abstract long getLong(int id); + + /** * Get the color given and ID * * @param id of the color @@ -629,6 +637,8 @@ public abstract class RemoteContext { /** The delta between current and last Frame */ public static final int ID_ANIMATION_DELTA_TIME = 31; + public static final int ID_EPOCH_SECOND = 32; + public static final float FLOAT_DENSITY = Utils.asNan(ID_DENSITY); /** CONTINUOUS_SEC is seconds from midnight looping every hour 0-3600 */ @@ -714,6 +724,9 @@ public abstract class RemoteContext { /** When was this player built */ public static final float FLOAT_API_LEVEL = Utils.asNan(ID_API_LEVEL); + /** The time in seconds since the epoch. */ + public static final long INT_EPOCH_SECOND = ((long) ID_EPOCH_SECOND) + 0x100000000L; + /////////////////////////////////////////////////////////////////////////////////////////////// // Click handling /////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java b/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java index cd5b202f5a79..57300364e0b5 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java +++ b/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java @@ -49,9 +49,12 @@ public class TimeVariables { OffsetDateTime offsetDateTime = dateTime.atZone(zoneId).toOffsetDateTime(); ZoneOffset offset = offsetDateTime.getOffset(); + long epochSec = dateTime.toEpochSecond(offset); context.loadFloat(RemoteContext.ID_OFFSET_TO_UTC, offset.getTotalSeconds()); context.loadFloat(RemoteContext.ID_CONTINUOUS_SEC, sec); + // This will overflow in 2038. + context.loadInteger(RemoteContext.ID_EPOCH_SECOND, (int) epochSec); context.loadFloat(RemoteContext.ID_TIME_IN_SEC, currentSeconds); context.loadFloat(RemoteContext.ID_TIME_IN_MIN, currentMinute); context.loadFloat(RemoteContext.ID_TIME_IN_HR, hour); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ConditionalOperations.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ConditionalOperations.java new file mode 100644 index 000000000000..da6035e1e87e --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ConditionalOperations.java @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import android.annotation.NonNull; + +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.VariableSupport; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.Container; +import com.android.internal.widget.remotecompose.core.serialize.MapSerializer; +import com.android.internal.widget.remotecompose.core.serialize.Serializable; + +import java.util.ArrayList; +import java.util.List; + +/** Represents conditional execution of a block of commands */ +public class ConditionalOperations extends PaintOperation + implements Container, VariableSupport, Serializable { + private static final String CLASS_NAME = "ConditionalOperations"; + + private static final int OP_CODE = Operations.CONDITIONAL_OPERATIONS; + + @NonNull public ArrayList<Operation> mList = new ArrayList<>(); + + int mIndexVariableId; + byte mType; + float mVarA; + float mVarB; + float mVarAOut; + float mVarBOut; + + /** Equality comparison */ + public static final byte TYPE_EQ = 0; + + /** Not equal comparison */ + public static final byte TYPE_NEQ = 1; + + /** Less than comparison */ + public static final byte TYPE_LT = 2; + + /** Less than or equal comparison */ + public static final byte TYPE_LTE = 3; + + /** Greater than comparison */ + public static final byte TYPE_GT = 4; + + /** Greater than or equal comparison */ + public static final byte TYPE_GTE = 5; + + private static final String[] TYPE_STR = {"EQ", "NEQ", "LT", "LTE", "GT", "GTE"}; + + @Override + public void registerListening(RemoteContext context) { + if (Float.isNaN(mVarA)) { + context.listensTo(Utils.idFromNan(mVarA), this); + } + if (Float.isNaN(mVarB)) { + context.listensTo(Utils.idFromNan(mVarB), this); + } + } + + @Override + public void updateVariables(RemoteContext context) { + mVarAOut = Float.isNaN(mVarA) ? context.getFloat(Utils.idFromNan(mVarA)) : mVarA; + mVarBOut = Float.isNaN(mVarB) ? context.getFloat(Utils.idFromNan(mVarB)) : mVarB; + } + + /** + * Constructor + * + * @param type type of comparison + * @param a first value + * @param b second value + */ + public ConditionalOperations(byte type, float a, float b) { + mType = type; + mVarAOut = mVarA = a; + mVarBOut = mVarB = b; + } + + @Override + @NonNull + public ArrayList<Operation> getList() { + return mList; + } + + @Override + public void write(@NonNull WireBuffer buffer) { + apply(buffer, mType, mVarA, mVarB); + } + + @NonNull + @Override + public String toString() { + StringBuilder builder = + new StringBuilder( + CLASS_NAME + + " " + + TYPE_STR[mType] + + "(" + + Utils.idFromNan(mVarA) + + "," + + Utils.idFromNan(mVarB) + + ")\n"); + for (Operation operation : mList) { + builder.append(" "); + builder.append(operation); + builder.append("\n"); + } + return builder.toString(); + } + + @NonNull + @Override + public String deepToString(@NonNull String indent) { + return (indent != null ? indent : "") + toString(); + } + + @Override + public void paint(@NonNull PaintContext context) { + RemoteContext remoteContext = context.getContext(); + boolean run = false; + switch (mType) { + case TYPE_EQ: + run = mVarAOut == mVarBOut; + break; + case TYPE_NEQ: + run = mVarAOut != mVarBOut; + break; + case TYPE_LT: + run = mVarAOut < mVarBOut; + break; + case TYPE_LTE: + run = mVarAOut <= mVarBOut; + break; + case TYPE_GT: + run = mVarAOut > mVarBOut; + break; + case TYPE_GTE: + run = mVarAOut >= mVarBOut; + break; + } + if (run) { + for (Operation op : mList) { + remoteContext.incrementOpCount(); + op.apply(context.getContext()); + } + } + } + + /** + * The name of the class + * + * @return the name + */ + @NonNull + public static String name() { + return CLASS_NAME; + } + + /** + * Write the operation on the buffer + * + * @param type type of operation + * @param a first value + * @param b second value + * @param buffer the buffer to write to + */ + public static void apply(@NonNull WireBuffer buffer, byte type, float a, float b) { + buffer.start(OP_CODE); + buffer.writeByte(type); + buffer.writeFloat(a); + buffer.writeFloat(b); + } + + /** + * Read this operation and add it to the list of operations + * + * @param buffer the buffer to read + * @param operations the list of operations that will be added to + */ + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { + byte type = (byte) buffer.readByte(); + float a = buffer.readFloat(); + float b = buffer.readFloat(); + operations.add(new ConditionalOperations(type, a, b)); + } + + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ + public static void documentation(@NonNull DocumentationBuilder doc) { + doc.operation("Operations", OP_CODE, name()) + .description("Run if the condition is true") + .field(DocumentedOperation.BYTE, "type", "type of comparison") + .field(DocumentedOperation.FLOAT, "a", "first value") + .field(DocumentedOperation.FLOAT, "b", "second value"); + } + + /** + * Calculate and estimate of the number of iterations + * + * @return number of loops or 10 if based on variables + */ + public int estimateIterations() { + return 1; // this is a generic estmate if the values are variables; + } + + @Override + public void serialize(MapSerializer serializer) { + serializer + .addType(CLASS_NAME) + .add("type", mType) + .add("varA", mVarA, mVarAOut) + .add("VarB", mVarB, mVarBOut) + .add("list", mList); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawContent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawContent.java index 4d2a939eb948..326f0600854e 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawContent.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawContent.java @@ -46,7 +46,7 @@ public class DrawContent extends PaintOperation implements Serializable { * * @param component */ - public void setComponent(LayoutComponent component) { + public void setComponent(@Nullable LayoutComponent component) { mComponent = component; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java index 31d9b6ac124d..5853578ab31e 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java @@ -110,7 +110,7 @@ public class DrawRoundRect extends DrawBase6 { "The x-radius of the oval used to round the corners") .field( DocumentedOperation.FLOAT, - "sweepAngle", + "ry", "The y-radius of the oval used to round the corners"); } @@ -126,7 +126,6 @@ public class DrawRoundRect extends DrawBase6 { @Override public void serialize(MapSerializer serializer) { - serialize(serializer, "left", "top", "right", "bottom", "rx", "sweepAngle") - .addType(CLASS_NAME); + serialize(serializer, "left", "top", "right", "bottom", "rx", "ry").addType(CLASS_NAME); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java index ee1689c21fe3..cec01c4e5b65 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java @@ -211,6 +211,7 @@ public class DrawText extends PaintOperation implements VariableSupport { public void serialize(MapSerializer serializer) { serializer .addType(CLASS_NAME) + .add("textId", mTextID) .add("start", mStart) .add("end", mEnd) .add("contextStart", mContextStart) diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/HapticFeedback.java b/core/java/com/android/internal/widget/remotecompose/core/operations/HapticFeedback.java new file mode 100644 index 000000000000..1b7f5e84b171 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/HapticFeedback.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import android.annotation.NonNull; + +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.SerializableToString; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation; +import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; +import com.android.internal.widget.remotecompose.core.serialize.MapSerializer; +import com.android.internal.widget.remotecompose.core.serialize.Serializable; + +import java.util.List; + +/** Generate HapticFeedback */ +public class HapticFeedback extends Operation implements SerializableToString, Serializable { + private static final int OP_CODE = Operations.HAPTIC_FEEDBACK; + private static final String CLASS_NAME = "HapticFeedback"; + private int mHapticFeedbackType; + + public HapticFeedback(int hapticFeedbackType) { + this.mHapticFeedbackType = hapticFeedbackType; + } + + @Override + public void write(@NonNull WireBuffer buffer) { + apply(buffer, mHapticFeedbackType); + } + + @NonNull + @Override + public String toString() { + return CLASS_NAME + "(" + mHapticFeedbackType + ")"; + } + + /** + * The name of the class + * + * @return the name + */ + @NonNull + public static String name() { + return CLASS_NAME; + } + + /** + * The OP_CODE for this command + * + * @return the opcode + */ + public static int id() { + return OP_CODE; + } + + /** + * add a text data operation + * + * @param buffer buffer to add to + * @param hapticFeedbackType the vibration effect + */ + public static void apply(@NonNull WireBuffer buffer, int hapticFeedbackType) { + buffer.start(OP_CODE); + buffer.writeInt(hapticFeedbackType); + } + + /** + * Read this operation and add it to the list of operations + * + * @param buffer the buffer to read + * @param operations the list of operations that will be added to + */ + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { + int hapticFeedbackType = buffer.readInt(); + + operations.add(new HapticFeedback(hapticFeedbackType)); + } + + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ + public static void documentation(@NonNull DocumentationBuilder doc) { + doc.operation("Data Operations", OP_CODE, CLASS_NAME) + .description("Generate an haptic feedback") + .field(DocumentedOperation.INT, "HapticFeedbackType", "Type of haptic feedback"); + } + + @Override + public void apply(@NonNull RemoteContext context) { + context.hapticEffect(mHapticFeedbackType); + } + + @NonNull + @Override + public String deepToString(@NonNull String indent) { + return indent + toString(); + } + + @Override + public void serializeToString(int indent, @NonNull StringSerializer serializer) { + serializer.append(indent, getSerializedName() + "<" + mHapticFeedbackType + ">"); + } + + @NonNull + private String getSerializedName() { + return "HAPTIC_FEEDBACK"; + } + + @Override + public void serialize(MapSerializer serializer) { + serializer.addType(CLASS_NAME).add("hapticFeedbackType", mHapticFeedbackType); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathCombine.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathCombine.java new file mode 100644 index 000000000000..5f761d184e29 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathCombine.java @@ -0,0 +1,176 @@ +/* + * 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.internal.widget.remotecompose.core.operations; + +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; + +import android.annotation.NonNull; + +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.VariableSupport; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation; +import com.android.internal.widget.remotecompose.core.serialize.MapSerializer; +import com.android.internal.widget.remotecompose.core.serialize.Serializable; + +import java.util.List; + +/** Operation to perform Constructive area geometry operations, combining two Paths */ +public class PathCombine extends PaintOperation implements VariableSupport, Serializable { + private static final int OP_CODE = Operations.PATH_COMBINE; + private static final String CLASS_NAME = "PathCombine"; + public int mOutId; + public int mPathId1; + public int mPathId2; + private byte mOperation; + + /** Subtract the second path from the first path. */ + public static final byte OP_DIFFERENCE = 0; + + /** Intersect the second path with the first path. */ + public static final byte OP_INTERSECT = 1; + + /** Subtract the first path from the second path. */ + public static final byte OP_REVERSE_DIFFERENCE = 2; + + /** Union (inclusive-or) the two paths. */ + public static final byte OP_UNION = 3; + + /** Exclusive-or the two paths. */ + public static final byte OP_XOR = 4; + + public PathCombine(int outId, int pathId1, int pathId2, byte operation) { + this.mOutId = outId; + this.mPathId1 = pathId1; + this.mPathId2 = pathId2; + this.mOperation = operation; + } + + @Override + public void updateVariables(@NonNull RemoteContext context) {} + + @Override + public void registerListening(@NonNull RemoteContext context) {} + + @Override + public void write(@NonNull WireBuffer buffer) { + apply(buffer, mOutId, mPathId1, mPathId2, mOperation); + } + + @NonNull + @Override + public String toString() { + return CLASS_NAME + + "[" + + mOutId + + "] = [" + + mPathId1 + + " ] + [ " + + mPathId2 + + "], " + + mOperation; + } + + /** + * The name of the class + * + * @return the name + */ + @NonNull + public static String name() { + return CLASS_NAME; + } + + /** + * The OP_CODE for this command + * + * @return the opcode + */ + public static int id() { + return OP_CODE; + } + + /** + * Writes out the operation to the buffer + * + * @param buffer buffer to write to + * @param outId id of the path + * @param pathId1 source path 1 + * @param pathId2 source path 2 + * @param op the operation to perform + */ + public static void apply( + @NonNull WireBuffer buffer, int outId, int pathId1, int pathId2, byte op) { + buffer.start(OP_CODE); + buffer.writeInt(outId); + buffer.writeInt(pathId1); + buffer.writeInt(pathId2); + buffer.writeByte(op); + } + + /** + * Read this operation and add it to the list of operations + * + * @param buffer the buffer to read + * @param operations the list of operations that will be added to + */ + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { + int outId1 = buffer.readInt(); + int pathId1 = buffer.readInt(); + int pathId2 = buffer.readInt(); + byte op = (byte) buffer.readByte(); + operations.add(new PathCombine(outId1, pathId1, pathId2, op)); + } + + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ + public static void documentation(@NonNull DocumentationBuilder doc) { + doc.operation("Data Operations", OP_CODE, CLASS_NAME) + .description("Merge two string into one") + .field(INT, "srcPathId1", "id of the path") + .field(INT, "srcPathId1", "x Shift of the path") + .field(DocumentedOperation.BYTE, "operation", "the operation"); + } + + @NonNull + @Override + public String deepToString(String indent) { + return indent + toString(); + } + + @Override + public void paint(PaintContext context) { + context.combinePath(mOutId, mPathId1, mPathId2, mOperation); + } + + @Override + public void serialize(MapSerializer serializer) { + serializer + .addType(CLASS_NAME) + .add("outId", mOutId) + .add("pathId1", mPathId1) + .add("pathId2", mPathId2) + .add("operation", mOperation); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java index 1239b5648446..2bc77cc48839 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.VariableSupport; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation; @@ -31,7 +32,7 @@ import com.android.internal.widget.remotecompose.core.serialize.Serializable; import java.util.List; /** Operation to deal with Text data */ -public class TextMerge extends Operation implements Serializable { +public class TextMerge extends Operation implements VariableSupport, Serializable { private static final int OP_CODE = Operations.TEXT_MERGE; private static final String CLASS_NAME = "TextMerge"; public int mTextId; @@ -123,10 +124,21 @@ public class TextMerge extends Operation implements Serializable { context.loadText(mTextId, str1 + str2); } + @Override + public void updateVariables(@NonNull RemoteContext context) { + apply(context); + } + + @Override + public void registerListening(@NonNull RemoteContext context) { + context.listensTo(mSrcId1, this); + context.listensTo(mSrcId2, this); + } + @NonNull @Override public String deepToString(@NonNull String indent) { - return indent + toString(); + return indent + this; } @Override diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TimeAttribute.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TimeAttribute.java index fd9a2bf5e435..e9cc26f58c9b 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/TimeAttribute.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TimeAttribute.java @@ -275,7 +275,7 @@ public class TimeAttribute extends PaintOperation { ctx.loadFloat(mId, time.getSecond()); break; case TIME_IN_MIN: - ctx.loadFloat(mId, time.getDayOfMonth()); + ctx.loadFloat(mId, time.getMinute()); break; case TIME_IN_HR: ctx.loadFloat(mId, time.getHour()); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasOperations.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasOperations.java index 25a10ab7dbeb..e473d9e392d2 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasOperations.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasOperations.java @@ -27,7 +27,6 @@ import com.android.internal.widget.remotecompose.core.VariableSupport; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; import com.android.internal.widget.remotecompose.core.operations.ComponentValue; -import com.android.internal.widget.remotecompose.core.operations.DrawContent; import com.android.internal.widget.remotecompose.core.serialize.MapSerializer; import com.android.internal.widget.remotecompose.core.serialize.Serializable; @@ -164,12 +163,10 @@ public class CanvasOperations extends PaintOperation * * @param layoutComponent */ - public void setComponent(LayoutComponent layoutComponent) { + public void setComponent(@Nullable LayoutComponent layoutComponent) { mComponent = layoutComponent; - for (Operation op : mList) { - if (op instanceof DrawContent) { - ((DrawContent) op).setComponent(layoutComponent); - } + if (layoutComponent != null) { + layoutComponent.setCanvasOperations(this); } } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java index b30dade828a7..76bb96d1b61a 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java @@ -556,6 +556,7 @@ public class Component extends PaintOperation ComponentMeasure m = measure.get(this); if (!mFirstLayout && context.isAnimationEnabled() + && mAnimationSpec.isAnimationEnabled() && !(this instanceof LayoutComponentContent)) { if (mAnimateMeasure == null) { ComponentMeasure origin = @@ -1129,17 +1130,6 @@ public class Component extends PaintOperation } } - /** Extract CanvasOperations if present */ - public @Nullable CanvasOperations getCanvasOperations(LayoutComponent layoutComponent) { - for (Operation op : mList) { - if (op instanceof CanvasOperations) { - ((CanvasOperations) op).setComponent(layoutComponent); - return (CanvasOperations) op; - } - } - return null; - } - /** * Extract child TextData elements * diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseOperation.java index 0e629c5d2448..3e1cf35e153a 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseOperation.java @@ -117,7 +117,7 @@ public class ImpulseOperation extends PaintOperation implements VariableSupport, @NonNull @Override public String toString() { - StringBuilder builder = new StringBuilder("LoopOperation\n"); + StringBuilder builder = new StringBuilder("ImpulseOperation\n"); for (Operation operation : mList) { builder.append(" startAt: "); builder.append(mStartAt); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java index 7e2a4ccec222..e57438662012 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java @@ -127,6 +127,15 @@ public class LayoutComponent extends Component { // Should be removed after ImageLayout is in private static final boolean USE_IMAGE_TEMP_FIX = true; + /** + * Set canvas operations op on this component + * + * @param operations + */ + public void setCanvasOperations(@Nullable CanvasOperations operations) { + mDrawContentOperations = operations; + } + @Override public void inflate() { ArrayList<TextData> data = new ArrayList<>(); @@ -139,7 +148,6 @@ public class LayoutComponent extends Component { mChildrenComponents.clear(); LayoutComponentContent content = (LayoutComponentContent) op; content.getComponents(mChildrenComponents); - mDrawContentOperations = content.getCanvasOperations(this); if (USE_IMAGE_TEMP_FIX) { if (mChildrenComponents.isEmpty() && !mContent.mList.isEmpty()) { CanvasContent canvasContent = diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java index dda328f57a3b..e5914eb7fd28 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java @@ -211,7 +211,6 @@ public class LoopOperation extends PaintOperation .add("until", mUntil, mUntilOut) .add("from", mFrom, mFromOut) .add("step", mStep, mStepOut) - .add("untilOut", mUntilOut) .add("list", mList); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java index c87bbdc9809d..4f552e7a9aaa 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java @@ -35,6 +35,7 @@ import java.util.List; /** Basic component animation spec */ public class AnimationSpec extends Operation implements ModifierOperation { public static final AnimationSpec DEFAULT = new AnimationSpec(); + public static final AnimationSpec DISABLED = new AnimationSpec(0); int mAnimationId = -1; float mMotionDuration = 300; int mMotionEasingType = GeneralEasing.CUBIC_STANDARD; @@ -71,6 +72,15 @@ public class AnimationSpec extends Operation implements ModifierOperation { ANIMATION.FADE_OUT); } + public AnimationSpec(int value) { + this(); + mAnimationId = value; + } + + public boolean isAnimationEnabled() { + return mAnimationId != 0; + } + public int getAnimationId() { return mAnimationId; } @@ -130,6 +140,7 @@ public class AnimationSpec extends Operation implements ModifierOperation { public void serialize(MapSerializer serializer) { serializer .addType("AnimationSpec") + .add("animationId", mAnimationId) .add("motionDuration", getMotionDuration()) .add("motionEasingType", Easing.getString(getMotionEasingType())) .add("visibilityDuration", getVisibilityDuration()) diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java index f9111dffe2c4..8e1c872aec1f 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java @@ -155,23 +155,5 @@ public class CanvasLayout extends BoxLayout { public void serialize(MapSerializer serializer) { super.serialize(serializer); serializer.addType(getSerializedName()); - serializer.add("horizontalPositioning", mHorizontalPositioning); - } - - private String getPositioningString(int pos) { - switch (pos) { - case START: - return "START"; - case CENTER: - return "CENTER"; - case END: - return "END"; - case TOP: - return "TOP"; - case BOTTOM: - return "BOTTOM"; - default: - return "NONE"; - } } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java index 2595a71abaa5..d383ee9e4fc9 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java @@ -31,6 +31,7 @@ import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; import com.android.internal.widget.remotecompose.core.operations.Utils; import com.android.internal.widget.remotecompose.core.operations.layout.Component; +import com.android.internal.widget.remotecompose.core.operations.layout.measure.ComponentMeasure; import com.android.internal.widget.remotecompose.core.operations.layout.measure.MeasurePass; import com.android.internal.widget.remotecompose.core.operations.layout.measure.Size; import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle; @@ -73,6 +74,8 @@ public class TextLayout extends LayoutManager implements VariableSupport, Access private float mTextW = -1; private float mTextH = -1; + private final Size mCachedSize = new Size(0f, 0f); + @Nullable private String mCachedString = ""; Platform.ComputedTextLayout mComputedTextLayout; @@ -230,6 +233,7 @@ public class TextLayout extends LayoutManager implements VariableSupport, Access case TEXT_ALIGN_START: default: } + if (mTextW > (mWidth - mPaddingLeft - mPaddingRight)) { context.save(); context.clipRect( @@ -317,6 +321,21 @@ public class TextLayout extends LayoutManager implements VariableSupport, Access } @Override + public void computeSize( + @NonNull PaintContext context, + float minWidth, + float maxWidth, + float minHeight, + float maxHeight, + @NonNull MeasurePass measure) { + super.computeSize(context, minWidth, maxWidth, minHeight, maxHeight, measure); + computeWrapSize(context, maxWidth, maxHeight, true, true, measure, mCachedSize); + ComponentMeasure m = measure.get(this); + m.setW(mCachedSize.getWidth()); + m.setH(mCachedSize.getHeight()); + } + + @Override public void computeWrapSize( @NonNull PaintContext context, float maxWidth, @@ -335,6 +354,8 @@ public class TextLayout extends LayoutManager implements VariableSupport, Access if (mCachedString == null) { return; } + + boolean forceComplex = false; int flags = PaintContext.TEXT_MEASURE_FONT_HEIGHT | PaintContext.TEXT_MEASURE_SPACES; if (mMaxLines == 1 && (mOverflow == OVERFLOW_START_ELLIPSIS @@ -342,8 +363,20 @@ public class TextLayout extends LayoutManager implements VariableSupport, Access || mOverflow == OVERFLOW_ELLIPSIS)) { flags |= PaintContext.TEXT_COMPLEX; } - context.getTextBounds(mTextId, 0, mCachedString.length(), flags, bounds); - if (bounds[2] - bounds[1] > maxWidth && mMaxLines > 1 && maxWidth > 0f) { + if ((flags & PaintContext.TEXT_COMPLEX) != PaintContext.TEXT_COMPLEX) { + for (int i = 0; i < mCachedString.length(); i++) { + char c = mCachedString.charAt(i); + if ((c == '\n') || (c == '\t')) { + flags |= PaintContext.TEXT_COMPLEX; + forceComplex = true; + break; + } + } + } + if (!forceComplex) { + context.getTextBounds(mTextId, 0, mCachedString.length(), flags, bounds); + } + if (forceComplex || bounds[2] - bounds[1] > maxWidth && mMaxLines > 1 && maxWidth > 0f) { mComputedTextLayout = context.layoutComplexText( mTextId, diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java index 466e435e20cf..3e1f32de66e4 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java @@ -401,10 +401,8 @@ public class ScrollModifierOperation extends ListActionsOperation .add("direction", mDirection) .add("max", mMax) .add("notchMax", mNotchMax) - .add("scrollX", mScrollX) - .add("scrollY", mScrollY) - .add("maxScrollX", mMaxScrollX) - .add("maxScrollY", mMaxScrollY) + .add("scrollValue", isVerticalScroll() ? mScrollY : mScrollX) + .add("maxScrollValue", isVerticalScroll() ? mMaxScrollY : mMaxScrollX) .add("contentDimension", mContentDimension) .add("hostDimension", mHostDimension); } diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java index b5aedd8d0231..680a221cc2db 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java +++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java @@ -808,6 +808,24 @@ public class AndroidPaintContext extends PaintContext { } @Override + public void combinePath(int out, int path1, int path2, byte operation) { + Path p1 = getPath(path1, 0, 1); + Path p2 = getPath(path2, 0, 1); + Path.Op[] op = { + Path.Op.DIFFERENCE, + Path.Op.INTERSECT, + Path.Op.REVERSE_DIFFERENCE, + Path.Op.UNION, + Path.Op.XOR, + }; + Path p = new Path(p1); + p.op(p2, op[operation]); + + AndroidRemoteContext androidContext = (AndroidRemoteContext) mContext; + androidContext.mRemoteComposeState.putPath(out, p); + } + + @Override public void reset() { mPaint.reset(); } diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java index b31c76056e38..ad2414974780 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java +++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java @@ -392,6 +392,11 @@ public class AndroidRemoteContext extends RemoteContext { } @Override + public long getLong(int id) { + return ((LongConstant) mRemoteComposeState.getObject(id)).getValue(); + } + + @Override public int getColor(int id) { return mRemoteComposeState.getColor(id); } diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp index e874163943b6..a6a748c3deb7 100644 --- a/core/jni/android_view_InputChannel.cpp +++ b/core/jni/android_view_InputChannel.cpp @@ -55,41 +55,25 @@ public: inline std::shared_ptr<InputChannel> getInputChannel() { return mInputChannel; } - void setDisposeCallback(InputChannelObjDisposeCallback callback, void* data); void dispose(JNIEnv* env, jobject obj); private: std::shared_ptr<InputChannel> mInputChannel; - InputChannelObjDisposeCallback mDisposeCallback; - void* mDisposeData; }; // ---------------------------------------------------------------------------- NativeInputChannel::NativeInputChannel(std::unique_ptr<InputChannel> inputChannel) - : mInputChannel(std::move(inputChannel)), mDisposeCallback(nullptr) {} + : mInputChannel(std::move(inputChannel)) {} NativeInputChannel::~NativeInputChannel() { } -void NativeInputChannel::setDisposeCallback(InputChannelObjDisposeCallback callback, void* data) { - if (input_flags::remove_input_channel_from_windowstate()) { - return; - } - mDisposeCallback = callback; - mDisposeData = data; -} - void NativeInputChannel::dispose(JNIEnv* env, jobject obj) { if (!mInputChannel) { return; } - if (mDisposeCallback) { - mDisposeCallback(env, obj, mInputChannel, mDisposeData); - mDisposeCallback = nullptr; - mDisposeData = nullptr; - } mInputChannel.reset(); } @@ -108,17 +92,6 @@ std::shared_ptr<InputChannel> android_view_InputChannel_getInputChannel(JNIEnv* return nativeInputChannel != nullptr ? nativeInputChannel->getInputChannel() : nullptr; } -void android_view_InputChannel_setDisposeCallback(JNIEnv* env, jobject inputChannelObj, - InputChannelObjDisposeCallback callback, void* data) { - NativeInputChannel* nativeInputChannel = - android_view_InputChannel_getNativeInputChannel(env, inputChannelObj); - if (!nativeInputChannel || !nativeInputChannel->getInputChannel()) { - ALOGW("Cannot set dispose callback because input channel object has not been initialized."); - } else { - nativeInputChannel->setDisposeCallback(callback, data); - } -} - static jlong android_view_InputChannel_createInputChannel( JNIEnv* env, std::unique_ptr<InputChannel> inputChannel) { std::unique_ptr<NativeInputChannel> nativeInputChannel = diff --git a/core/res/res/layout/notification_2025_action_list.xml b/core/res/res/layout/notification_2025_action_list.xml new file mode 100644 index 000000000000..053aca068027 --- /dev/null +++ b/core/res/res/layout/notification_2025_action_list.xml @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2025 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 + --> + +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/actions_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" + android:layout_marginBottom="@dimen/notification_2025_action_list_margin_bottom" + > + + <LinearLayout + android:id="@+id/actions_container_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="end" + android:layout_gravity="bottom" + android:orientation="horizontal" + android:background="@color/notification_action_list_background_color" + > + + <com.android.internal.widget.NotificationActionListLayout + android:id="@+id/actions" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="wrap_content" + android:minHeight="@dimen/notification_2025_action_list_height" + android:orientation="horizontal" + android:gravity="center_vertical" + android:visibility="gone" + > + <!-- actions will be added here --> + </com.android.internal.widget.NotificationActionListLayout> + + <!-- + This nested linear layout exists to ensure that if the neither of the contained + actions is visible we have some minimum padding at the end of the actions is present, + then there will be 12dp of padding at the end of the actions list. + + The end padding exists to match the bottom margin of the actions, for symmetry when the icon + is shown in the corner of the notification. + --> + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:orientation="horizontal" + android:paddingEnd="@dimen/notification_2025_action_list_margin_bottom" + android:minWidth="@dimen/snooze_and_bubble_gone_padding_end" + > + <ImageView + android:id="@+id/snooze_button" + android:layout_width="@dimen/notification_2025_actions_icon_size" + android:layout_height="@dimen/notification_2025_actions_icon_size" + android:layout_gravity="center_vertical|end" + android:visibility="gone" + android:scaleType="centerInside" + /> + + <ImageView + android:id="@+id/bubble_button" + android:layout_width="@dimen/notification_2025_actions_icon_size" + android:layout_height="@dimen/notification_2025_actions_icon_size" + android:layout_gravity="center_vertical|end" + android:visibility="gone" + android:scaleType="centerInside" + /> + </LinearLayout> + </LinearLayout> +</FrameLayout> diff --git a/core/res/res/layout/notification_2025_template_collapsed_call.xml b/core/res/res/layout/notification_2025_template_collapsed_call.xml index fbea10d42b2b..4e0cf753722f 100644 --- a/core/res/res/layout/notification_2025_template_collapsed_call.xml +++ b/core/res/res/layout/notification_2025_template_collapsed_call.xml @@ -182,10 +182,10 @@ <include layout="@layout/notification_template_smart_reply_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/notification_content_margin" + android:layout_marginTop="@dimen/notification_2025_smart_reply_container_margin" android:layout_marginStart="@dimen/notification_2025_content_margin_start" android:layout_marginEnd="@dimen/notification_content_margin_end" /> - <include layout="@layout/notification_material_action_list" /> + <include layout="@layout/notification_2025_action_list" /> </LinearLayout> </LinearLayout> diff --git a/core/res/res/layout/notification_2025_template_collapsed_conversation.xml b/core/res/res/layout/notification_2025_template_collapsed_conversation.xml index a6fdcd95399e..5783201981a8 100644 --- a/core/res/res/layout/notification_2025_template_collapsed_conversation.xml +++ b/core/res/res/layout/notification_2025_template_collapsed_conversation.xml @@ -206,10 +206,10 @@ <include layout="@layout/notification_template_smart_reply_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/notification_content_margin" + android:layout_marginTop="@dimen/notification_2025_smart_reply_container_margin" android:layout_marginStart="@dimen/notification_2025_content_margin_start" android:layout_marginEnd="@dimen/notification_content_margin_end" /> - <include layout="@layout/notification_material_action_list" /> + <include layout="@layout/notification_2025_action_list" /> </LinearLayout> </LinearLayout> </com.android.internal.widget.ConversationLayout> diff --git a/core/res/res/layout/notification_2025_template_collapsed_messaging.xml b/core/res/res/layout/notification_2025_template_collapsed_messaging.xml index 3716fa6825b3..6391b1ebf744 100644 --- a/core/res/res/layout/notification_2025_template_collapsed_messaging.xml +++ b/core/res/res/layout/notification_2025_template_collapsed_messaging.xml @@ -216,10 +216,10 @@ <include layout="@layout/notification_template_smart_reply_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/notification_content_margin" + android:layout_marginTop="@dimen/notification_2025_smart_reply_container_margin" android:layout_marginStart="@dimen/notification_2025_content_margin_start" android:layout_marginEnd="@dimen/notification_content_margin_end" /> - <include layout="@layout/notification_material_action_list" /> + <include layout="@layout/notification_2025_action_list" /> </LinearLayout> </LinearLayout> </com.android.internal.widget.MessagingLayout> diff --git a/core/res/res/layout/notification_2025_template_compact_heads_up_messaging.xml b/core/res/res/layout/notification_2025_template_compact_heads_up_messaging.xml index cf9ff6bef6f8..be6404609f25 100644 --- a/core/res/res/layout/notification_2025_template_compact_heads_up_messaging.xml +++ b/core/res/res/layout/notification_2025_template_compact_heads_up_messaging.xml @@ -96,7 +96,7 @@ <FrameLayout android:id="@+id/reply_action_container" android:layout_width="wrap_content" - android:layout_height="@dimen/notification_action_list_height" + android:layout_height="@dimen/notification_2025_action_list_height" android:gravity="center_vertical" android:orientation="horizontal" /> <FrameLayout diff --git a/core/res/res/layout/notification_2025_template_expanded_base.xml b/core/res/res/layout/notification_2025_template_expanded_base.xml index 8d99e47c5386..76a85813b980 100644 --- a/core/res/res/layout/notification_2025_template_expanded_base.xml +++ b/core/res/res/layout/notification_2025_template_expanded_base.xml @@ -79,9 +79,9 @@ android:layout_height="wrap_content" android:layout_marginStart="@dimen/notification_2025_content_margin_start" android:layout_marginEnd="@dimen/notification_content_margin_end" - android:layout_marginTop="@dimen/notification_content_margin" + android:layout_marginTop="@dimen/notification_2025_smart_reply_container_margin" /> - <include layout="@layout/notification_material_action_list" /> + <include layout="@layout/notification_2025_action_list" /> </LinearLayout> </FrameLayout> diff --git a/core/res/res/layout/notification_2025_template_expanded_big_picture.xml b/core/res/res/layout/notification_2025_template_expanded_big_picture.xml index e8e460d1b4ae..999afa66c65b 100644 --- a/core/res/res/layout/notification_2025_template_expanded_big_picture.xml +++ b/core/res/res/layout/notification_2025_template_expanded_big_picture.xml @@ -86,9 +86,9 @@ android:layout_height="wrap_content" android:layout_marginStart="@dimen/notification_2025_content_margin_start" android:layout_marginEnd="@dimen/notification_content_margin_end" - android:layout_marginTop="@dimen/notification_content_margin" + android:layout_marginTop="@dimen/notification_2025_smart_reply_container_margin" /> - <include layout="@layout/notification_material_action_list" /> + <include layout="@layout/notification_2025_action_list" /> </LinearLayout> </FrameLayout> diff --git a/core/res/res/layout/notification_2025_template_expanded_big_text.xml b/core/res/res/layout/notification_2025_template_expanded_big_text.xml index b68db7f0a638..c9206eddbcde 100644 --- a/core/res/res/layout/notification_2025_template_expanded_big_text.xml +++ b/core/res/res/layout/notification_2025_template_expanded_big_text.xml @@ -85,10 +85,10 @@ android:layout_height="wrap_content" android:layout_marginStart="@dimen/notification_2025_content_margin_start" android:layout_marginEnd="@dimen/notification_content_margin_end" - android:layout_marginTop="@dimen/notification_content_margin" + android:layout_marginTop="@dimen/notification_2025_smart_reply_container_margin" /> - <include layout="@layout/notification_material_action_list" /> + <include layout="@layout/notification_2025_action_list" /> </com.android.internal.widget.RemeasuringLinearLayout> <include layout="@layout/notification_2025_right_icon" /> diff --git a/core/res/res/layout/notification_2025_template_expanded_call.xml b/core/res/res/layout/notification_2025_template_expanded_call.xml index 7b45b55ba15b..ec214554a30b 100644 --- a/core/res/res/layout/notification_2025_template_expanded_call.xml +++ b/core/res/res/layout/notification_2025_template_expanded_call.xml @@ -60,11 +60,11 @@ <include layout="@layout/notification_template_smart_reply_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/notification_content_margin" + android:layout_marginTop="@dimen/notification_2025_smart_reply_container_margin" android:layout_marginStart="@dimen/notification_2025_content_margin_start" android:layout_marginEnd="@dimen/notification_content_margin_end" /> - <include layout="@layout/notification_material_action_list" /> + <include layout="@layout/notification_2025_action_list" /> </com.android.internal.widget.RemeasuringLinearLayout> diff --git a/core/res/res/layout/notification_2025_template_expanded_conversation.xml b/core/res/res/layout/notification_2025_template_expanded_conversation.xml index 592785d53018..6ee82fa116ff 100644 --- a/core/res/res/layout/notification_2025_template_expanded_conversation.xml +++ b/core/res/res/layout/notification_2025_template_expanded_conversation.xml @@ -62,11 +62,11 @@ <include layout="@layout/notification_template_smart_reply_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/notification_content_margin" + android:layout_marginTop="@dimen/notification_2025_smart_reply_container_margin" android:layout_marginStart="@dimen/notification_2025_content_margin_start" android:layout_marginEnd="@dimen/notification_content_margin_end" /> - <include layout="@layout/notification_material_action_list" /> + <include layout="@layout/notification_2025_action_list" /> </com.android.internal.widget.RemeasuringLinearLayout> diff --git a/core/res/res/layout/notification_2025_template_expanded_inbox.xml b/core/res/res/layout/notification_2025_template_expanded_inbox.xml index 6459e1eab862..1eaef228aaca 100644 --- a/core/res/res/layout/notification_2025_template_expanded_inbox.xml +++ b/core/res/res/layout/notification_2025_template_expanded_inbox.xml @@ -127,8 +127,8 @@ android:layout_height="wrap_content" android:layout_marginStart="@dimen/notification_2025_content_margin_start" android:layout_marginEnd="@dimen/notification_content_margin_end" - android:layout_marginTop="@dimen/notification_content_margin" /> - <include layout="@layout/notification_material_action_list" /> + android:layout_marginTop="@dimen/notification_2025_smart_reply_container_margin" /> + <include layout="@layout/notification_2025_action_list" /> </LinearLayout> <include layout="@layout/notification_2025_right_icon" /> </FrameLayout> diff --git a/core/res/res/layout/notification_2025_template_expanded_messaging.xml b/core/res/res/layout/notification_2025_template_expanded_messaging.xml index 82c71527a291..62059af7f056 100644 --- a/core/res/res/layout/notification_2025_template_expanded_messaging.xml +++ b/core/res/res/layout/notification_2025_template_expanded_messaging.xml @@ -62,11 +62,11 @@ <include layout="@layout/notification_template_smart_reply_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/notification_content_margin" + android:layout_marginTop="@dimen/notification_2025_smart_reply_container_margin" android:layout_marginStart="@dimen/notification_2025_content_margin_start" android:layout_marginEnd="@dimen/notification_content_margin_end" /> - <include layout="@layout/notification_material_action_list" /> + <include layout="@layout/notification_2025_action_list" /> </com.android.internal.widget.RemeasuringLinearLayout> diff --git a/core/res/res/layout/notification_2025_template_expanded_progress.xml b/core/res/res/layout/notification_2025_template_expanded_progress.xml index 2ff252747fd2..cf39d8b08c4f 100644 --- a/core/res/res/layout/notification_2025_template_expanded_progress.xml +++ b/core/res/res/layout/notification_2025_template_expanded_progress.xml @@ -115,9 +115,9 @@ android:layout_height="wrap_content" android:layout_marginStart="@dimen/notification_2025_content_margin_start" android:layout_marginEnd="@dimen/notification_content_margin_end" - android:layout_marginTop="@dimen/notification_content_margin" + android:layout_marginTop="@dimen/notification_2025_smart_reply_container_margin" /> - <include layout="@layout/notification_material_action_list" /> + <include layout="@layout/notification_2025_action_list" /> </LinearLayout> </FrameLayout>
\ No newline at end of file diff --git a/core/res/res/layout/notification_2025_template_heads_up_base.xml b/core/res/res/layout/notification_2025_template_heads_up_base.xml index 084ec7daa683..4d3b2453637d 100644 --- a/core/res/res/layout/notification_2025_template_heads_up_base.xml +++ b/core/res/res/layout/notification_2025_template_heads_up_base.xml @@ -57,10 +57,10 @@ android:layout_height="wrap_content" android:layout_marginStart="@dimen/notification_2025_content_margin_start" android:layout_marginEnd="@dimen/notification_content_margin_end" - android:layout_marginTop="@dimen/notification_content_margin" + android:layout_marginTop="@dimen/notification_2025_smart_reply_container_margin" /> - <include layout="@layout/notification_material_action_list" /> + <include layout="@layout/notification_2025_action_list" /> </LinearLayout> </LinearLayout> </FrameLayout> diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 9967209c3f49..59ac5c68f9a5 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Rollees"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Onderbreek"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posisie"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in die BEPERK-groep geplaas"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"het \'n prent gestuur"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Werk 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Toets"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Gemeenskaplik"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Werkprofiel"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privaat ruimte"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Kloon"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index bdaf5a18a5ba..169e0208cf34 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"ሸብልል"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"ባለበት አቁም"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"አቀማመጥ"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ወደ የRESTRICTED ባልዲ ተከትቷል"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>፦"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"አንድ ምስል ልከዋል"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ሥራ 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"ሙከራ"</string> <string name="profile_label_communal" msgid="8743921499944800427">"የጋራ"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"የሥራ መገለጫ"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"የግል ቦታ"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"አባዛ"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 3b0e78dbada1..1d2bd776b505 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -2278,6 +2278,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"الانتقال للأسفل أو للأعلى"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"إيقاف مؤقت"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"تعديل الموضع"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"تم وضع <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> في الحزمة \"محظورة\"."</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"هذا المستخدم أرسل صورة"</string> @@ -2485,6 +2497,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ملف العمل 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"ملف شخصي تجريبي"</string> <string name="profile_label_communal" msgid="8743921499944800427">"ملف شخصي مشترك"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"ملف العمل"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"المساحة الخاصة"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"نسخة طبق الأصل"</string> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 5d93b655d741..606161c29f12 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"স্ক্ৰ’ল কৰক"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"পজ কৰক"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"স্থান"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ক সীমাবদ্ধ বাকেটটোত ৰখা হৈছে"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"এখন প্ৰতিচ্ছবি পঠিয়াইছে"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"কৰ্মস্থান ৩"</string> <string name="profile_label_test" msgid="9168641926186071947">"পৰীক্ষা"</string> <string name="profile_label_communal" msgid="8743921499944800427">"শ্বেয়াৰ কৰা"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"কৰ্মস্থানৰ প্ৰ’ফাইল"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"প্ৰাইভেট স্পে’চ"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ক্ল’ন"</string> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index c6a0adea6d6f..904194f122b8 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Sürüşdürün"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Durdurun"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Mövqe"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> MƏHDUDLAŞDIRILMIŞ səbətinə yerləşdirilib"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"şəkil göndərdi"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"İş 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Kommunal"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"İş profili"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Məxfi sahə"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 2b4dc578e610..e7fff52222f1 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -2275,6 +2275,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Skrolujte"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pauziraj"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozicija"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je dodat u segment OGRANIČENO"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"je poslao/la sliku"</string> @@ -2482,6 +2494,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Posao 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Zajedničko"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Poslovni profil"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privatan prostor"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klonirano"</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 8230b1c45757..94739b353de9 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -2276,6 +2276,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Гартанне"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Прыпыніць"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Пазіцыя"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" дададзены ў АБМЕЖАВАНУЮ групу"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"адпраўлены відарыс"</string> @@ -2483,6 +2495,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Працоўны 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Тэставы"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Супольны"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Працоўны профіль"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Прыватная прастора"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клон"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 1b0477f09538..2bd7d1d8ac60 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -1965,8 +1965,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Запитване за фигура за отключване преди освобождаване"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Запитване за парола преди освобождаване"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"Инсталирано от администратора ви.\nОтворете настройките, за да прегледате предоставените разрешения"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"Актуализирано от администратора ви.\nОтворете настройките, за да прегледате предоставените разрешения"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Изтрито от администратора ви"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Режимът за запазване на батерията включва тъмната тема и ограничава или изключва активността на заден план, някои визуални ефекти, определени функции и някои връзки с мрежата."</string> @@ -2274,6 +2273,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Превъртане"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Пауза"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Позиция"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакетът <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е поставен в ОГРАНИЧЕНИЯ контейнер"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"изпратено изображение"</string> @@ -2481,6 +2492,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Служебни 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Тестване"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Общи"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Служебен потребителски профил"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Частно пространство"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клониране"</string> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index 2461a70e1ab8..16a7e9aad04a 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"স্ক্রল করুন"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"পজ করুন"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"পজিশন"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> সীমাবদ্ধ গ্রুপে অন্তর্ভুক্ত করা হয়েছে"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"একটি ছবি পাঠানো হয়েছে"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"৩য় অফিস"</string> <string name="profile_label_test" msgid="9168641926186071947">"পরীক্ষা"</string> <string name="profile_label_communal" msgid="8743921499944800427">"কমিউনাল"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"অফিস প্রোফাইল"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"প্রাইভেট স্পেস"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ক্লোন"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index b8d3283491c3..e5a78a34d5d6 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -2275,6 +2275,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Klizanje"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pauziraj"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Položaj"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je stavljen u odjeljak OGRANIČENO"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"je poslao/la sliku"</string> @@ -2482,6 +2494,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"3. poslovno"</string> <string name="profile_label_test" msgid="9168641926186071947">"Testno"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Opće"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Radni profil"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privatni prostor"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index cbfa521c96e4..b70bb3337b7c 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -2275,6 +2275,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Desplaça"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Posa en pausa"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posició"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> s\'ha transferit al segment RESTRINGIT"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ha enviat una imatge"</string> @@ -2482,6 +2494,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Treball 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Prova"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Compartit"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Perfil de treball"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espai privat"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clon"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 356cdc71b54a..c4e69ab37ef7 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -2276,6 +2276,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Posunutí"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pozastavit"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozice"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balíček <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> byl vložen do sekce OMEZENO"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"posílá obrázek"</string> @@ -2483,6 +2495,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Práce 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Komunální"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Pracovní profil"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Soukromý prostor"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index efe3e103d0e1..c0447239859d 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Rul"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Sæt på pause"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Placering"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blevet placeret i samlingen BEGRÆNSET"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sendte et billede"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Arbejde 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Fælles"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Arbejdsprofil"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privat område"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index fc0e9ed19b9d..0d371cceba6b 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Scrollen"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausieren"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> wurde in den BESCHRÄNKT-Bucket gelegt"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"hat ein Bild gesendet"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Geschäftlich 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Gemeinsam genutzt"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Arbeitsprofil"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Vertrauliches Profil"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 58f5d9db4d68..55d28c500b2d 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Κύλιση"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Παύση"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Θέση"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Το πακέτο <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> τοποθετήθηκε στον κάδο ΠΕΡΙΟΡΙΣΜΕΝΗΣ ΠΡΟΣΒΑΣΗΣ."</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"έστειλε μια εικόνα"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Εργασία 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Δοκιμή"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Κοινόχρηστο"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Προφίλ εργασίας"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Ιδιωτικός χώρος"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Κλώνος"</string> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 320e63935fc9..b94840430e60 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -1965,8 +1965,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Ask for unlock pattern before unpinning"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Ask for password before unpinning"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"Installed by your admin.\nGo to Settings to view granted permissions"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"Updated by your admin.\nGo to settings to view granted permissions"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects, certain features and some network connections."</string> @@ -2274,6 +2273,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Scroll"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pause"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sent an image"</string> @@ -2481,6 +2492,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Work 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Communal"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Work profile"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Private space"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 85471d8a5efb..30843adab245 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -2273,6 +2273,12 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Scroll"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pause"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string> + <string name="accessibility_autoclick_scroll_up" msgid="2044948780797117443">"Scroll Up"</string> + <string name="accessibility_autoclick_scroll_down" msgid="3733401063292018116">"Scroll Down"</string> + <string name="accessibility_autoclick_scroll_left" msgid="8564421367992824198">"Scroll Left"</string> + <string name="accessibility_autoclick_scroll_right" msgid="8932417330753984265">"Scroll Right"</string> + <string name="accessibility_autoclick_scroll_exit" msgid="3788610039146769696">"Exit Scroll Mode"</string> + <string name="accessibility_autoclick_scroll_panel_title" msgid="7120598166296447036">"Scroll Panel"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sent an image"</string> @@ -2480,6 +2486,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Work 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Communal"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Work profile"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Private space"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 730dd3b808e8..bcfc861932fb 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -1965,8 +1965,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Ask for unlock pattern before unpinning"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Ask for password before unpinning"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"Installed by your admin.\nGo to Settings to view granted permissions"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"Updated by your admin.\nGo to settings to view granted permissions"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects, certain features and some network connections."</string> @@ -2274,6 +2273,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Scroll"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pause"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sent an image"</string> @@ -2481,6 +2492,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Work 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Communal"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Work profile"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Private space"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index a9654e525df4..15ea9bf0007c 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -1965,8 +1965,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Ask for unlock pattern before unpinning"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Ask for password before unpinning"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"Installed by your admin.\nGo to Settings to view granted permissions"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"Updated by your admin.\nGo to settings to view granted permissions"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects, certain features and some network connections."</string> @@ -2274,6 +2273,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Scroll"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pause"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sent an image"</string> @@ -2481,6 +2492,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Work 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Communal"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Work profile"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Private space"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 036ecfc59d87..1e10140e2bf1 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -1966,8 +1966,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Solicitar desbloqueo para quitar fijación"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Solicitar contraseña para quitar fijación"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"Tu administrador realizó la instalación.\nVe a la configuración para ver los permisos otorgados"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"Tu administrador realizó la actualización.\nVe a la configuración para ver los permisos otorgados"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Tu administrador borró este paquete"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"El Ahorro de batería activa el Tema oscuro y desactiva o restringe la actividad en segundo plano, algunos efectos visuales, algunas conexiones de red y otras funciones determinadas."</string> @@ -2275,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Desplazamiento"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausar"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posición"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Se colocó <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> en el bucket RESTRICTED"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"envió una imagen"</string> @@ -2482,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Trabajo 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Probar"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Compartido"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Perfil de trabajo"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espacio privado"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clon"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 3553aea44c2d..189a027350bb 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -2275,6 +2275,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Desplazarse"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausar"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posición"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> se ha incluido en el grupo de restringidos"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ha enviado una imagen"</string> @@ -2482,6 +2494,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Trabajo 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Prueba"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Común"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Perfil de trabajo"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espacio privado"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clon"</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index abecc1a76d3f..893bc4e755fa 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Keri"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Peata"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Asukoht"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on lisatud salve PIIRANGUTEGA"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"saatis kujutise"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Töö 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Jagatud"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Tööprofiil"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privaatne ruum"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Kloon"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 64dc7303e8c1..fb60c8dc6e8d 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Egin gora eta behera"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausatu"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Ezarri posizioan"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Murriztuen edukiontzian ezarri da <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"erabiltzaileak irudi bat bidali du"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Lanekoa 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Probakoa"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Partekatua"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Laneko profila"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Eremu pribatua"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klona"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 13083d0c04d4..24db15aa7b26 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -1965,8 +1965,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"درخواست الگوی بازگشایی قفل قبلاز برداشتن سنجاق"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"درخواست گذرواژه قبل از برداشتن سنجاق"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"سرپرست شما آن را نصب کرده است.\nبرای مشاهده اجازههای اعطاشده به تنظیمات بروید"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"سرپرستتان آن را بهروز کرده است.\nبرای مشاهده اجازههای اعطاشده به تنظیمات بروید"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"توسط سرپرست سیستم حذف شد"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"تأیید"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"«بهینهسازی باتری» «زمینه تاریک» را روشن میکند و فعالیت پسزمینه، برخی از جلوههای بصری، ویژگیهایی خاص، و برخی از اتصالهای شبکه را محدود یا خاموش میکند."</string> @@ -2274,6 +2273,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"پیمایش"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"توقف موقت"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"موقعیت"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> در سطل «محدودشده» قرار گرفت"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"تصویری ارسال کرد"</string> @@ -2481,6 +2492,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"کار ۳"</string> <string name="profile_label_test" msgid="9168641926186071947">"آزمایش"</string> <string name="profile_label_communal" msgid="8743921499944800427">"عمومی"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"نمایه کاری"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"فضای خصوصی"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"همسانهسازی"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 145c5ee4bef1..cb16427bd351 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Vieritä"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Keskeytä"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Sijainti"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on nyt rajoitettujen ryhmässä"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"lähetti kuvan"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Työ 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Testi"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Jaettu"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Työprofiili"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Yksityinen tila"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klooni"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 0ee4112ed458..c2b368e7c02c 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -1966,8 +1966,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Demander le schéma de déverrouillage avant d\'annuler l\'épinglage"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Demander le mot de passe avant d\'annuler l\'épinglage"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"Installé par votre administrateur.\nAccédez aux paramètres pour consulter les autorisations accordées"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"Installé par votre administrateur.\nAccédez aux paramètres pour consulter les autorisations accordées"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Supprimé par votre administrateur"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Le mode Économiseur de pile active le thème sombre et limite ou désactive l\'activité en arrière-plan, certains effets visuels, certaines fonctionnalités et certaines connexions réseau."</string> @@ -2275,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Faire défiler"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pause"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le compartiment RESTREINT"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g> :"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"a envoyé une image"</string> @@ -2482,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Professionnel 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Commun"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Profil professionnel"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espace privé"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index a5b6f9a92dce..1cf540905515 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -2275,6 +2275,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Faire défiler"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pause"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le bucket RESTRICTED"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g> :"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"a envoyé une image"</string> @@ -2482,6 +2494,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Professionnel 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Commun"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Profil professionnel"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espace privé"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 332387ad0131..ecd2d4b197d2 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Desprazar"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausa"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posición"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> incluíuse no grupo RESTRINXIDO"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"enviouse unha imaxe"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Traballo 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Proba"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Compartido"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Perfil de traballo"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espazo privado"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clonado"</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 7a39d634508e..b4095ef8dbd3 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -2275,6 +2275,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"સ્ક્રોલ કરો"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"થોભાવો"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"સ્થિતિ"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ને પ્રતિબંધિત સમૂહમાં મૂકવામાં આવ્યું છે"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"છબી મોકલી"</string> @@ -2482,6 +2494,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ઑફિસ 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"પરીક્ષણ કરો"</string> <string name="profile_label_communal" msgid="8743921499944800427">"કૉમ્યુનલ"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"ઑફિસની પ્રોફાઇલ"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"ખાનગી સ્પેસ"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ક્લોન"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 2c43996064ea..f93b8a2ec269 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"स्क्रोल करें"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"रोकें"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"पोज़िशन"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> को प्रतिबंधित बकेट में रखा गया है"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"एक इमेज भेजी गई"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ऑफ़िस 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"टेस्ट"</string> <string name="profile_label_communal" msgid="8743921499944800427">"कम्यूनिटी"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"वर्क प्रोफ़ाइल"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"प्राइवेट स्पेस"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"क्लोन"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index d870a1dbda61..336e37956783 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -2275,6 +2275,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Pomakni se"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pauziraj"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozicija"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> premješten je u spremnik OGRANIČENO"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"šalje sliku"</string> @@ -2482,6 +2494,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Posao 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Zajedničko"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Radni profil"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privatni prostor"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 350d51dee68c..1519326cdb6b 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -1965,8 +1965,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Feloldási minta kérése a kitűzés feloldásához"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Jelszó kérése a rögzítés feloldásához"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"A rendszergazda által telepítve.\nLépjen a beállításokhoz a megadott engedélyek megtekintéséhez."</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"A rendszergazda által frissítve.\nLépjen a beállításokhoz a megadott engedélyek megtekintéséhez."</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"A rendszergazda által törölve"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Az Akkumulátorkímélő mód bekapcsolja a Sötét témát, és korlátozza vagy kikapcsolja a háttérbeli tevékenységeket, valamint bizonyos vizuális effekteket, funkciókat és hálózati kapcsolatokat."</string> @@ -2274,6 +2273,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Görgetés"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Szüneteltetés"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozíció"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"A következő csomag a KORLÁTOZOTT csoportba került: <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"képet küldött"</string> @@ -2481,6 +2492,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"3. munkahelyi"</string> <string name="profile_label_test" msgid="9168641926186071947">"Teszt"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Közös"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Munkaprofil"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privát terület"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klón"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 655af9395fa3..af9ee628e4b1 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -1965,8 +1965,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Հարցնել ապակողպող նախշը"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Հարցնել գաղտնաբառը"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"Տեղադրվել է ադմինիստրատորի կողմից։\nԱնցեք կարգավորումներ՝ տրամադրված թույլտվությունները դիտելու համար"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"Թարմացվել է ձեր ադմինիստրատորի կողմից։\nԱնցեք կարգավորումներ՝ տրամադրված թույլտվությունները դիտելու համար"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Ջնջվել է ձեր ադմինիստրատորի կողմից"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Եղավ"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"«Մարտկոցի տնտեսում» գործառույթը միացնում է մուգ թեման և անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ, ցանցային միացումներ և այլ գործառույթներ։"</string> @@ -2274,6 +2273,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Ոլորել"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Դադարեցնել"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Դիրքը"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> փաթեթը գցվեց ՍԱՀՄԱՆԱՓԱԿՎԱԾ զամբյուղի մեջ"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>՝"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"օգտատերը պատկեր է ուղարկել"</string> @@ -2481,6 +2492,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Աշխատանքային 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Փորձնական"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Ընդհանուր"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Աշխատանքային պրոֆիլ"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Մասնավոր տարածք"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Կլոն"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 305d23a15c00..90b1ddfcc2cb 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Scroll"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Jeda"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posisi"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah dimasukkan ke dalam bucket DIBATASI"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"mengirim gambar"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Kerja 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Pengujian"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Umum"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Profil kerja"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Ruang privasi"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index cdf89ad4424d..772be761426d 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -1965,8 +1965,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Biðja um opnunarmynstur til að losa"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Biðja um aðgangsorð til að losa"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"Sett upp af stjórnanda.\nFarðu í stillingar til að sjá heimildir"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"Uppfært af stjórnanda.\nFarðu í stillingarnar þínar til að sjá þær heimildir sem hafa verið veittar"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Kerfisstjóri eyddi"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Í lagi"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Rafhlöðusparnaður kveikir á dökku þema og takmarkar eða slekkur á bakgrunnsvirkni, sumum myndáhrifum, tilteknum eiginleikum og sumum nettengingum."</string> @@ -2274,6 +2273,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Fletta"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Hlé"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Staðsetning"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> var sett í flokkinn TAKMARKAÐ"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sendi mynd"</string> @@ -2481,6 +2492,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Vinna 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Prófun"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Sameiginlegt"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Vinnusnið"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Leynirými"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Afrit"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 3b7d1ec750ee..dd10d1d3688d 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -1966,8 +1966,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Richiedi sequenza di sblocco prima di sbloccare"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Richiedi password prima di sbloccare"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"Installato dall\'amministratore.\nVai alle impostazioni per visualizzare le autorizzazioni concesse"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"Aggiornato dall\'amministratore.\nVai alle impostazioni per visualizzare le autorizzazioni concesse"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminato dall\'amministratore"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Ok"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Il risparmio energetico attiva il tema scuro e limita o disattiva l\'attività in background, nonché alcuni effetti visivi, funzionalità e connessioni di rete."</string> @@ -2275,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Scorri"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Metti in pausa"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posizione"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> è stato inserito nel bucket RESTRICTED"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ha inviato un\'immagine"</string> @@ -2482,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Lavoro 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Condiviso"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Profilo di lavoro"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Spazio privato"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index cf7374868a50..1055612ff636 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -1804,8 +1804,7 @@ <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> - <!-- no translation found for autoclick_feature_name (8149248738736949630) --> - <skip /> + <string name="autoclick_feature_name" msgid="8149248738736949630">"קליק אוטומטי"</string> <string name="hearing_device_status_disconnected" msgid="497547752953543832">"מנותק"</string> <string name="hearing_device_status_connected" msgid="2149385149669918764">"מחובר"</string> <string name="hearing_device_status_active" msgid="4770378695482566032">"מצב פעיל"</string> @@ -2276,6 +2275,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"גלילה"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"השהיה"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"מיקום"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> התווספה לקטגוריה \'מוגבל\'"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"נשלחה תמונה"</string> @@ -2483,6 +2494,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"פרופיל עבודה 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"בדיקה"</string> <string name="profile_label_communal" msgid="8743921499944800427">"שיתופי"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"פרופיל העבודה"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"המרחב הפרטי"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"שכפול"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index f8bc2413fca0..ea101ec8ee84 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -1965,8 +1965,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"画面固定を解除する前にロック解除パターンの入力を求める"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"オフライン再生を解除する前にパスワードの入力を求める"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"管理者によりインストールされています。\n付与された権限を確認するには、設定に移動してください"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"管理者により更新されています。\n付与された権限を確認するには、設定に移動してください"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"管理者により削除されています"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"バッテリー セーバーを ON にすると、ダークモードが ON になります。また、バックグラウンド アクティビティ、一部の視覚効果、特定の機能、一部のネットワーク接続が制限されるか OFF になります。"</string> @@ -2274,6 +2273,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"スクロール"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"一時停止"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"位置"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> は RESTRICTED バケットに移動しました。"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"画像を送信しました"</string> @@ -2481,6 +2492,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"仕事用 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"テスト"</string> <string name="profile_label_communal" msgid="8743921499944800427">"共用"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"仕事用プロファイル"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"プライベート スペース"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"複製"</string> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 8aa0af3efc44..055c41201ced 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -1965,8 +1965,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ფიქსაციის მოხსნამდე განბლოკვის ნიმუშის მოთხოვნა"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ფიქსაციის მოხსნამდე პაროლის მოთხოვნა"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"დაინსტალირებულია თქვენი ადმინისტრატორის მიერ.\nდაშვებული ნებართვების სანახავად გადადით პარამეტრებზე"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"განახლებულია თქვენი ადმინისტრატორის მიერ.\nდაშვებული ნებართვების სანახავად გადადით პარამეტრებზე"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"წაიშალა თქვენი ადმინისტრატორის მიერ"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"კარგი"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ბატარეის დამზოგი ჩართავს მუქ თემას და შეზღუდავს ან გამორთავს ფონურ აქტივობას, ზოგიერთ ვიზუალურ ეფექტს, გარკვეულ ფუნქციებსა და ზოგიერთ ქსელთან კავშირს."</string> @@ -2274,6 +2273,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"გადაადგილება"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"პაუზა"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"პოზიცია"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> მოთავსდა კალათაში „შეზღუდული“"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"გაიგზავნა სურათი"</string> @@ -2481,6 +2492,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"სამსახური 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"სატესტო"</string> <string name="profile_label_communal" msgid="8743921499944800427">"საერთო"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"სამსახურის პროფილი"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"კერძო სივრცე"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"კლონის შექმნა"</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 3908427d9f97..176645fb1a9a 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Айналдыру"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Кідірту"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Орналастыру"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ШЕКТЕЛГЕН себетке салынды."</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"сурет жіберілді"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Жұмыс 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Сынақ"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Жалпы"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Жұмыс профилі"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Құпия кеңістік"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клон"</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index dee23f65e8ca..63b05e670513 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"រំកិល"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"ផ្អាក"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"ទីតាំង"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ត្រូវបានដាក់ទៅក្នុងធុងដែលបានដាក់កំហិត"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>៖"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"បានផ្ញើរូបភាព"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ការងារទី 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"ការធ្វើតេស្ត"</string> <string name="profile_label_communal" msgid="8743921499944800427">"ទូទៅ"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"កម្រងព័ត៌មានការងារ"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"លំហឯកជន"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ក្លូន"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index c1a70b0f7276..f56f2c8571cb 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -1965,8 +1965,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ಅನ್ಪಿನ್ ಮಾಡಲು ಅನ್ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಕೇಳಿ"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ಅನ್ಪಿನ್ ಮಾಡಲು ಪಾಸ್ವರ್ಡ್ ಕೇಳು"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿದ್ದಾರೆ.\nನೀಡಲಾದ ಅನುಮತಿಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಹೋಗಿ"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಅಪ್ಡೇಟ್ ಮಾಡಿದ್ದಾರೆ.\nನೀಡಲಾದ ಅನುಮತಿಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಹೋಗಿ"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಅಳಿಸಿದ್ದಾರೆ"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ಸರಿ"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ಬ್ಯಾಟರಿ ಸೇವರ್, ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ವಿಷುವಲ್ ಎಫೆಕ್ಟ್ಗಳು, ಕೆಲವು ಫೀಚರ್ಗಳು ಮತ್ತು ಇತರ ನೆಟ್ವರ್ಕ್ ಸಂಪರ್ಕಗಳನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ ಅಥವಾ ಆಫ್ ಮಾಡುತ್ತದೆ."</string> @@ -2274,6 +2273,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"ಸ್ಕ್ರಾಲ್ ಮಾಡಿ"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"ವಿರಾಮಗೊಳಿಸಿ"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"ಸ್ಥಾನ"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ಅನ್ನು ನಿರ್ಬಂಧಿತ ಬಕೆಟ್ಗೆ ಹಾಕಲಾಗಿದೆ"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ಚಿತ್ರವನ್ನು ಕಳುಹಿಸಲಾಗಿದೆ"</string> @@ -2481,6 +2492,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ಕೆಲಸ 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"ಪರೀಕ್ಷೆ"</string> <string name="profile_label_communal" msgid="8743921499944800427">"ಸಮುದಾಯ"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"ಪ್ರೈವೆಟ್ ಸ್ಪೇಸ್"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ಕ್ಲೋನ್"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index be4a28423a93..253d162427fa 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"스크롤"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"일시중지"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"위치"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 항목이 RESTRICTED 버킷으로 이동함"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"이미지 보냄"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"직장 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"테스트"</string> <string name="profile_label_communal" msgid="8743921499944800427">"공동"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"직장 프로필"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"비공개 스페이스"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"클론"</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 121908a416a4..96f01ffcb93a 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -1965,8 +1965,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Бошотуудан мурун графикалык ачкыч суралсын"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Бошотуудан мурун сырсөз суралсын"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"Администраторуңуз орнотту.\nБерилген уруксаттарды көрүү үчүн параметрлерге өтүңүз"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"Администраторуңуз орнотту.\nБерилген уруксаттарды көрүү үчүн параметрлерге өтүңүз"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Администраторуңуз жок кылып салган"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ЖАРАЙТ"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Батареяны үнөмдөөчү режимде Караңгы тема күйгүзүлүп, фондогу аракеттер, айрым визуалдык эффекттер, белгилүү бир функциялар жана айрым тармакка туташуулар чектелип же өчүрүлөт."</string> @@ -2274,6 +2273,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Сыдыруу"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Тындыруу"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Орду"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ЧЕКТЕЛГЕН чакага коюлган"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"сүрөт жөнөттү"</string> @@ -2481,6 +2492,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Жумуш 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Сыноо"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Жалпы"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Жумуш профили"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Жеке мейкиндик"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клон"</string> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index ad62671d5e5b..4905a53b06f6 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"ເລື່ອນ"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"ຢຸດຊົ່ວຄາວ"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"ຕຳແໜ່ງ"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ຖືກວາງໄວ້ໃນກະຕ່າ \"ຈຳກັດ\" ແລ້ວ"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ສົ່ງຮູບແລ້ວ"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ວຽກ 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"ທົດສອບ"</string> <string name="profile_label_communal" msgid="8743921499944800427">"ສ່ວນກາງ"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"ພື້ນທີ່ສ່ວນບຸກຄົນ"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ໂຄລນ"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 27a08c25a84e..07a6c6e663d2 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -1967,8 +1967,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Prašyti atrakinimo piešinio prieš atsegant"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Prašyti slaptažodžio prieš atsegant"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"Įdiegė administratorius.\nEikite į nustatymus ir peržiūrėkite suteiktus leidimus"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"Atnaujino administratorius.\nEikite į nustatymus ir peržiūrėkite suteiktus leidimus"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Ištrynė administratorius"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Gerai"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Akumuliatoriaus tausojimo priemonė įjungia tamsiąją temą ir apriboja arba išjungia veiklą fone, kai kuriuos vaizdinius efektus, tam tikras funkcijas bei kai kuriuos tinklo ryšius."</string> @@ -2276,6 +2275,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Slinkti"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pristabdyti"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozicija"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"„<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>“ įkeltas į grupę APRIBOTA"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"išsiuntė vaizdą"</string> @@ -2483,6 +2494,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Darbas (3)"</string> <string name="profile_label_test" msgid="9168641926186071947">"Bandymas"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Bendruomenės"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Darbo profilis"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privati erdvė"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klonuoti"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 78c7ebdb4587..60a99b3fd338 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -2275,6 +2275,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Ritināt"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pārtraukt"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozīcija"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Pakotne “<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>” ir ievietota ierobežotā kopā."</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"nosūtīts attēls"</string> @@ -2482,6 +2494,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Darbam (3.)"</string> <string name="profile_label_test" msgid="9168641926186071947">"Testēšanai"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Kopīgs"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Darba profils"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privātā telpa"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klons"</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 146de01e7951..6d98869e7b60 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Лизгање"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Паузирај"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Позиционирај"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е ставен во корпата ОГРАНИЧЕНИ"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"испрати слика"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Работен профил 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Профил за тестирање"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Профил на заедницата"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Работен профил"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Приватен простор"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клониран профил"</string> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 3bb425ec9351..fca58a113c7b 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -1965,8 +1965,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"അൺപിന്നിനുമുമ്പ് അൺലോക്ക് പാറ്റേൺ ആവശ്യപ്പെടൂ"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"അൺപിന്നിനുമുമ്പ് പാസ്വേഡ് ആവശ്യപ്പെടൂ"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"നിങ്ങളുടെ അഡ്മിൻ ഇൻസ്റ്റാൾ ചെയ്തത്.\nനൽകിയ അനുമതികൾ കാണാൻ ക്രമീകരണത്തിലേക്ക് പോകുക"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"നിങ്ങളുടെ അഡ്മിൻ അപ്ഡേറ്റ് ചെയ്തത്.\nനൽകിയ അനുമതികൾ കാണാൻ ക്രമീകരണത്തിലേക്ക് പോകുക"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"നിങ്ങളുടെ അഡ്മിൻ ഇല്ലാതാക്കുന്നത്"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ശരി"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"\'ബാറ്ററി സേവർ\' ഡാർക്ക് തീം ഓണാക്കുന്നു, ഒപ്പം പശ്ചാത്തല ആക്റ്റിവിറ്റിയും ചില വിഷ്വൽ ഇഫക്റ്റുകളും ചില ഫീച്ചറുകളും ചില നെറ്റ്വർക്ക് കണക്ഷനുകളും പരിമിതപ്പെടുത്തുകയോ ഓഫാക്കുകയോ ചെയ്യുന്നു."</string> @@ -2274,6 +2273,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"സ്ക്രോൾ ചെയ്യുക"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"താൽക്കാലികമായി നിർത്തുക"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"സ്ഥാനം"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> നിയന്ത്രിത ബക്കറ്റിലേക്ക് നീക്കി"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ചിത്രം അയച്ചു"</string> @@ -2481,6 +2492,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ഔദ്യോഗികം 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"ടെസ്റ്റ്"</string> <string name="profile_label_communal" msgid="8743921499944800427">"കമ്മ്യൂണൽ"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"സ്വകാര്യ സ്പേസ്"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ക്ലോൺ ചെയ്യുക"</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 1ad9685a23d1..58f4cf7b83cb 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Гүйлгэх"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Түр зогсоох"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Байрлал"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>-г ХЯЗГААРЛАСАН сагс руу орууллаа"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"зураг илгээсэн"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Ажил 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Туршилт"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Нийтийн"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Ажлын профайл"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Хаалттай орон зай"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клон"</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 82f217ff21b2..c37884d4473c 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"स्क्रोल करा"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"थांबवा"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"स्थिती"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> हे प्रतिबंधित बादलीमध्ये ठेवण्यात आले आहे"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"इमेज पाठवली आहे"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ऑफिस ३"</string> <string name="profile_label_test" msgid="9168641926186071947">"चाचणी"</string> <string name="profile_label_communal" msgid="8743921499944800427">"सामुदायिक"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"कार्य प्रोफाइल"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"खाजगी स्पेस"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"क्लोन"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index bda439a187a2..d675246df729 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Tatal"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Jeda"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Kedudukan"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah diletakkan dalam baldi TERHAD"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"menghantar imej"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Kerja 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Ujian"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Umum"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Profil kerja"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Ruang persendirian"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 9a8041644d5f..1a5bc7af86ca 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"လှိမ့်ရန်"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"ခဏရပ်ရန်"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"နေရာ"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ကို တားမြစ်ထားသော သိမ်းဆည်းမှုအတွင်းသို့ ထည့်ပြီးပါပြီ"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>-"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ပုံပို့ထားသည်"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"အလုပ် ၃"</string> <string name="profile_label_test" msgid="9168641926186071947">"စမ်းသပ်မှု"</string> <string name="profile_label_communal" msgid="8743921499944800427">"အများသုံး"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"အလုပ်ပရိုဖိုင်"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"သီးသန့်နေရာ"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ပုံတူပွားရန်"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index d8e785f742d5..4b44dd6c67ce 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Rull"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Sett på pause"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Plassér"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blitt plassert i TILGANGSBEGRENSET-toppmappen"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"har sendt et bilde"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Jobb 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Felles"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Jobbprofil"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privat område"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 88e93709453e..16e48d547a55 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"स्क्रोल गर्नुहोस्"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"पज गर्नुहोस्"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"स्थिति"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> लाई प्रतिबन्धित बाल्टीमा राखियो"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"फोटो पठाइयो"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"कार्य प्रोफाइल ३"</string> <string name="profile_label_test" msgid="9168641926186071947">"परीक्षण"</string> <string name="profile_label_communal" msgid="8743921499944800427">"सामुदायिक"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"कार्य प्रोफाइल"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"निजी स्पेस"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"क्लोन"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index a43c0c443c8c..11c40fdbfce4 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Scrollen"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pauzeren"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Positie"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in de bucket RESTRICTED geplaatst"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"heeft een afbeelding gestuurd"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Werk 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Gemeenschappelijk"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Werkprofiel"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privégedeelte"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Kloon"</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index f61e10919209..eca778a24c8a 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"ସ୍କ୍ରୋଲ କରନ୍ତୁ"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"ବିରତ କରନ୍ତୁ"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"ସ୍ଥିତି"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>କୁ ପ୍ରତିବନ୍ଧିତ ବକେଟରେ ରଖାଯାଇଛି"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ଏକ ଛବି ପଠାଯାଇଛି"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ୱାର୍କ 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"ଟେଷ୍ଟ"</string> <string name="profile_label_communal" msgid="8743921499944800427">"କମ୍ୟୁନାଲ"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"ୱାର୍କ ପ୍ରୋଫାଇଲ"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"ପ୍ରାଇଭେଟ ସ୍ପେସ"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"କ୍ଲୋନ"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 5d2cc7be3039..2da2a608bf97 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"ਸਕ੍ਰੋਲ ਕਰੋ"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"ਰੋਕੋ"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"ਸਥਿਤੀ"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ਨੂੰ ਪ੍ਰਤਿਬੰਧਿਤ ਖਾਨੇ ਵਿੱਚ ਪਾਇਆ ਗਿਆ ਹੈ"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ਚਿੱਤਰ ਭੇਜਿਆ ਗਿਆ"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ਕੰਮ ਸੰਬੰਧੀ 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"ਜਾਂਚ"</string> <string name="profile_label_communal" msgid="8743921499944800427">"ਭਾਈਚਾਰਕ"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ਕਲੋਨ"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index bb7edb8a79ad..730429da67d2 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -2276,6 +2276,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Przewijanie"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Wstrzymaj"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozycja"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Umieszczono pakiet <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> w zasobniku danych RESTRICTED"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"wysłano obraz"</string> @@ -2483,6 +2495,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Służbowy 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Testowy"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Wspólny"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Profil służbowy"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Przestrzeń prywatna"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 0440e39a9dd5..cea3b73b2070 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -2275,6 +2275,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Rolar"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausar"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posição"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"enviou uma imagem"</string> @@ -2482,6 +2494,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Trabalho 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Teste"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Público"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Perfil de trabalho"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espaço privado"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 745e17be6c28..2951d482a490 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -1966,8 +1966,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pedir padrão de desbloqueio antes de soltar"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pedir palavra-passe antes de soltar"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalado pelo seu administrador.\nAceda às definições para ver as autorizações concedidas"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"Atualizado pelo seu administrador.\nAceda às definições para ver as autorizações concedidas"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado pelo seu gestor"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"A Poupança de bateria ativa o tema escuro e limita ou desativa a atividade em segundo plano, alguns efeitos visuais, determinadas funcionalidades e algumas ligações de rede."</string> @@ -2275,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Deslocar"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausar"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posição"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no contentor RESTRITO."</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"enviou uma imagem"</string> @@ -2482,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Trabalho 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Teste"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Comum"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Perfil de trabalho"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espaço privado"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 0440e39a9dd5..cea3b73b2070 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -2275,6 +2275,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Rolar"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausar"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posição"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"enviou uma imagem"</string> @@ -2482,6 +2494,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Trabalho 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Teste"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Público"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Perfil de trabalho"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espaço privado"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 4ef0423b327b..19158cc47ae2 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -2275,6 +2275,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Derulează"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Întrerupe"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Poziție"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a fost adăugat la grupul RESTRICȚIONATE"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"a trimis o imagine"</string> @@ -2482,6 +2494,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Serviciu 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Comun"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Profil de serviciu"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Spațiu privat"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clonă"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index a03963ef9924..136f76ae55ce 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -2276,6 +2276,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Прокрутить"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Приостановить"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Положение"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Приложение \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" помещено в категорию с ограниченным доступом."</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"Отправлено изображение"</string> @@ -2483,6 +2495,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Рабочий 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Тестовый"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Совместный"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Рабочий профиль"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Частное пространство"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клонированный"</string> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 571706e325c9..7a4de0eca678 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"අනුචලනය කරන්න"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"විරාම කරන්න"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"ස්ථානය"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> අවහිර කළ බාල්දියට දමා ඇත"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"රූපයක් එව්වා"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"කාර්යාලය 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"පරීක්ෂණය"</string> <string name="profile_label_communal" msgid="8743921499944800427">"වාර්ගික"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"කාර්යාල පැතිකඩ"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"රහසිගත අවකාශය"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ක්ලෝන කරන්න"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index bcbd66f55412..c47ce658c1a8 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -1967,8 +1967,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pred uvoľnením požiadať o bezpečnostný vzor"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pred odopnutím požiadať o heslo"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"Nainštaloval správca.\nAk si chcete zobraziť udelené povolenia, prejdite do nastavení."</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"Aktualizoval správca.\nAk si chcete zobraziť udelené povolenia, prejdite do nastavení."</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Odstránil správca"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Šetrič batérie zapne tmavý motív a obmedzí alebo vypne aktivitu na pozadí, niektoré vizuálne efekty, určité funkcie a niektoré pripojenia k sieti."</string> @@ -2276,6 +2275,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Posúvať"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pozastaviť"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozícia"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balík <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> bol vložený do kontajnera OBMEDZENÉ"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"odoslal(a) obrázok"</string> @@ -2483,6 +2494,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"3. pracovný"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Spoločné"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Pracovný profil"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Súkromný priestor"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index c0d18ed0a067..07cb71c1b317 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -1967,8 +1967,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pred odpenjanjem vprašaj za vzorec za odklepanje"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pred odpenjanjem vprašaj za geslo"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"Namestil skrbnik.\nV nastavitvah si oglejte odobrena dovoljenja."</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"Posodobil skrbnik.\nV nastavitvah si oglejte odobrena dovoljenja"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisal skrbnik"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"V redu"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Funkcija varčevanja z energijo baterije vklopi temno temo ter omeji ali izklopi dejavnost v ozadju, nekatere vizualne učinke, določene funkcije in nekatere omrežne povezave."</string> @@ -2276,6 +2275,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Drsenje"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Začasna zaustavitev"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Položaj"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je bil dodan v segment OMEJENO"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"je poslal(-a) sliko"</string> @@ -2483,6 +2494,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Delo 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Preizkus"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Skupno"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Delovni profil"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Zasebni prostor"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index ddccedeaa36c..1b3feedaeccb 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Lëviz"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Vendos në pauzë"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozicioni"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> është vendosur në grupin E KUFIZUAR"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"dërgoi një imazh"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Puna 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"I përbashkët"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Profili i punës"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Hapësira private"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 397a39458580..24624f7e479f 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -2275,6 +2275,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Скролујте"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Паузирај"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Позиција"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> је додат у сегмент ОГРАНИЧЕНО"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"је послао/ла слику"</string> @@ -2482,6 +2494,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Посао 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Тест"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Заједничко"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Пословни профил"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Приватан простор"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клонирано"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 71062addb40f..c471f065b377 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -1965,8 +1965,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Be om upplåsningsmönster innan skärmen slutar fästas"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Be om lösenord innan skärmen slutar fästas"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"Har installerats av administratören.\nÖppna inställningarna för att se behörigheter som beviljats"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"Har uppdaterats av administratören.\nÖppna inställningarna för att se behörigheter som beviljats"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Administratören raderade paketet"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"I batterisparläget aktiveras mörkt tema medan bakgrundsaktivitet, vissa visuella effekter och funktioner samt vissa nätverksanslutningar begränsas eller inaktiveras."</string> @@ -2274,6 +2273,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Scrolla"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausa"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> har placerats i hinken RESTRICTED"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"har skickat en bild"</string> @@ -2481,6 +2492,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Arbete 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Allmän"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Jobbprofil"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privat utrymme"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klona"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index e74ac1858d76..2a920b235335 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Sogeza"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Sitisha"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Nafasi"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> kimewekwa katika kikundi KILICHODHIBITIWA"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"alituma picha"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Wa 3 wa Kazini"</string> <string name="profile_label_test" msgid="9168641926186071947">"Jaribio"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Unaoshirikiwa"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Wasifu wa kazini"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Sehemu ya faragha"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Nakala"</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 7737d8f6da45..1fade556f421 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"நகர்த்தும்"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"இடைநிறுத்து"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"நிலை"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> என்பதை வரம்பிடப்பட்ட பக்கெட்திற்குள் சேர்க்கப்பட்டது"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"படம் அனுப்பப்பட்டது"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"பணி 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"பரிசோதனை"</string> <string name="profile_label_communal" msgid="8743921499944800427">"பொது"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"பணிக் கணக்கு"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"ரகசிய இடம்"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"குளோன்"</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 265fb8c9b382..4f6eaf3b2307 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -1965,8 +1965,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"అన్పిన్ చేయడానికి ముందు అన్లాక్ ఆకృతి కోసం అడుగు"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"అన్పిన్ చేయడానికి ముందు పాస్వర్డ్ కోసం అడుగు"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"మీ అడ్మిన్ ఇన్స్టాల్ చేశారు.\nసెట్టింగ్లకు వెళ్లి, మంజూరు చేసిన అనుమతులు చూడండి"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"మీ అడ్మిన్ అప్డేట్ చేశారు.\nసెట్టింగ్లకు వెళ్లి, మంజూరు చేసిన అనుమతులను చూడండి"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"మీ నిర్వాహకులు తొలగించారు"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"సరే"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"బ్యాటరీ సేవర్ ముదురు రంగు రూపాన్ని ఆన్ చేసి, బ్యాక్గ్రౌండ్ యాక్టివిటీ, కొన్ని విజువల్ ఎఫెక్ట్లు, నిర్దిష్ట ఫీచర్లు, ఇంకా కొన్ని నెట్వర్క్ కనెక్షన్లను పరిమితం చేస్తుంది లేదా ఆఫ్ చేస్తుంది."</string> @@ -2274,6 +2273,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"స్క్రోల్ చేయండి"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"పాజ్ చేయండి"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"స్థానం"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> పరిమితం చేయబడిన బకెట్లో ఉంచబడింది"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ఇమేజ్ను పంపారు"</string> @@ -2481,6 +2492,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ఆఫీస్ 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"పరీక్ష"</string> <string name="profile_label_communal" msgid="8743921499944800427">"కమ్యూనల్"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"వర్క్ ప్రొఫైల్"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"ప్రైవేట్ స్పేస్"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"క్లోన్"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index a922943f54c7..b67f3828ab72 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -1965,8 +1965,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ขอรูปแบบการปลดล็อกก่อนเลิกปักหมุด"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ขอรหัสผ่านก่อนเลิกปักหมุด"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"ติดตั้งโดยผู้ดูแลระบบของคุณ\nไปที่การตั้งค่าเพื่อดูสิทธิ์ที่ได้รับอนุญาต"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"อัปเดตโดยผู้ดูแลระบบของคุณ\nไปที่การตั้งค่าเพื่อดูสิทธิ์ที่ได้รับอนุญาต"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"ลบโดยผู้ดูแลระบบ"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ตกลง"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"โหมดประหยัดแบตเตอรี่จะเปิดธีมมืดและจำกัดหรือปิดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง ฟีเจอร์บางส่วน และการเชื่อมต่อบางเครือข่าย"</string> @@ -2274,6 +2273,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"เลื่อน"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"หยุดชั่วคราว"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"วางตำแหน่ง"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"ใส่ <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ในที่เก็บข้อมูลที่ถูกจำกัดแล้ว"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ส่งรูปภาพ"</string> @@ -2481,6 +2492,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"งาน 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"ทดสอบ"</string> <string name="profile_label_communal" msgid="8743921499944800427">"ส่วนกลาง"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"โปรไฟล์งาน"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"พื้นที่ส่วนตัว"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"โคลน"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 5e3e1e86c713..3c380884ceea 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -1965,8 +1965,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Humingi ng pattern sa pag-unlock bago mag-unpin"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Humingi ng password bago mag-unpin"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"Na-install ng iyong admin.\nPumunta sa mga setting para makita ang mga ibinigay na pahintulot"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"Na-update ng iyong admin.\nPumunta sa mga setting para makita ang mga ibinigay na pahintulot"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Na-delete ng iyong admin"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Ino-on ng Pantipid ng Baterya ang Madilim na tema at nililimitahan o ino-off nito ang aktibidad sa background, ilang visual effect, ilang partikular na feature, at ilang koneksyon sa network."</string> @@ -2274,6 +2273,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Mag-scroll"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"I-pause"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posisyon"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Inilagay ang <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> sa PINAGHIHIGPITANG bucket"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"nagpadala ng larawan"</string> @@ -2481,6 +2492,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Trabaho 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Communal"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Profile sa trabaho"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Pribadong space"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 72d62d5b2499..dfaa061ba093 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Kaydırma"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Duraklatma"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Konum"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> KISITLANMIŞ gruba yerleştirildi"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"bir resim gönderildi"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"İş 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Paylaşılan"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"İş profili"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Özel alan"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index e4e1e99be263..34dda976f1bc 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -2276,6 +2276,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Прокрутити"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Призупинити"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Змінити позицію"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" додано в сегмент з обмеженнями"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"надіслано зображення"</string> @@ -2483,6 +2495,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Робочий профіль 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Тестовий профіль"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Спільний профіль"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Робочий профіль"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Приватний простір"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Копія профілю"</string> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index a98179a3064b..31b5999b6f15 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -1965,8 +1965,7 @@ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"پن ہٹانے سے پہلے غیر مقفل کرنے کا پیٹرن طلب کریں"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"پن ہٹانے سے پہلے پاس ورڈ طلب کریں"</string> <string name="package_installed_device_owner" msgid="8684974629306529138">"آپ کے منتظم نے انسٹال کیا ہے۔\nدی گئی اجازتیں دیکھنے کیلئے ترتیبات پر جائیں"</string> - <!-- no translation found for package_updated_device_owner (7770195449213776218) --> - <skip /> + <string name="package_updated_device_owner" msgid="7770195449213776218">"آپ کے منتظم نے اپ ڈیٹ کیا ہے۔\nدی گئی اجازتیں دیکھنے کیلئے ترتیبات پر جائیں"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"آپ کے منتظم کے ذریعے حذف کیا گیا"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ٹھیک ہے"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"بیٹری سیور گہری تھیم کو آن کرتی ہے اور پس منظر کی سرگرمی، کچھ بصری اثرات، مخصوص خصوصیات اور کچھ نیٹ ورک کنکشنز کو محدود یا آف کرتی ہے۔"</string> @@ -2274,6 +2273,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"اسکرول کریں"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"موقوف کریں"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"پوزیشن"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> کو پابند کردہ بکٹ میں رکھ دیا گیا ہے"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ایک تصویر بھیجی"</string> @@ -2481,6 +2492,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"تیسری دفتری پروفائل"</string> <string name="profile_label_test" msgid="9168641926186071947">"ٹیسٹ"</string> <string name="profile_label_communal" msgid="8743921499944800427">"کمیونل"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"دفتری پروفائل"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"پرائیویٹ اسپیس"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"کلون"</string> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index 81ebe5fa7c2b..35c35ac6d90b 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Aylantirish"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pauza"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Joylashuvi"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> cheklangan turkumga joylandi"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"rasm yuborildi"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Ish 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Umumiy"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Ish profili"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Maxfiy makon"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Nusxalash"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 4dda8cc0c8c1..626625f85d40 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Cuộn"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Tạm dừng"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Vị trí"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Đã đưa <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> vào bộ chứa BỊ HẠN CHẾ"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"đã gửi hình ảnh"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Công việc 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Kiểm thử"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Dùng chung"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Hồ sơ công việc"</string> <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> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 851195acf204..921a464c434e 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"滚动"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"暂停"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"位置"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已被放入受限存储分区"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"发送了一张图片"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"工作 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"测试"</string> <string name="profile_label_communal" msgid="8743921499944800427">"共用"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"工作资料"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"私密空间"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"克隆"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 87b403d39207..8681d036948a 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"捲動"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"暫停"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"位置"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已納入受限制的儲存區"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"已傳送圖片"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"工作 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"測試"</string> <string name="profile_label_communal" msgid="8743921499944800427">"共用"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"工作設定檔"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"私人空間"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"複製"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 72d2e7ce3cc1..21e9113bc9a0 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"捲動"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"暫停"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"位置"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"已將「<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>」移入受限制的值區"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"傳送了一張圖片"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"工作 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"測試"</string> <string name="profile_label_communal" msgid="8743921499944800427">"通用"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"工作資料夾"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"私人空間"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"複製"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 13356cbcd356..695f3198c90b 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -2274,6 +2274,18 @@ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Skrola"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Misa"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Indawo"</string> + <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) --> + <skip /> + <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) --> + <skip /> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"I-<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ifakwe kubhakede LOKUKHAWULELWE"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"uthumele isithombe"</string> @@ -2481,6 +2493,8 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Umsebenzi 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Hlola"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Okomphakathi"</string> + <!-- no translation found for profile_label_supervising (5649312778545745371) --> + <skip /> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Iphrofayela yomsebenzi"</string> <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Indawo engasese"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Yenza i-Clone"</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 8c5b20da73ef..7a38dce296de 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4184,6 +4184,11 @@ <!-- Whether device supports double tap to wake --> <bool name="config_supportDoubleTapWake">false</bool> + <!-- Whether device supports double tap to sleep. This will allow the user to enable/disable + double tap gestures in non-action areas in the lock screen and launcher workspace to go to + sleep. --> + <bool name="config_supportDoubleTapSleep">false</bool> + <!-- The RadioAccessFamilies supported by the device. Empty is viewed as "all". Only used on devices which don't support RIL_REQUEST_GET_RADIO_CAPABILITY diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 465e318511c6..6e540833bc46 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -277,12 +277,24 @@ <!-- The margin on the end of the top-line content views (accommodates the expander) --> <dimen name="notification_heading_margin_end">56dp</dimen> + <!-- The vertical spacing for the smart reply/smart action container. + Note that the button background itself also has an inset of 6dp (making the height of the + tappable area 48dp total, 32dp for the visible button plus 6dp top and bottom), so the visible + space between the button and the other content is going to be 16dp. --> + <dimen name="notification_2025_smart_reply_container_margin">10dp</dimen> + <!-- The total height of the notification action list --> <dimen name="notification_action_list_height">60dp</dimen> + <!-- The total height of the notification action list (2025 redesign version) --> + <dimen name="notification_2025_action_list_height">48dp</dimen> + <!-- The margin of the notification action list at the top --> <dimen name="notification_action_list_margin_top">0dp</dimen> + <!-- The margin of the notification action list at the bottom in the 2025 redesign --> + <dimen name="notification_2025_action_list_margin_bottom">6dp</dimen> + <!-- The overall height of the emphasized notification action --> <dimen name="notification_action_emphasized_height">48dp</dimen> @@ -304,6 +316,9 @@ <!-- The size of icons for visual actions in the notification_material_action_list --> <dimen name="notification_actions_icon_size">56dp</dimen> + <!-- The size of icon actions in notification_material_action_list (2025 redesign version) --> + <dimen name="notification_2025_actions_icon_size">48dp</dimen> + <!-- The size of icons for visual actions in the notification_material_action_list --> <dimen name="notification_actions_icon_drawable_size">20dp</dimen> @@ -1235,4 +1250,7 @@ <!-- The maximum width for a context menu icon --> <dimen name="list_menu_item_icon_max_width">24dp</dimen> + + <!-- Default height of desktop view header for freeform tasks on launch. --> + <dimen name="desktop_view_default_header_height">40dp</dimen> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 3de30f7f25a8..922d59dfcfe0 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3142,6 +3142,7 @@ <java-symbol type="color" name="chooser_row_divider" /> <java-symbol type="layout" name="chooser_row_direct_share" /> <java-symbol type="bool" name="config_supportDoubleTapWake" /> + <java-symbol type="bool" name="config_supportDoubleTapSleep" /> <java-symbol type="drawable" name="ic_perm_device_info" /> <java-symbol type="string" name="config_radio_access_family" /> <java-symbol type="string" name="notification_inbox_ellipsis" /> @@ -3270,6 +3271,8 @@ <java-symbol type="dimen" name="notification_2025_expand_button_reduced_end_padding" /> <java-symbol type="dimen" name="notification_2025_expand_button_right_icon_spacing" /> <java-symbol type="dimen" name="notification_2025_right_icon_expanded_margin_end" /> + <java-symbol type="dimen" name="notification_2025_action_list_margin_bottom" /> + <java-symbol type="dimen" name="notification_2025_smart_reply_container_margin" /> <java-symbol type="dimen" name="notification_progress_margin_horizontal" /> <java-symbol type="dimen" name="notification_header_background_height" /> <java-symbol type="dimen" name="notification_header_touchable_height" /> @@ -3496,6 +3499,7 @@ <java-symbol type="dimen" name="input_extract_action_button_height" /> <java-symbol type="dimen" name="notification_action_list_height" /> + <java-symbol type="dimen" name="notification_2025_action_list_height" /> <java-symbol type="dimen" name="notification_action_emphasized_height" /> <!-- TV Remote Service package --> @@ -5974,4 +5978,6 @@ <!-- Enable OEMs to support scale up anim across tasks.--> <java-symbol type="bool" name="config_enableCrossTaskScaleUpAnimation" /> + <!-- Default height of desktop view header for freeform tasks on launch. --> + <java-symbol type="dimen" name="desktop_view_default_header_height" /> </resources> diff --git a/core/tests/coretests/src/android/text/LayoutTest.java b/core/tests/coretests/src/android/text/LayoutTest.java index 9e78af57b470..11ec9f8e1912 100644 --- a/core/tests/coretests/src/android/text/LayoutTest.java +++ b/core/tests/coretests/src/android/text/LayoutTest.java @@ -16,6 +16,9 @@ package android.text; +import static android.text.Layout.HIGH_CONTRAST_TEXT_BACKGROUND_CORNER_RADIUS_FACTOR; +import static android.text.Layout.HIGH_CONTRAST_TEXT_BACKGROUND_CORNER_RADIUS_MIN_DP; + import static com.android.graphics.hwui.flags.Flags.FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT; import static org.junit.Assert.assertArrayEquals; @@ -1073,6 +1076,68 @@ public class LayoutTest { } } + @Test + @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) + public void highContrastTextEnabled_testRoundedRectSize_belowMinimum_usesMinimumValue() { + mTextPaint.setColor(Color.BLACK); + mTextPaint.setTextSize(8); // Value chosen so that N * RADIUS_FACTOR < RADIUS_MIN_DP + Layout layout = new StaticLayout("Test text", mTextPaint, mWidth, + mAlign, mSpacingMult, mSpacingAdd, /* includePad= */ false); + + MockCanvas c = new MockCanvas(/* width= */ 256, /* height= */ 256); + c.setHighContrastTextEnabled(true); + layout.draw( + c, + /* highlightPaths= */ null, + /* highlightPaints= */ null, + /* selectionPath= */ null, + /* selectionPaint= */ null, + /* cursorOffsetVertical= */ 0 + ); + + final float expectedRoundedRectSize = + mTextPaint.density * HIGH_CONTRAST_TEXT_BACKGROUND_CORNER_RADIUS_MIN_DP; + List<MockCanvas.DrawCommand> drawCommands = c.getDrawCommands(); + for (int i = 0; i < drawCommands.size(); i++) { + MockCanvas.DrawCommand drawCommand = drawCommands.get(i); + if (drawCommand.rect != null) { + expect.that(drawCommand.rX).isEqualTo(expectedRoundedRectSize); + expect.that(drawCommand.rY).isEqualTo(expectedRoundedRectSize); + } + } + } + + @Test + @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) + public void highContrastTextEnabled_testRoundedRectSize_aboveMinimum_usesScaledValue() { + mTextPaint.setColor(Color.BLACK); + mTextPaint.setTextSize(50); // Value chosen so that N * RADIUS_FACTOR > RADIUS_MIN_DP + Layout layout = new StaticLayout("Test text", mTextPaint, mWidth, + mAlign, mSpacingMult, mSpacingAdd, /* includePad= */ false); + + MockCanvas c = new MockCanvas(/* width= */ 256, /* height= */ 256); + c.setHighContrastTextEnabled(true); + layout.draw( + c, + /* highlightPaths= */ null, + /* highlightPaints= */ null, + /* selectionPath= */ null, + /* selectionPaint= */ null, + /* cursorOffsetVertical= */ 0 + ); + + final float expectedRoundedRectSize = + mTextPaint.getTextSize() * HIGH_CONTRAST_TEXT_BACKGROUND_CORNER_RADIUS_FACTOR; + List<MockCanvas.DrawCommand> drawCommands = c.getDrawCommands(); + for (int i = 0; i < drawCommands.size(); i++) { + MockCanvas.DrawCommand drawCommand = drawCommands.get(i); + if (drawCommand.rect != null) { + expect.that(drawCommand.rX).isEqualTo(expectedRoundedRectSize); + expect.that(drawCommand.rY).isEqualTo(expectedRoundedRectSize); + } + } + } + private int removeAlpha(int color) { return Color.rgb( Color.red(color), @@ -1087,6 +1152,8 @@ public class LayoutTest { public final String text; public final float x; public final float y; + public final float rX; + public final float rY; public final Path path; public final RectF rect; public final Paint paint; @@ -1098,6 +1165,8 @@ public class LayoutTest { this.paint = new Paint(paint); path = null; rect = null; + this.rX = 0; + this.rY = 0; } DrawCommand(Path path, Paint paint) { @@ -1107,15 +1176,19 @@ public class LayoutTest { x = 0; text = null; rect = null; + this.rX = 0; + this.rY = 0; } - DrawCommand(RectF rect, Paint paint) { + DrawCommand(RectF rect, Paint paint, float rX, float rY) { this.rect = new RectF(rect); this.paint = new Paint(paint); path = null; y = 0; x = 0; text = null; + this.rX = rX; + this.rY = rY; } @Override @@ -1189,12 +1262,12 @@ public class LayoutTest { @Override public void drawRect(RectF rect, Paint p) { - mDrawCommands.add(new DrawCommand(rect, p)); + mDrawCommands.add(new DrawCommand(rect, p, 0, 0)); } @Override public void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) { - mDrawCommands.add(new DrawCommand(rect, paint)); + mDrawCommands.add(new DrawCommand(rect, paint, rx, ry)); } List<DrawCommand> getDrawCommands() { diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityWorkProfileTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityWorkProfileTest.java index db69cf2397fc..02a296892c53 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityWorkProfileTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityWorkProfileTest.java @@ -72,7 +72,8 @@ public class ChooserActivityWorkProfileTest { private static final UserHandle PERSONAL_USER_HANDLE = InstrumentationRegistry .getInstrumentation().getTargetContext().getUser(); - private static final UserHandle WORK_USER_HANDLE = UserHandle.of(10); + private static final UserHandle WORK_USER_HANDLE = + UserHandle.of(PERSONAL_USER_HANDLE.getIdentifier() + 1); @Rule public ActivityTestRule<ChooserWrapperActivity> mActivityRule = diff --git a/libs/WindowManager/Shell/aconfig/OWNERS b/libs/WindowManager/Shell/aconfig/OWNERS index 9eba0f2dea7b..eacadeacab36 100644 --- a/libs/WindowManager/Shell/aconfig/OWNERS +++ b/libs/WindowManager/Shell/aconfig/OWNERS @@ -1,3 +1,4 @@ # Owners for flag changes madym@google.com -hwwang@google.com
\ No newline at end of file +hwwang@google.com +sqsun@google.com
\ No newline at end of file diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig index ab2804626361..592c7cdd070c 100644 --- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig +++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig @@ -203,4 +203,11 @@ flag { metadata { purpose: PURPOSE_BUGFIX } -}
\ No newline at end of file +} + +flag { + name: "enable_magnetic_split_divider" + namespace: "multitasking" + description: "Makes the split divider snap 'magnetically' to available snap points during drag" + bug: "383631946" +} diff --git a/libs/WindowManager/Shell/multivalentTests/Android.bp b/libs/WindowManager/Shell/multivalentTests/Android.bp index 03076c0940a4..50666911e313 100644 --- a/libs/WindowManager/Shell/multivalentTests/Android.bp +++ b/libs/WindowManager/Shell/multivalentTests/Android.bp @@ -51,6 +51,7 @@ android_robolectric_test { "androidx.test.ext.junit", "mockito-robolectric-prebuilt", "mockito-kotlin2", + "platform-parametric-runner-lib", "truth", "flag-junit-base", "flag-junit", @@ -74,6 +75,7 @@ android_test { "frameworks-base-testutils", "mockito-kotlin2", "mockito-target-extended-minus-junit4", + "platform-parametric-runner-lib", "truth", "platform-test-annotations", "platform-test-rules", diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleExpandedViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleExpandedViewTest.kt new file mode 100644 index 000000000000..bdfaef2c6960 --- /dev/null +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleExpandedViewTest.kt @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2025 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.bubbles + +import android.content.ComponentName +import android.content.Context +import android.platform.test.flag.junit.FlagsParameterization +import android.platform.test.flag.junit.SetFlagsRule +import androidx.test.core.app.ApplicationProvider +import androidx.test.filters.SmallTest +import com.android.wm.shell.Flags +import com.android.wm.shell.taskview.TaskView +import com.google.common.truth.Truth.assertThat +import com.google.common.util.concurrent.MoreExecutors.directExecutor +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.mock +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters + +/** Tests for [BubbleExpandedView] */ +@SmallTest +@RunWith(ParameterizedAndroidJunit4::class) +class BubbleExpandedViewTest(flags: FlagsParameterization) { + + @get:Rule + val setFlagsRule = SetFlagsRule(flags) + + private val context = ApplicationProvider.getApplicationContext<Context>() + private val componentName = ComponentName(context, "TestClass") + + @Test + fun getTaskId_onTaskCreated_returnsCorrectTaskId() { + val bubbleTaskView = BubbleTaskView(mock<TaskView>(), directExecutor()) + val expandedView = BubbleExpandedView(context).apply { + initialize( + mock<BubbleExpandedViewManager>(), + mock<BubbleStackView>(), + mock<BubblePositioner>(), + false /* isOverflow */, + bubbleTaskView, + ) + setAnimating(true) // Skips setContentVisibility for testing. + } + + bubbleTaskView.listener.onTaskCreated(123, componentName) + + assertThat(expandedView.getTaskId()).isEqualTo(123) + } + + companion object { + @JvmStatic + @Parameters(name = "{0}") + fun getParams() = FlagsParameterization.allCombinationsOf( + Flags.FLAG_ENABLE_BUBBLE_TASK_VIEW_LISTENER, + ) + } +} diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewListenerTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewListenerTest.kt index 9087da34d259..636ff669d6b4 100644 --- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewListenerTest.kt +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewListenerTest.kt @@ -266,8 +266,6 @@ class BubbleTaskViewListenerTest { optionsCaptor.capture(), any()) - assertThat((intentCaptor.lastValue.flags - and Intent.FLAG_ACTIVITY_MULTIPLE_TASK) != 0).isTrue() assertThat(optionsCaptor.lastValue.launchedFromBubble).isFalse() // chat only assertThat(optionsCaptor.lastValue.isApplyActivityFlagsForBubbles).isFalse() // chat only assertThat(optionsCaptor.lastValue.taskAlwaysOnTop).isTrue() @@ -295,8 +293,6 @@ class BubbleTaskViewListenerTest { optionsCaptor.capture(), any()) - assertThat((intentCaptor.lastValue.flags - and Intent.FLAG_ACTIVITY_MULTIPLE_TASK) != 0).isTrue() assertThat(optionsCaptor.lastValue.launchedFromBubble).isFalse() // chat only assertThat(optionsCaptor.lastValue.isApplyActivityFlagsForBubbles).isFalse() // chat only assertThat(optionsCaptor.lastValue.taskAlwaysOnTop).isTrue() @@ -324,8 +320,6 @@ class BubbleTaskViewListenerTest { optionsCaptor.capture(), any()) - assertThat((intentCaptor.lastValue.flags - and Intent.FLAG_ACTIVITY_MULTIPLE_TASK) != 0).isTrue() assertThat(optionsCaptor.lastValue.launchedFromBubble).isFalse() // chat only assertThat(optionsCaptor.lastValue.isApplyActivityFlagsForBubbles).isFalse() // chat only assertThat(optionsCaptor.lastValue.taskAlwaysOnTop).isTrue() diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/UiEventSubject.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/UiEventSubject.kt index 2d6df43f67e0..3597ce0041d4 100644 --- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/UiEventSubject.kt +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/UiEventSubject.kt @@ -22,14 +22,14 @@ import com.google.common.truth.Subject import com.google.common.truth.Truth /** Subclass of [Subject] to simplify verifying [FakeUiEvent] data */ -class UiEventSubject(metadata: FailureMetadata, private val actual: FakeUiEvent) : +class UiEventSubject(metadata: FailureMetadata, private val actual: FakeUiEvent?) : Subject(metadata, actual) { /** Check that [FakeUiEvent] contains the expected data from the [bubble] passed id */ fun hasBubbleInfo(bubble: Bubble) { - check("uid").that(actual.uid).isEqualTo(bubble.appUid) - check("packageName").that(actual.packageName).isEqualTo(bubble.packageName) - check("instanceId").that(actual.instanceId).isEqualTo(bubble.instanceId) + check("uid").that(actual?.uid).isEqualTo(bubble.appUid) + check("packageName").that(actual?.packageName).isEqualTo(bubble.packageName) + check("instanceId").that(actual?.instanceId).isEqualTo(bubble.instanceId) } companion object { diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_header_ic_minimize.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_header_ic_minimize.xml index b35dc022e210..56e5dc717a7b 100644 --- a/libs/WindowManager/Shell/res/drawable/desktop_mode_header_ic_minimize.xml +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_header_ic_minimize.xml @@ -18,9 +18,9 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" - android:viewportHeight="24" - android:viewportWidth="24"> + android:viewportWidth="960" + android:viewportHeight="960"> <path android:fillColor="#FF000000" - android:pathData="M6,21V19H18V21Z"/> + android:pathData="M160,800L160,720L800,720L800,800L160,800Z"/> </vector> diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml index 16e098b39004..e11babe5cb0e 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml @@ -39,8 +39,8 @@ <ImageView android:id="@+id/application_icon" - android:layout_width="@dimen/desktop_mode_caption_icon_radius" - android:layout_height="@dimen/desktop_mode_caption_icon_radius" + android:layout_width="@dimen/desktop_mode_handle_menu_icon_radius" + android:layout_height="@dimen/desktop_mode_handle_menu_icon_radius" android:layout_marginStart="10dp" android:layout_marginEnd="12dp" android:contentDescription="@string/app_icon_text" diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml index c2aa146d6437..3ebe87dcf505 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml @@ -38,11 +38,11 @@ android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" - android:layout_marginStart="4dp" - android:layout_marginEnd="4dp"> + android:gravity="center_horizontal" + android:layout_marginHorizontal="4dp"> <Button - android:layout_width="94dp" + android:layout_width="108dp" android:layout_height="60dp" android:id="@+id/maximize_menu_immersive_toggle_button" style="?android:attr/buttonBarButtonStyle" @@ -75,8 +75,7 @@ android:layout_weight="1" android:orientation="vertical" android:gravity="center_horizontal" - android:layout_marginStart="4dp" - android:layout_marginEnd="4dp"> + android:layout_marginHorizontal="4dp"> <Button android:layout_width="108dp" @@ -112,8 +111,7 @@ android:layout_weight="1" android:orientation="vertical" android:gravity="center_horizontal" - android:layout_marginStart="4dp" - android:layout_marginEnd="4dp"> + android:layout_marginHorizontal="4dp"> <LinearLayout android:id="@+id/maximize_menu_snap_menu_layout" android:layout_width="wrap_content" diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml index 61dbb69761ad..1491c70023e7 100644 --- a/libs/WindowManager/Shell/res/values-af/strings.xml +++ b/libs/WindowManager/Shell/res/values-af/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nie opgelos nie?\nTik om terug te stel"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Geen kamerakwessies nie? Tik om toe te maak."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Die appkieslys kan hier gevind word"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Maak rekenaaraansig oop om veelvuldige apps saam oop te maak"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Keer enige tyd terug na volskerm vanaf die appkieslys"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Sien en doen meer"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Sleep ’n ander app in vir verdeelde skerm"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Apphandvatsel"</string> <string name="app_icon_text" msgid="2823268023931811747">"Appikoon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Volskerm"</string> - <string name="desktop_text" msgid="1582173066857454541">"Rekenaaraansig"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Verdeelde skerm"</string> <string name="more_button_text" msgid="3655388105592893530">"Meer"</string> <string name="float_button_text" msgid="9221657008391364581">"Sweef"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Verander aspekverhouding"</string> <string name="close_text" msgid="4986518933445178928">"Maak toe"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Maak kieslys toe"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Rekenaaraansig)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimeer skerm"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Verander grootte"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App kan nie hierheen geskuif word nie"</string> diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml index 52008a6ff952..8bd602c08508 100644 --- a/libs/WindowManager/Shell/res/values-am/strings.xml +++ b/libs/WindowManager/Shell/res/values-am/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"አልተስተካከለም?\nለማህደር መታ ያድርጉ"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ምንም የካሜራ ችግሮች የሉም? ለማሰናበት መታ ያድርጉ።"</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"የመተግበሪያ ምናሌው እዚህ መገኘት ይችላል"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"በርካታ መተግበሪያዎችን በአንድ ላይ ለመክፈት ወደ የዴስክቶፕ እይታ ይግቡ"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"በማንኛውም ጊዜ ከመተግበሪያ ምናሌው ላይ ወደ ሙሉ ገጽ እይታ ይመለሱ"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ተጨማሪ ይመልከቱ እና ያድርጉ"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ለተከፈለ ማያ ገፅ ሌላ መተግበሪያ ይጎትቱ"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"የመተግበሪያ መያዣ"</string> <string name="app_icon_text" msgid="2823268023931811747">"የመተግበሪያ አዶ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ሙሉ ማያ"</string> - <string name="desktop_text" msgid="1582173066857454541">"የዴስክቶፕ ዕይታ"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"የተከፈለ ማያ ገፅ"</string> <string name="more_button_text" msgid="3655388105592893530">"ተጨማሪ"</string> <string name="float_button_text" msgid="9221657008391364581">"ተንሳፋፊ"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"ምጥጥነ ገፅታ ለውጥ"</string> <string name="close_text" msgid="4986518933445178928">"ዝጋ"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"ምናሌ ዝጋ"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> የዴስክቶፕ ዕይታ"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"የማያ ገጹ መጠን አሳድግ"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"መጠን ቀይር"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"መተግበሪያ ወደዚህ መንቀሳቀስ አይችልም"</string> diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml index 65dd965afbf1..70a23b73b6f5 100644 --- a/libs/WindowManager/Shell/res/values-ar/strings.xml +++ b/libs/WindowManager/Shell/res/values-ar/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ألم يتم حل المشكلة؟\nانقر للعودة"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"أليس هناك مشاكل في الكاميرا؟ انقر للإغلاق."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"يمكن العثور على قائمة التطبيقات هنا"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"يمكنك الدخول إلى وضع العرض المخصّص للكمبيوتر المكتبي لفتح عدة تطبيقات معًا"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"يمكنك الرجوع إلى وضع ملء الشاشة في أي وقت من قائمة التطبيقات"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"استخدام تطبيقات متعدّدة في وقت واحد"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"اسحب تطبيقًا آخر لاستخدام وضع تقسيم الشاشة."</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"مقبض التطبيق"</string> <string name="app_icon_text" msgid="2823268023931811747">"رمز التطبيق"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ملء الشاشة"</string> - <string name="desktop_text" msgid="1582173066857454541">"العرض المخصّص للكمبيوتر المكتبي"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"تقسيم الشاشة"</string> <string name="more_button_text" msgid="3655388105592893530">"المزيد"</string> <string name="float_button_text" msgid="9221657008391364581">"نافذة عائمة"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"تغيير نسبة العرض إلى الارتفاع"</string> <string name="close_text" msgid="4986518933445178928">"إغلاق"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"إغلاق القائمة"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (العرض المخصّص للكمبيوتر المكتبي)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"تكبير الشاشة إلى أقصى حدّ"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"تغيير الحجم"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"لا يمكن نقل التطبيق إلى هنا"</string> diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml index 919447e125a1..6872df6acbc9 100644 --- a/libs/WindowManager/Shell/res/values-as/strings.xml +++ b/libs/WindowManager/Shell/res/values-as/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"এইটো সমাধান কৰা নাই নেকি?\nপূৰ্বাৱস্থালৈ নিবলৈ টিপক"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"কেমেৰাৰ কোনো সমস্যা নাই নেকি? অগ্ৰাহ্য কৰিবলৈ টিপক।"</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"এপৰ মেনু ইয়াত বিচাৰি পোৱা যাব"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"একেলগে একাধিক এপ্ খুলিবলৈ ডেস্কটপ ভিউলৈ যাওক"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"এপৰ মেনুৰ পৰা যিকোনো সময়তে পূৰ্ণ স্ক্ৰীনলৈ উভতি যাওক"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"চাওক আৰু অধিক কৰক"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"বিভাজিত স্ক্ৰীনৰ বাবে অন্য এটা এপ্ টানি আনি এৰক"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"এপৰ হেণ্ডেল"</string> <string name="app_icon_text" msgid="2823268023931811747">"এপৰ চিহ্ন"</string> <string name="fullscreen_text" msgid="1162316685217676079">"সম্পূৰ্ণ স্ক্ৰীন"</string> - <string name="desktop_text" msgid="1582173066857454541">"ডেস্কটপ ভিউ"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"বিভাজিত স্ক্ৰীন"</string> <string name="more_button_text" msgid="3655388105592893530">"অধিক"</string> <string name="float_button_text" msgid="9221657008391364581">"ওপঙা"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"আকাৰৰ অনুপাত সলনি কৰক"</string> <string name="close_text" msgid="4986518933445178928">"বন্ধ কৰক"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"মেনু বন্ধ কৰক"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ডেস্কটপ ভিউ)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"স্ক্ৰীন মেক্সিমাইজ কৰক"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"আকাৰ সলনি কৰক"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ইয়ালৈ এপ্টো আনিব নোৱাৰি"</string> diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml index 846240f80037..46309411d0c9 100644 --- a/libs/WindowManager/Shell/res/values-az/strings.xml +++ b/libs/WindowManager/Shell/res/values-az/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Düzəltməmisiniz?\nGeri qaytarmaq üçün toxunun"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kamera problemi yoxdur? Qapatmaq üçün toxunun."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Tətbiq menyusunu burada tapa bilərsiniz"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Bir neçə tətbiqi birlikdə açmaq üçün masaüstü görünüşə daxil olun"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"İstənilən vaxt tətbiq menyusundan tam ekrana qayıdın"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Ardını görün və edin"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Bölünmüş ekran üçün başqa tətbiq sürüşdürün"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Tətbiq ləqəbi"</string> <string name="app_icon_text" msgid="2823268023931811747">"Tətbiq ikonası"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Tam Ekran"</string> - <string name="desktop_text" msgid="1582173066857454541">"Masaüstü Görünüş"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Bölünmüş Ekran"</string> <string name="more_button_text" msgid="3655388105592893530">"Ardı"</string> <string name="float_button_text" msgid="9221657008391364581">"Üzən pəncərə"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Tərəflər nisbətini dəyişin"</string> <string name="close_text" msgid="4986518933445178928">"Bağlayın"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Menyunu bağlayın"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Masaüstü Görünüş)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranı maksimum böyüdün"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Ölçüsünü dəyişin"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Tətbiqi bura köçürmək mümkün deyil"</string> diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml index 4ee7d7ee92bb..4af564833ba1 100644 --- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml +++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problem nije rešen?\nDodirnite da biste vratili"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemate problema sa kamerom? Dodirnite da biste odbacili."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Meni aplikacije možete da pronađete ovde"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Uđite u prikaz za računare da biste istovremeno otvorili više aplikacija"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Vratite se na ceo ekran bilo kada iz menija aplikacije"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Vidite i uradite više"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Prevucite drugu aplikaciju da biste koristili podeljeni ekran"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Identifikator aplikacije"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Preko celog ekrana"</string> - <string name="desktop_text" msgid="1582173066857454541">"Prikaz za računare"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Podeljeni ekran"</string> <string name="more_button_text" msgid="3655388105592893530">"Još"</string> <string name="float_button_text" msgid="9221657008391364581">"Plutajuće"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Promeni razmeru"</string> <string name="close_text" msgid="4986518933445178928">"Zatvorite"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite meni"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (prikaz za računare)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Povećaj ekran"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Prilagodi"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacija ne može da se premesti ovde"</string> diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml index d686da96d3d8..7719396b01d1 100644 --- a/libs/WindowManager/Shell/res/values-be/strings.xml +++ b/libs/WindowManager/Shell/res/values-be/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не ўдалося выправіць?\nНацісніце, каб аднавіць"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ніякіх праблем з камерай? Націсніце, каб адхіліць."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Меню праграмы шукайце тут"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Каб адкрыць некалькі праграм адначасова, увайдзіце ў версію для камп’ютараў"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Вы можаце вярнуцца ў поўнаэкранны рэжым у любы час з меню праграмы"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Адначасова выконвайце розныя задачы"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Перацягніце іншую праграму, каб выкарыстоўваць падзелены экран"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Маркер праграмы"</string> <string name="app_icon_text" msgid="2823268023931811747">"Значок праграмы"</string> <string name="fullscreen_text" msgid="1162316685217676079">"На ўвесь экран"</string> - <string name="desktop_text" msgid="1582173066857454541">"Версія для камп’ютараў"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Падзяліць экран"</string> <string name="more_button_text" msgid="3655388105592893530">"Яшчэ"</string> <string name="float_button_text" msgid="9221657008391364581">"Зрабіць рухомым акном"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Змяніць суадносіны бакоў"</string> <string name="close_text" msgid="4986518933445178928">"Закрыць"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Закрыць меню"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (версія для камп’ютараў)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Разгарнуць на ўвесь экран"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Змяніць памер"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Нельга перамясціць сюды праграму"</string> diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml index 984c20ff5dba..514556e30fe0 100644 --- a/libs/WindowManager/Shell/res/values-bg/strings.xml +++ b/libs/WindowManager/Shell/res/values-bg/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблемът не се отстрани?\nДокоснете за връщане в предишното състояние"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нямате проблеми с камерата? Докоснете, за да отхвърлите."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Можете да намерите менюто на приложението тук"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Активирайте изгледа за настолни компютри, за да отворите няколко приложения едновременно"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Преминете към цял екран по всяко време от менюто на приложението"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Преглеждайте и правете повече неща"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Преместете друго приложение с плъзгане, за да преминете в режим за разделен екран"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Манипулатор за приложението"</string> <string name="app_icon_text" msgid="2823268023931811747">"Икона на приложението"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Цял екран"</string> - <string name="desktop_text" msgid="1582173066857454541">"Изглед за настолни компютри"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Разделяне на екрана"</string> <string name="more_button_text" msgid="3655388105592893530">"Още"</string> <string name="float_button_text" msgid="9221657008391364581">"Плаващо"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Промяна на съотношението"</string> <string name="close_text" msgid="4986518933445178928">"Затваряне"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Затваряне на менюто"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (изглед за настолни компютри)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Увеличаване на екрана"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Нов размер"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Приложението не може да бъде преместено тук"</string> diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml index dd5653c48464..d4488a220ac7 100644 --- a/libs/WindowManager/Shell/res/values-bn/strings.xml +++ b/libs/WindowManager/Shell/res/values-bn/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"এখনও সমাধান হয়নি?\nরিভার্ট করার জন্য ট্যাপ করুন"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ক্যামেরা সংক্রান্ত সমস্যা নেই? বাতিল করতে ট্যাপ করুন।"</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"অ্যাপ মেনু এখানে খুঁজে পাওয়া যাবে"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"একসাথে একাধিক অ্যাপ খোলার জন্য ডেস্কটপ ভিউতে যান"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"অ্যাপ মেনু থেকে ফুল-স্ক্রিন মোডে যেকোনও সময়ে ফিরে আসুন"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"দেখুন ও আরও অনেক কিছু করুন"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"স্প্লিট স্ক্রিনের ক্ষেত্রে অন্য কোনও অ্যাপ টেনে আনুন"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"অ্যাপের হ্যান্ডেল"</string> <string name="app_icon_text" msgid="2823268023931811747">"অ্যাপ আইকন"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ফুলস্ক্রিন"</string> - <string name="desktop_text" msgid="1582173066857454541">"ডেস্কটপ ভিউ"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"স্প্লিট স্ক্রিন"</string> <string name="more_button_text" msgid="3655388105592893530">"আরও"</string> <string name="float_button_text" msgid="9221657008391364581">"ফ্লোট"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"অ্যাস্পেক্ট রেশিও পরিবর্তন করুন"</string> <string name="close_text" msgid="4986518933445178928">"বন্ধ করুন"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"\'মেনু\' বন্ধ করুন"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ডেস্কটপ ভিউ)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"স্ক্রিন বড় করুন"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ছোট বড় করুন"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"অ্যাপটি এখানে সরানো যাবে না"</string> diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml index 01e0515dfa16..23c467c0b4ba 100644 --- a/libs/WindowManager/Shell/res/values-bs/strings.xml +++ b/libs/WindowManager/Shell/res/values-bs/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nije popravljeno?\nDodirnite da vratite"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nema problema s kamerom? Dodirnite da odbacite."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Ovdje možete pronaći meni aplikacije"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Ulazak u prikaz na računaru radi istovremenog otvaranja više aplikacija"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Povratak na prikaz preko cijelog ekrana bilo kada putem menija aplikacije"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Pogledajte i učinite više"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Prevucite još jednu aplikaciju za podijeljeni ekran"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Ručica aplikacije"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Cijeli ekran"</string> - <string name="desktop_text" msgid="1582173066857454541">"Prikaz na računaru"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Podijeljeni ekran"</string> <string name="more_button_text" msgid="3655388105592893530">"Više"</string> <string name="float_button_text" msgid="9221657008391364581">"Lebdeći"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Promjena formata slike"</string> <string name="close_text" msgid="4986518933445178928">"Zatvaranje"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvaranje menija"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (prikaz na računaru)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimiziraj ekran"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Promijeni veličinu"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ne možete premjestiti aplikaciju ovdje"</string> diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml index 77cf94b84450..893d16e6155e 100644 --- a/libs/WindowManager/Shell/res/values-ca/strings.xml +++ b/libs/WindowManager/Shell/res/values-ca/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"El problema no s\'ha resolt?\nToca per desfer els canvis"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No tens cap problema amb la càmera? Toca per ignorar."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Pots trobar el menú de l\'aplicació aquí"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Accedeix a la visualització per a ordinadors per obrir diverses aplicacions alhora"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Torna a la pantalla completa en qualsevol moment des del menú de l\'aplicació"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Consulta i fes més coses"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arrossega una altra aplicació per utilitzar la pantalla dividida"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Identificador de l\'aplicació"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icona de l\'aplicació"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pantalla completa"</string> - <string name="desktop_text" msgid="1582173066857454541">"Visualització per a ordinadors"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Pantalla dividida"</string> <string name="more_button_text" msgid="3655388105592893530">"Més"</string> <string name="float_button_text" msgid="9221657008391364581">"Flotant"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Canvia la relació d\'aspecte"</string> <string name="close_text" msgid="4986518933445178928">"Tanca"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Tanca el menú"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (visualització per a ordinadors)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximitza la pantalla"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Canvia la mida"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"L\'aplicació no es pot moure aquí"</string> diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml index 1a414ba89fdc..a96344a0a365 100644 --- a/libs/WindowManager/Shell/res/values-cs/strings.xml +++ b/libs/WindowManager/Shell/res/values-cs/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nepomohlo to?\nKlepnutím se vrátíte"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Žádné problémy s fotoaparátem? Klepnutím zavřete."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Najdete tu nabídku aplikace"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Pokud chcete otevřít několik aplikací současně, přejděte na zobrazení na počítači"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Na celou obrazovku se můžete kdykoli vrátit z nabídky aplikace"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Lepší zobrazení a více možností"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Přetáhnutím druhé aplikace použijete rozdělenou obrazovku"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Popisovač aplikace"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikace"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Celá obrazovka"</string> - <string name="desktop_text" msgid="1582173066857454541">"Zobrazení na počítači"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Rozdělená obrazovka"</string> <string name="more_button_text" msgid="3655388105592893530">"Více"</string> <string name="float_button_text" msgid="9221657008391364581">"Plovoucí"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Změnit poměr stran"</string> <string name="close_text" msgid="4986518933445178928">"Zavřít"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zavřít nabídku"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (zobrazení na počítači)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximalizovat obrazovku"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Změnit velikost"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikaci sem nelze přesunout"</string> diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml index 07f1969ec9c6..7d28fc842e59 100644 --- a/libs/WindowManager/Shell/res/values-da/strings.xml +++ b/libs/WindowManager/Shell/res/values-da/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Løste det ikke problemet?\nTryk for at fortryde"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Har du ingen problemer med dit kamera? Tryk for at afvise."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Appmenuen kan findes her"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Gå til computervenlig visning for at åbne flere apps på én gang"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Gå tilbage til fuld skærm når som helst via appmenuen"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Se og gør mere"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Træk en anden app hertil for at bruge opdelt skærm"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Apphåndtag"</string> <string name="app_icon_text" msgid="2823268023931811747">"Appikon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Fuld skærm"</string> - <string name="desktop_text" msgid="1582173066857454541">"Computervenlig visning"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Opdelt skærm"</string> <string name="more_button_text" msgid="3655388105592893530">"Mere"</string> <string name="float_button_text" msgid="9221657008391364581">"Svævende"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Skift billedformat"</string> <string name="close_text" msgid="4986518933445178928">"Luk"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Luk menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (computervenlig visning)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimér skærm"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Tilpas størrelse"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Apps kan ikke flyttes hertil"</string> diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml index 7a8f2d984457..4cc11243b8bd 100644 --- a/libs/WindowManager/Shell/res/values-de/strings.xml +++ b/libs/WindowManager/Shell/res/values-de/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Das Problem ist nicht behoben?\nZum Rückgängigmachen tippen."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Keine Probleme mit der Kamera? Zum Schließen tippen."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Das App-Menü findest du hier"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Über die Desktop-Ansicht kannst du mehrere Apps gleichzeitig öffnen"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Über das App-Menü kannst du jederzeit zum Vollbildmodus zurückkehren"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Mehr sehen und erledigen"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Für Splitscreen-Modus weitere App hineinziehen"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"App-Ziehpunkt"</string> <string name="app_icon_text" msgid="2823268023931811747">"App-Symbol"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Vollbild"</string> - <string name="desktop_text" msgid="1582173066857454541">"Desktop-Ansicht"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Splitscreen"</string> <string name="more_button_text" msgid="3655388105592893530">"Mehr"</string> <string name="float_button_text" msgid="9221657008391364581">"Frei schwebend"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Seitenverhältnis ändern"</string> <string name="close_text" msgid="4986518933445178928">"Schließen"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Menü schließen"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Desktop-Ansicht)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Bildschirm maximieren"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Größe ändern"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Die App kann nicht hierher verschoben werden"</string> diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml index e2477d35881c..0fb17ecdb278 100644 --- a/libs/WindowManager/Shell/res/values-el/strings.xml +++ b/libs/WindowManager/Shell/res/values-el/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Δεν διορθώθηκε;\nΠατήστε για επαναφορά."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Δεν αντιμετωπίζετε προβλήματα με την κάμερα; Πατήστε για παράβλεψη."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Μπορείτε να βρείτε το μενού εφαρμογών εδώ"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Μεταβείτε στην προβολή για υπολογιστές, για να ανοίξετε πολλές εφαρμογές μαζί"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Επιστρέψτε στην πλήρη οθόνη ανά πάσα στιγμή από το μενού της εφαρμογής"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Δείτε και κάντε περισσότερα"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Σύρετε σε μια άλλη εφαρμογή για διαχωρισμό οθόνης."</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Λαβή εφαρμογής"</string> <string name="app_icon_text" msgid="2823268023931811747">"Εικονίδιο εφαρμογής"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Πλήρης οθόνη"</string> - <string name="desktop_text" msgid="1582173066857454541">"Προβολή για υπολογιστές"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Διαχωρισμός οθόνης"</string> <string name="more_button_text" msgid="3655388105592893530">"Περισσότερα"</string> <string name="float_button_text" msgid="9221657008391364581">"Κινούμενο"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Αλλαγή λόγου διαστάσεων"</string> <string name="close_text" msgid="4986518933445178928">"Κλείσιμο"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Κλείσιμο μενού"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Προβολή για υπολογιστές)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Μεγιστοποίηση οθόνης"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Αλλαγή μεγέθους"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Δεν είναι δυνατή η μετακίνηση της εφαρμογής εδώ"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml index bed6e5058a9f..2087bb4ad579 100644 --- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"The app menu can be found here"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Enter desktop view to open multiple apps together"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Return to full screen at any time from the app menu"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Drag in another app for split screen"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"App handle"</string> <string name="app_icon_text" msgid="2823268023931811747">"App icon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Full screen"</string> - <string name="desktop_text" msgid="1582173066857454541">"Desktop view"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Split screen"</string> <string name="more_button_text" msgid="3655388105592893530">"More"</string> <string name="float_button_text" msgid="9221657008391364581">"Float"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string> <string name="close_text" msgid="4986518933445178928">"Close"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (desktop view)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Resize"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml index 9b9294dbeba8..8abb9dffec67 100644 --- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"The app menu can be found here"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Enter desktop view to open multiple apps together"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Return to full screen anytime from the app menu"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Drag in another app for split screen"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"App handle"</string> <string name="app_icon_text" msgid="2823268023931811747">"App Icon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Fullscreen"</string> - <string name="desktop_text" msgid="1582173066857454541">"Desktop View"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Split Screen"</string> <string name="more_button_text" msgid="3655388105592893530">"More"</string> <string name="float_button_text" msgid="9221657008391364581">"Float"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string> <string name="close_text" msgid="4986518933445178928">"Close"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Close Menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Desktop View)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximize Screen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Resize"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml index bed6e5058a9f..2087bb4ad579 100644 --- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"The app menu can be found here"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Enter desktop view to open multiple apps together"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Return to full screen at any time from the app menu"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Drag in another app for split screen"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"App handle"</string> <string name="app_icon_text" msgid="2823268023931811747">"App icon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Full screen"</string> - <string name="desktop_text" msgid="1582173066857454541">"Desktop view"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Split screen"</string> <string name="more_button_text" msgid="3655388105592893530">"More"</string> <string name="float_button_text" msgid="9221657008391364581">"Float"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string> <string name="close_text" msgid="4986518933445178928">"Close"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (desktop view)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Resize"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml index bed6e5058a9f..2087bb4ad579 100644 --- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"The app menu can be found here"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Enter desktop view to open multiple apps together"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Return to full screen at any time from the app menu"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Drag in another app for split screen"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"App handle"</string> <string name="app_icon_text" msgid="2823268023931811747">"App icon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Full screen"</string> - <string name="desktop_text" msgid="1582173066857454541">"Desktop view"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Split screen"</string> <string name="more_button_text" msgid="3655388105592893530">"More"</string> <string name="float_button_text" msgid="9221657008391364581">"Float"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string> <string name="close_text" msgid="4986518933445178928">"Close"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (desktop view)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Resize"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string> diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml index 2b7769d19168..bb70f6e419a5 100644 --- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml +++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"¿No se resolvió?\nPresiona para revertir los cambios"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"¿No tienes problemas con la cámara? Presionar para descartar."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"El menú de la app se encuentra aquí"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Entra a la vista de escritorio para abrir varias apps a la vez"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Regresa a pantalla completa en cualquier momento desde el menú de la app"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Aprovecha más"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arrastra otra app para el modo de pantalla dividida"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Controlador de la app"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ícono de la app"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pantalla completa"</string> - <string name="desktop_text" msgid="1582173066857454541">"Vista para computadoras de escritorio"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Pantalla dividida"</string> <string name="more_button_text" msgid="3655388105592893530">"Más"</string> <string name="float_button_text" msgid="9221657008391364581">"Flotante"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambiar relación de aspecto"</string> <string name="close_text" msgid="4986518933445178928">"Cerrar"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (vista para computadoras de escritorio)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Dividir pantalla"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"No se puede mover la app aquí"</string> diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml index afb1034551b3..a6595aa9292d 100644 --- a/libs/WindowManager/Shell/res/values-es/strings.xml +++ b/libs/WindowManager/Shell/res/values-es/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"¿No se ha solucionado?\nToca para revertir"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"¿No hay problemas con la cámara? Toca para cerrar."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"El menú de la aplicación se encuentra aquí"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Entra en la vista para ordenador si quieres abrir varias aplicaciones a la vez"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Vuelve a la pantalla completa en cualquier momento desde el menú de aplicaciones"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Consulta más información y haz más"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arrastra otra aplicación para activar la pantalla dividida"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Controlador de la aplicación"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icono de la aplicación"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pantalla completa"</string> - <string name="desktop_text" msgid="1582173066857454541">"Vista para ordenadores"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Pantalla dividida"</string> <string name="more_button_text" msgid="3655388105592893530">"Más"</string> <string name="float_button_text" msgid="9221657008391364581">"Flotante"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambiar relación de aspecto"</string> <string name="close_text" msgid="4986518933445178928">"Cerrar"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (vista para ordenadores)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Dividir pantalla"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"La aplicación no se puede mover aquí"</string> diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml index 61ca3e0db920..36086578dd4d 100644 --- a/libs/WindowManager/Shell/res/values-et/strings.xml +++ b/libs/WindowManager/Shell/res/values-et/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Kas probleemi ei lahendatud?\nPuudutage ennistamiseks."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kas kaameraprobleeme pole? Puudutage loobumiseks."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Rakenduse menüü leiate siit"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Mitme rakenduse koos avamiseks avage arvutivaade"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Saate rakenduse menüüst igal ajal täisekraanile naasta"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Vaadake ja tehke rohkem"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Lohistage muusse rakendusse, et jagatud ekraanikuva kasutada"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Rakenduse element"</string> <string name="app_icon_text" msgid="2823268023931811747">"Rakenduse ikoon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Täisekraan"</string> - <string name="desktop_text" msgid="1582173066857454541">"Arvutivaade"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Jagatud ekraanikuva"</string> <string name="more_button_text" msgid="3655388105592893530">"Rohkem"</string> <string name="float_button_text" msgid="9221657008391364581">"Hõljuv"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Kuvasuhte muutmine"</string> <string name="close_text" msgid="4986518933445178928">"Sule"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Sule menüü"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (arvutivaade)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Kuva täisekraanil"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Suuruse muutmine"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Rakendust ei saa siia teisaldada"</string> diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml index af175bc9d08e..446839a8eb06 100644 --- a/libs/WindowManager/Shell/res/values-eu/strings.xml +++ b/libs/WindowManager/Shell/res/values-eu/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ez al da konpondu?\nLeheneratzeko, sakatu hau."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ez daukazu arazorik kamerarekin? Baztertzeko, sakatu hau."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Aplikazioaren menua dago hemen"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Sartu ordenagailuetarako ikuspegian aplikazio bat baino gehiago batera irekitzeko"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Pantaila osoko modura itzultzeko, erabili aplikazioaren menua"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Ikusi eta egin gauza gehiago"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Pantaila zatitua ikusteko, arrastatu beste aplikazio bat"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Aplikazioaren kontrol-puntua"</string> <string name="app_icon_text" msgid="2823268023931811747">"Aplikazioaren ikonoa"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pantaila osoa"</string> - <string name="desktop_text" msgid="1582173066857454541">"Ordenagailuetarako ikuspegia"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Pantaila zatitzea"</string> <string name="more_button_text" msgid="3655388105592893530">"Gehiago"</string> <string name="float_button_text" msgid="9221657008391364581">"Leiho gainerakorra"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Aldatu aspektu-erlazioa"</string> <string name="close_text" msgid="4986518933445178928">"Itxi"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Itxi menua"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ordenagailuetarako ikuspegia)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Handitu pantaila"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Aldatu tamaina"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikazioa ezin da hona ekarri"</string> diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml index 4df47c1dd2cf..bf5c8f95cfb3 100644 --- a/libs/WindowManager/Shell/res/values-fa/strings.xml +++ b/libs/WindowManager/Shell/res/values-fa/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"مشکل برطرف نشد؟\nبرای برگرداندن تکضرب بزنید"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"دوربین مشکلی ندارد؟ برای بستن تکضرب بزنید."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"منو برنامه را میتوانید اینجا ببینید"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"برای باز کردن همزمان چند برنامه، وارد نمای ویژه رایانه شوید"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"هروقت خواستید از منو برنامه به حالت تمامصفحه برگردید"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"از چندین برنامه بهطور همزمان استفاده کنید"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"برای حالت صفحهٔ دونیمه، در برنامهای دیگر بکشید"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"دستگیره برنامه"</string> <string name="app_icon_text" msgid="2823268023931811747">"نماد برنامه"</string> <string name="fullscreen_text" msgid="1162316685217676079">"تمامصفحه"</string> - <string name="desktop_text" msgid="1582173066857454541">"نمای ویژه رایانه رومیزی"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"صفحهٔ دونیمه"</string> <string name="more_button_text" msgid="3655388105592893530">"بیشتر"</string> <string name="float_button_text" msgid="9221657008391364581">"شناور"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"تغییر نسبت ابعادی"</string> <string name="close_text" msgid="4986518933445178928">"بستن"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"بستن منو"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (نمای ویژه رایانه رومیزی)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"بزرگ کردن صفحه"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"تغییر اندازه"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"برنامه را نمیتوان به اینجا منتقل کرد"</string> diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml index 7da06bd50378..a32e4fab9d81 100644 --- a/libs/WindowManager/Shell/res/values-fi/strings.xml +++ b/libs/WindowManager/Shell/res/values-fi/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Eikö ongelma ratkennut?\nKumoa napauttamalla"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ei ongelmia kameran kanssa? Hylkää napauttamalla."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Sovellusvalikko löytyy täältä"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Siirry työpöytänäkymään, niin voit avata useita sovelluksia kerralla"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Voit palata koko näytön tilaan milloin tahansa sovellusvalikosta"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Näe ja tee enemmän"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Käytä jaettua näyttöä vetämällä tähän toinen sovellus"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Sovelluksen tunnus"</string> <string name="app_icon_text" msgid="2823268023931811747">"Sovelluskuvake"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Koko näyttö"</string> - <string name="desktop_text" msgid="1582173066857454541">"Tietokonenäkymä"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Jaettu näyttö"</string> <string name="more_button_text" msgid="3655388105592893530">"Lisää"</string> <string name="float_button_text" msgid="9221657008391364581">"Kelluva ikkuna"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Vaihda kuvasuhdetta"</string> <string name="close_text" msgid="4986518933445178928">"Sulje"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Sulje valikko"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (tietokonenäkymä)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Suurenna näyttö"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Muuta kokoa"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Sovellusta ei voi siirtää tänne"</string> diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml index d0fac37dc8ed..7037377156c6 100644 --- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problème non résolu?\nTouchez pour rétablir"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Aucun problème d\'appareil photo? Touchez pour ignorer."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Le menu de l\'appli se trouve ici"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Accéder à l\'affichage sur un ordinateur de bureau pour ouvrir plusieurs applis simultanément"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Revenir au mode Plein écran à tout moment à partir du menu de l\'appli"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Voir et en faire plus"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Faites glisser une autre appli pour utiliser l\'écran partagé"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Poignée de l\'appli"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icône de l\'appli"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Plein écran"</string> - <string name="desktop_text" msgid="1582173066857454541">"Affichage sur un ordinateur de bureau"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Écran divisé"</string> <string name="more_button_text" msgid="3655388105592893530">"Plus"</string> <string name="float_button_text" msgid="9221657008391364581">"Flottant"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Modifier les proportions"</string> <string name="close_text" msgid="4986518933445178928">"Fermer"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Fermer le menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (affichage sur un ordinateur de bureau)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Agrandir l\'écran"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Redimensionner"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Impossible de déplacer l\'appli ici"</string> diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml index 91dc6de3a27f..fb2ebfd55583 100644 --- a/libs/WindowManager/Shell/res/values-fr/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problème non résolu ?\nAppuyez pour rétablir"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Aucun problème d\'appareil photo ? Appuyez pour ignorer."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Le menu de l\'application se trouve ici"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Passer à l\'affichage sur ordinateur pour ouvrir plusieurs applications simultanément"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Revenir en plein écran à tout moment depuis le menu de l\'application"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Voir et interagir plus"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Faites glisser une autre appli pour utiliser l\'écran partagé"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Poignée de l\'appli"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icône d\'application"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Plein écran"</string> - <string name="desktop_text" msgid="1582173066857454541">"Affichage sur ordinateur"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Écran partagé"</string> <string name="more_button_text" msgid="3655388105592893530">"Plus"</string> <string name="float_button_text" msgid="9221657008391364581">"Flottante"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Modifier le format"</string> <string name="close_text" msgid="4986518933445178928">"Fermer"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Fermer le menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (affichage sur ordinateur)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Mettre en plein écran"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Redimensionner"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Impossible de déplacer l\'appli ici"</string> diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml index e315648c598d..895cf47e3d53 100644 --- a/libs/WindowManager/Shell/res/values-gl/strings.xml +++ b/libs/WindowManager/Shell/res/values-gl/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Non se solucionaron os problemas?\nToca para reverter o seu tratamento"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Non hai problemas coa cámara? Tocar para ignorar."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Aquí podes ver o menú da aplicación"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Vai á vista para ordenadores se queres abrir varias aplicacións á vez"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Volve á pantalla completa en calquera momento desde o menú da aplicación"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Ver e facer máis"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arrastra outra aplicación para usar a pantalla dividida"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Controlador da aplicación"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icona de aplicación"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pantalla completa"</string> - <string name="desktop_text" msgid="1582173066857454541">"Vista para ordenadores"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Pantalla dividida"</string> <string name="more_button_text" msgid="3655388105592893530">"Máis"</string> <string name="float_button_text" msgid="9221657008391364581">"Flotante"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambiar a proporción"</string> <string name="close_text" msgid="4986518933445178928">"Pechar"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Pechar o menú"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (vista para ordenadores)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Cambiar tamaño"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Non se pode mover aquí a aplicación"</string> diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml index cd7550893dca..9c8cf96be294 100644 --- a/libs/WindowManager/Shell/res/values-gu/strings.xml +++ b/libs/WindowManager/Shell/res/values-gu/strings.xml @@ -102,7 +102,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"સુધારો નથી થયો?\nપહેલાંના પર પાછું ફેરવવા માટે ટૅપ કરો"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"કૅમેરામાં કોઈ સમસ્યા નથી? છોડી દેવા માટે ટૅપ કરો."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"ઍપ મેનૂ અહીં જોવા મળી શકે છે"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"એકથી વધુ ઍપ એકસાથે ખોલવા માટે ડેસ્કટૉપ વ્યૂ દાખલ કરો"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"ઍપ મેનૂમાંથી કોઈપણ સમયે પૂર્ણ સ્ક્રીન પર પાછા ફરો"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"જુઓ અને બીજું ઘણું કરો"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"વિભાજિત સ્ક્રીન માટે કોઈ અન્ય ઍપમાં ખેંચો"</string> @@ -127,7 +128,8 @@ <string name="handle_text" msgid="4419667835599523257">"ઍપનું હૅન્ડલ"</string> <string name="app_icon_text" msgid="2823268023931811747">"ઍપનું આઇકન"</string> <string name="fullscreen_text" msgid="1162316685217676079">"પૂર્ણસ્ક્રીન"</string> - <string name="desktop_text" msgid="1582173066857454541">"ડેસ્કટૉપ વ્યૂ"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"સ્ક્રીનને વિભાજિત કરો"</string> <string name="more_button_text" msgid="3655388105592893530">"વધુ"</string> <string name="float_button_text" msgid="9221657008391364581">"ફ્લોટિંગ વિન્ડો"</string> @@ -140,7 +142,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"સાપેક્ષ ગુણોત્તર બદલો"</string> <string name="close_text" msgid="4986518933445178928">"બંધ કરો"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"મેનૂ બંધ કરો"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ડેસ્કટૉપ વ્યૂ)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"સ્ક્રીન કરો મોટી કરો"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"કદ બદલો"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ઍપ અહીં ખસેડી શકાતી નથી"</string> diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml index cbcb2674c6b4..985dafffa68a 100644 --- a/libs/WindowManager/Shell/res/values-hi/strings.xml +++ b/libs/WindowManager/Shell/res/values-hi/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"क्या समस्या ठीक नहीं हुई?\nपहले जैसा करने के लिए टैप करें"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"क्या कैमरे से जुड़ी कोई समस्या नहीं है? खारिज करने के लिए टैप करें."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"ऐप्लिकेशन मेन्यू यहां पाया जा सकता है"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"एक साथ कई ऐप्लिकेशन खोलने के लिए, डेस्कटॉप व्यू में जाएं"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"ऐप्लिकेशन मेन्यू से फ़ुल स्क्रीन मोड पर किसी भी समय वापस जाएं"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"पूरी जानकारी लेकर, बेहतर तरीके से काम करें"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"स्प्लिट स्क्रीन का इस्तेमाल करने के लिए, किसी अन्य ऐप्लिकेशन को खींचें और छोड़ें"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"ऐप्लिकेशन का हैंडल"</string> <string name="app_icon_text" msgid="2823268023931811747">"ऐप्लिकेशन आइकॉन"</string> <string name="fullscreen_text" msgid="1162316685217676079">"फ़ुलस्क्रीन"</string> - <string name="desktop_text" msgid="1582173066857454541">"डेस्कटॉप व्यू"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"स्प्लिट स्क्रीन मोड"</string> <string name="more_button_text" msgid="3655388105592893530">"ज़्यादा देखें"</string> <string name="float_button_text" msgid="9221657008391364581">"फ़्लोट"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) बदलें"</string> <string name="close_text" msgid="4986518933445178928">"बंद करें"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"मेन्यू बंद करें"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (डेस्कटॉप व्यू)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रीन को बड़ा करें"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"साइज़ बदलें"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ऐप्लिकेशन को यहां मूव नहीं किया जा सकता"</string> diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml index 0eed0a422cf1..4640bf3b8293 100644 --- a/libs/WindowManager/Shell/res/values-hr/strings.xml +++ b/libs/WindowManager/Shell/res/values-hr/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problem nije riješen?\nDodirnite za vraćanje"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemate problema s fotoaparatom? Dodirnite za odbacivanje."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Izbornik aplikacije možete pronaći ovdje"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Otvorite prikaz na računalu da biste otvorili više aplikacija zajedno"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Vratite se na cijeli zaslon bilo kad iz izbornika aplikacije"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Gledajte i učinite više"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Povucite drugu aplikaciju unutra da biste podijelili zaslon"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Pokazivač aplikacije"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Puni zaslon"</string> - <string name="desktop_text" msgid="1582173066857454541">"Prikaz na računalu"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Razdvojeni zaslon"</string> <string name="more_button_text" msgid="3655388105592893530">"Više"</string> <string name="float_button_text" msgid="9221657008391364581">"Plutajući"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Promijeni omjer slike"</string> <string name="close_text" msgid="4986518933445178928">"Zatvorite"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite izbornik"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (prikaz na računalu)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimalno povećaj zaslon"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Promijeni veličinu"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacija se ne može premjestiti ovdje"</string> diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml index 48d5afd778c3..711e2f0bfbbe 100644 --- a/libs/WindowManager/Shell/res/values-hu/strings.xml +++ b/libs/WindowManager/Shell/res/values-hu/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nem sikerült a hiba kijavítása?\nKoppintson a visszaállításhoz."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nincsenek problémái kamerával? Koppintson az elvetéshez."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Az alkalmazásmenü itt található"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Asztali nézetbe lépve több alkalmazást nyithat meg egyidejűleg"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Az alkalmazásmenüből bármikor visszatérhet a teljes képernyőre"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Több mindent láthat és tehet"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Húzzon ide egy másik alkalmazást az osztott képernyő használatához"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"App fogópontja"</string> <string name="app_icon_text" msgid="2823268023931811747">"Alkalmazásikon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Teljes képernyő"</string> - <string name="desktop_text" msgid="1582173066857454541">"Asztali nézet"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Osztott képernyő"</string> <string name="more_button_text" msgid="3655388105592893530">"Továbbiak"</string> <string name="float_button_text" msgid="9221657008391364581">"Lebegő"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Méretarány módosítása"</string> <string name="close_text" msgid="4986518933445178928">"Bezárás"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Menü bezárása"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Asztali nézet)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Képernyő méretének maximalizálása"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Átméretezés"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Az alkalmazás nem helyezhető át ide"</string> diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml index bf1e840179d5..d7b1b07b6917 100644 --- a/libs/WindowManager/Shell/res/values-hy/strings.xml +++ b/libs/WindowManager/Shell/res/values-hy/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Չհաջողվե՞ց շտկել։\nՀպեք՝ փոփոխությունները չեղարկելու համար։"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Տեսախցիկի հետ կապված խնդիրներ չկա՞ն։ Փակելու համար հպեք։"</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Հավելվածի ընտրացանկն այստեղ է"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Անցեք համակարգչային տարբերակին՝ միաժամանակ մի քանի հավելված բացելու համար"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Ցանկացած ժամանակ հավելվածի ընտրացանկից վերադարձեք լիաէկրան ռեժիմ"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Միաժամանակ կատարեք մի քանի առաջադրանք"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Քաշեք մյուս հավելվածի մեջ՝ էկրանի տրոհումն օգտագործելու համար"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Հավելվածի կեղծանուն"</string> <string name="app_icon_text" msgid="2823268023931811747">"Հավելվածի պատկերակ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Լիաէկրան"</string> - <string name="desktop_text" msgid="1582173066857454541">"Համակարգչային տարբերակ"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Տրոհված էկրան"</string> <string name="more_button_text" msgid="3655388105592893530">"Ավելին"</string> <string name="float_button_text" msgid="9221657008391364581">"Լողացող պատուհան"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Փոխել կողմերի հարաբերակցությունը"</string> <string name="close_text" msgid="4986518933445178928">"Փակել"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Փակել ընտրացանկը"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (համակարգչային տարբերակ)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ծավալել էկրանը"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Փոխել չափը"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Հավելվածը հնարավոր չէ տեղափոխել այստեղ"</string> diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml index d658f59ec9e3..1d1927f9dfbc 100644 --- a/libs/WindowManager/Shell/res/values-in/strings.xml +++ b/libs/WindowManager/Shell/res/values-in/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Tidak dapat diperbaiki?\nKetuk untuk mengembalikan"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Tidak ada masalah kamera? Ketuk untuk menutup."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Menu aplikasi dapat ditemukan di sini"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Buka tampilan desktop untuk membuka beberapa aplikasi secara bersamaan"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Kembali ke layar penuh kapan saja dari menu aplikasi"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Lihat dan lakukan lebih banyak hal"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Tarik aplikasi lain untuk menggunakan layar terpisah"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Penanganan aplikasi"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikon Aplikasi"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Layar Penuh"</string> - <string name="desktop_text" msgid="1582173066857454541">"Tampilan Desktop"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Layar Terpisah"</string> <string name="more_button_text" msgid="3655388105592893530">"Lainnya"</string> <string name="float_button_text" msgid="9221657008391364581">"Mengambang"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Ubah rasio aspek"</string> <string name="close_text" msgid="4986518933445178928">"Tutup"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Tutup Menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Tampilan Desktop)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Perbesar Layar"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Ubah ukuran"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikasi tidak dapat dipindahkan ke sini"</string> diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml index f7b78d2222f5..e94a4c8a08ea 100644 --- a/libs/WindowManager/Shell/res/values-is/strings.xml +++ b/libs/WindowManager/Shell/res/values-is/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ennþá vesen?\nÝttu til að afturkalla"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ekkert myndavélavesen? Ýttu til að hunsa."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Hér finnurðu forritavalmyndina"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Veldu tölvuútgáfu til að opna mörg forrit samtímis"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Þú getur skipt aftur í allan skjáinn hvenær sem er af forritavalmyndinni"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Sjáðu og gerðu meira"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Dragðu annað forrit inn til að nota skjáskiptingu"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Handfang forrits"</string> <string name="app_icon_text" msgid="2823268023931811747">"Tákn forrits"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Allur skjárinn"</string> - <string name="desktop_text" msgid="1582173066857454541">"Tölvuútgáfa"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Skjáskipting"</string> <string name="more_button_text" msgid="3655388105592893530">"Meira"</string> <string name="float_button_text" msgid="9221657008391364581">"Reikult"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Breyta myndhlutfalli"</string> <string name="close_text" msgid="4986518933445178928">"Loka"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Loka valmynd"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (tölvuútgáfa)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Stækka skjá"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Breyta stærð"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ekki er hægt að færa forritið hingað"</string> diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml index a2787a7e7b91..5f8334fa011c 100644 --- a/libs/WindowManager/Shell/res/values-it/strings.xml +++ b/libs/WindowManager/Shell/res/values-it/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Il problema non si è risolto?\nTocca per ripristinare"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nessun problema con la fotocamera? Tocca per ignorare."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Il menu dell\'app si trova qui"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Entra nella visualizzazione desktop per aprire più app contemporaneamente"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Torna allo schermo intero in qualsiasi momento dal menu dell\'app"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Visualizza più contenuti e fai di più"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Trascina in un\'altra app per usare lo schermo diviso"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Punto di manipolazione app"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icona dell\'app"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Schermo intero"</string> - <string name="desktop_text" msgid="1582173066857454541">"Visualizzazione desktop"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Schermo diviso"</string> <string name="more_button_text" msgid="3655388105592893530">"Altro"</string> <string name="float_button_text" msgid="9221657008391364581">"Mobile"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambia proporzioni"</string> <string name="close_text" msgid="4986518933445178928">"Chiudi"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Chiudi il menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (visualizzazione desktop)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Massimizza schermo"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Ridimensiona"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Impossibile spostare l\'app qui"</string> diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml index 36ac62091e43..c3e85230c319 100644 --- a/libs/WindowManager/Shell/res/values-iw/strings.xml +++ b/libs/WindowManager/Shell/res/values-iw/strings.xml @@ -43,10 +43,8 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"שמאלה 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"שמאלה 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"מסך ימני מלא"</string> - <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) --> - <skip /> - <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) --> - <skip /> + <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"החלפה בין האפליקציה העליונה לבין האפליקציה התחתונה"</string> + <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"החלפה בין האפליקציה השמאלית לבין האפליקציה הימנית"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"מסך עליון מלא"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"עליון 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"עליון 50%"</string> @@ -102,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"הבעיה לא נפתרה?\nאפשר ללחוץ כדי לחזור לגרסה הקודמת"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"אין בעיות במצלמה? אפשר ללחוץ כדי לסגור."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"תפריט האפליקציה נמצא כאן"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"כדי לפתוח כמה אפליקציות יחד, צריך לעבור למצב תצוגה למחשב"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"אפשר לחזור למסך מלא בכל שלב מתפריט האפליקציה"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"רוצה לראות ולעשות יותר?"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"צריך לגרור אפליקציה אחרת כדי להשתמש במסך המפוצל"</string> @@ -115,19 +114,16 @@ <string name="letterbox_restart_restart" msgid="8529976234412442973">"הפעלה מחדש"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"לא להציג שוב"</string> <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"אפשר ללחוץ לחיצה כפולה כדי\nלהעביר את האפליקציה למקום אחר"</string> - <!-- no translation found for maximize_button_text (8106849394538234709) --> - <skip /> - <!-- no translation found for restore_button_text (5377571986086775288) --> - <skip /> - <!-- no translation found for minimize_button_text (5213953162664451152) --> - <skip /> - <!-- no translation found for close_button_text (4544839489310949894) --> - <skip /> + <string name="maximize_button_text" msgid="8106849394538234709">"הגדלה של <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="restore_button_text" msgid="5377571986086775288">"שחזור של <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="minimize_button_text" msgid="5213953162664451152">"מזעור של <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="close_button_text" msgid="4544839489310949894">"סגירה של <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="back_button_text" msgid="1469718707134137085">"חזרה"</string> <string name="handle_text" msgid="4419667835599523257">"נקודת אחיזה לאפליקציה"</string> <string name="app_icon_text" msgid="2823268023931811747">"סמל האפליקציה"</string> <string name="fullscreen_text" msgid="1162316685217676079">"מסך מלא"</string> - <string name="desktop_text" msgid="1582173066857454541">"תצוגה למחשב"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"מסך מפוצל"</string> <string name="more_button_text" msgid="3655388105592893530">"עוד"</string> <string name="float_button_text" msgid="9221657008391364581">"בלונים"</string> @@ -140,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"שינוי יחס הגובה-רוחב"</string> <string name="close_text" msgid="4986518933445178928">"סגירה"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"סגירת התפריט"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (תצוגה למחשב)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"הגדלת המסך"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"שינוי הגודל"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"לא ניתן להעביר את האפליקציה לכאן"</string> @@ -158,14 +155,10 @@ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"שינוי גודל החלון שמשמאל"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"שינוי גודל החלון שמימין"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"שחזור של גודל החלון או הגדלת החלון"</string> - <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) --> - <skip /> - <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) --> - <skip /> - <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) --> - <skip /> - <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) --> - <skip /> + <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"הגדלת החלון של האפליקציה"</string> + <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"שחזור הגודל של החלון"</string> + <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"מזעור החלון של האפליקציה"</string> + <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"סגירת החלון של האפליקציה"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"הגדרות לפתיחה כברירת מחדל"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"כאן בוחרים איך לפתוח באפליקציה הזו קישורים לדפי אינטרנט"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"באפליקציה"</string> diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml index d68581bda1ff..1a73dd3b7715 100644 --- a/libs/WindowManager/Shell/res/values-ja/strings.xml +++ b/libs/WindowManager/Shell/res/values-ja/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"修正されなかった場合は、\nタップすると元に戻ります"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"カメラに関する問題でない場合は、タップすると閉じます。"</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"アプリメニューはここにあります"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"デスクトップ ビューに切り替えて複数のアプリを同時に開けます"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"アプリメニューからいつでも全画面表示に戻れます"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"表示を拡大して機能を強化"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"分割画面にするにはもう 1 つのアプリをドラッグしてください"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"アプリハンドル"</string> <string name="app_icon_text" msgid="2823268023931811747">"アプリのアイコン"</string> <string name="fullscreen_text" msgid="1162316685217676079">"全画面表示"</string> - <string name="desktop_text" msgid="1582173066857454541">"デスクトップ ビュー"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"分割画面"</string> <string name="more_button_text" msgid="3655388105592893530">"その他"</string> <string name="float_button_text" msgid="9221657008391364581">"フローティング"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"アスペクト比を変更"</string> <string name="close_text" msgid="4986518933445178928">"閉じる"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"メニューを閉じる"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g>(デスクトップ ビュー)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"画面の最大化"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"サイズ変更"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"アプリはここに移動できません"</string> diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml index 369c019726c7..4bbfaefb36a2 100644 --- a/libs/WindowManager/Shell/res/values-ka/strings.xml +++ b/libs/WindowManager/Shell/res/values-ka/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"არ გამოსწორდა?\nშეეხეთ წინა ვერსიის დასაბრუნებლად"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"კამერას პრობლემები არ აქვს? შეეხეთ უარყოფისთვის."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"აპის მენიუ შეგიძლიათ იხილოთ აქ"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"რამდენიმე აპის ერთდროულად გასახსნელად შედით დესკტოპის ხედში"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"სრულ ეკრანზე ნებისმიერ დროს შეგიძლიათ დაბრუნდეთ აპის მენიუდან"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"მეტის ნახვა და გაკეთება"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ეკრანის გასაყოფად ჩავლებით გადაიტანეთ სხვა აპში"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"აპის იდენტიფიკატორი"</string> <string name="app_icon_text" msgid="2823268023931811747">"აპის ხატულა"</string> <string name="fullscreen_text" msgid="1162316685217676079">"სრულ ეკრანზე"</string> - <string name="desktop_text" msgid="1582173066857454541">"დესკტოპის ხედი"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"ეკრანის გაყოფა"</string> <string name="more_button_text" msgid="3655388105592893530">"სხვა"</string> <string name="float_button_text" msgid="9221657008391364581">"ფარფატი"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"თანაფარდობის შეცვლა"</string> <string name="close_text" msgid="4986518933445178928">"დახურვა"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"მენიუს დახურვა"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (დესკტოპის ხედი)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"აპლიკაციის გაშლა სრულ ეკრანზე"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ზომის შეცვლა"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"აპის აქ გადატანა შეუძლებელია"</string> diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml index 1de32d4ae834..2f6404d4680d 100644 --- a/libs/WindowManager/Shell/res/values-kk/strings.xml +++ b/libs/WindowManager/Shell/res/values-kk/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Жөнделмеді ме?\nҚайтару үшін түртіңіз."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерада қателер шықпады ма? Жабу үшін түртіңіз."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Қолданба мәзірін осы жерден табуға болады."</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Бірнеше қолданбаны бірге ашу үшін компьютерлік нұсқаны қосыңыз."</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Қолданба мәзірінен кез келген уақытта толық экранға оралыңыз."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Қосымша ақпаратты қарап, әрекеттер жасау"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Экранды бөлу үшін басқа қолданбаға өтіңіз."</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Қолданба идентификаторы"</string> <string name="app_icon_text" msgid="2823268023931811747">"Қолданба белгішесі"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Толық экран"</string> - <string name="desktop_text" msgid="1582173066857454541">"Компьютерлік нұсқа"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Экранды бөлу"</string> <string name="more_button_text" msgid="3655388105592893530">"Қосымша"</string> <string name="float_button_text" msgid="9221657008391364581">"Қалқыма"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Арақатынасты өзгерту"</string> <string name="close_text" msgid="4986518933445178928">"Жабу"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Мәзірді жабу"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (компьютерлік нұсқа)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Экранды ұлғайту"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Өлшемін өзгерту"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Қолданба бұл жерге қойылмайды."</string> diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml index 6c7faf1469eb..d3942fdc1e6c 100644 --- a/libs/WindowManager/Shell/res/values-km/strings.xml +++ b/libs/WindowManager/Shell/res/values-km/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"មិនបានដោះស្រាយបញ្ហានេះទេឬ?\nចុចដើម្បីត្រឡប់"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"មិនមានបញ្ហាពាក់ព័ន្ធនឹងកាមេរ៉ាទេឬ? ចុចដើម្បីច្រានចោល។"</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"អាចរកឃើញម៉ឺនុយកម្មវិធីនៅទីនេះ"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"ចូលទិដ្ឋភាពលើកុំព្យូទ័រ ដើម្បីបើកកម្មវិធីច្រើនជាមួយគ្នា"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"ត្រឡប់ទៅអេក្រង់ពេញវិញនៅពេលណាក៏បានពីម៉ឺនុយកម្មវិធី"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"មើលឃើញ និងធ្វើបានកាន់តែច្រើន"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"អូសកម្មវិធីមួយទៀតចូល ដើម្បីប្រើមុខងារបំបែកអេក្រង់"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"ឈ្មោះអ្នកប្រើប្រាស់កម្មវិធី"</string> <string name="app_icon_text" msgid="2823268023931811747">"រូបកម្មវិធី"</string> <string name="fullscreen_text" msgid="1162316685217676079">"អេក្រង់ពេញ"</string> - <string name="desktop_text" msgid="1582173066857454541">"ទិដ្ឋភាពលើកុំព្យូទ័រ"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"មុខងារបំបែកអេក្រង់"</string> <string name="more_button_text" msgid="3655388105592893530">"ច្រើនទៀត"</string> <string name="float_button_text" msgid="9221657008391364581">"អណ្ដែត"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"ប្ដូរសមាមាត្រ"</string> <string name="close_text" msgid="4986518933445178928">"បិទ"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"បិទម៉ឺនុយ"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ទិដ្ឋភាពលើកុំព្យូទ័រ)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ពង្រីកអេក្រង់"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ប្ដូរទំហំ"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"មិនអាចផ្លាស់ទីកម្មវិធីមកទីនេះបានទេ"</string> diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml index 6a9e07f91d08..fb15e34d934b 100644 --- a/libs/WindowManager/Shell/res/values-kn/strings.xml +++ b/libs/WindowManager/Shell/res/values-kn/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ಅದನ್ನು ಸರಿಪಡಿಸಲಿಲ್ಲವೇ?\nಹಿಂತಿರುಗಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ಕ್ಯಾಮರಾ ಸಮಸ್ಯೆಗಳಿಲ್ಲವೇ? ವಜಾಗೊಳಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"ಆ್ಯಪ್ ಮೆನುವನ್ನು ಇಲ್ಲಿ ಕಾಣಬಹುದು"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"ಹಲವು ಆ್ಯಪ್ಗಳನ್ನು ಒಟ್ಟಿಗೆ ತೆರೆಯಲು ಡೆಸ್ಕ್ಟಾಪ್ ವೀಕ್ಷಣೆಯನ್ನು ನಮೂದಿಸಿ"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"ಆ್ಯಪ್ ಮೆನುವಿನಿಂದ ಯಾವಾಗ ಬೇಕಾದರೂ ಫುಲ್ಸ್ಕ್ರೀನ್ಗೆ ಹಿಂತಿರುಗಿ"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ನೋಡಿ ಮತ್ತು ಹೆಚ್ಚಿನದನ್ನು ಮಾಡಿ"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ಗಾಗಿ ಮತ್ತೊಂದು ಆ್ಯಪ್ನಲ್ಲಿ ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"ಆ್ಯಪ್ ಹ್ಯಾಂಡಲ್"</string> <string name="app_icon_text" msgid="2823268023931811747">"ಆ್ಯಪ್ ಐಕಾನ್"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ಫುಲ್ಸ್ಕ್ರೀನ್"</string> - <string name="desktop_text" msgid="1582173066857454541">"ಡೆಸ್ಕ್ಟಾಪ್ ವೀಕ್ಷಣೆ"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್"</string> <string name="more_button_text" msgid="3655388105592893530">"ಇನ್ನಷ್ಟು"</string> <string name="float_button_text" msgid="9221657008391364581">"ಫ್ಲೋಟ್"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"ದೃಶ್ಯಾನುಪಾತವನ್ನು ಬದಲಾಯಿಸಿ"</string> <string name="close_text" msgid="4986518933445178928">"ಮುಚ್ಚಿ"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"ಮೆನು ಮುಚ್ಚಿ"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ಡೆಸ್ಕ್ಟಾಪ್ ವೀಕ್ಷಣೆ)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ಸ್ಕ್ರೀನ್ ಅನ್ನು ಮ್ಯಾಕ್ಸಿಮೈಸ್ ಮಾಡಿ"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ಮರುಗಾತ್ರಗೊಳಿಸಿ"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ಆ್ಯಪ್ ಅನ್ನು ಇಲ್ಲಿಗೆ ಸರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml index e94d8893010f..dbfd32a7dcb1 100644 --- a/libs/WindowManager/Shell/res/values-ko/strings.xml +++ b/libs/WindowManager/Shell/res/values-ko/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"해결되지 않았나요?\n되돌리려면 탭하세요."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"카메라에 문제가 없나요? 닫으려면 탭하세요."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"앱 메뉴는 여기에서 찾을 수 있습니다."</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"데스크톱 뷰를 실행하여 여러 앱을 함께 열 수 있습니다."</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"언제든지 앱 메뉴에서 전체 화면으로 돌아갈 수 있습니다."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"더 많은 정보를 보고 더 많은 작업을 처리하세요"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"화면 분할을 사용하려면 다른 앱을 드래그해 가져옵니다."</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"앱 핸들"</string> <string name="app_icon_text" msgid="2823268023931811747">"앱 아이콘"</string> <string name="fullscreen_text" msgid="1162316685217676079">"전체 화면"</string> - <string name="desktop_text" msgid="1582173066857454541">"데스크톱 뷰"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"화면 분할"</string> <string name="more_button_text" msgid="3655388105592893530">"더보기"</string> <string name="float_button_text" msgid="9221657008391364581">"플로팅"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"가로세로 비율 변경"</string> <string name="close_text" msgid="4986518933445178928">"닫기"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"메뉴 닫기"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g>(데스크톱 뷰)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"화면 최대화"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"크기 조절"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"앱을 여기로 이동할 수 없음"</string> diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml index 73e743686b77..36194cdaaa47 100644 --- a/libs/WindowManager/Shell/res/values-ky/strings.xml +++ b/libs/WindowManager/Shell/res/values-ky/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Оңдолгон жокпу?\nАртка кайтаруу үчүн таптаңыз"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерада маселе жокпу? Этибарга албоо үчүн таптаңыз."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Колдонмонун менюсун ушул жерден таба аласыз"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Бир убакта бир нече колдонмону ачуу үчүн компьютердик версияга өтүңүз"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Каалаган убакта колдонмонун менюсунан толук экранга кайта аласыз"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Көрүп, көбүрөөк нерселерди жасаңыз"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Экранды бөлүү үчүн башка колдонмону сүйрөңүз"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Колдонмонун маркери"</string> <string name="app_icon_text" msgid="2823268023931811747">"Колдонмонун сүрөтчөсү"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Толук экран"</string> - <string name="desktop_text" msgid="1582173066857454541">"Компьютердик версия"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Экранды бөлүү"</string> <string name="more_button_text" msgid="3655388105592893530">"Дагы"</string> <string name="float_button_text" msgid="9221657008391364581">"Калкыма"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Тараптардын катнашын өзгөртүү"</string> <string name="close_text" msgid="4986518933445178928">"Жабуу"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Менюну жабуу"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (компьютердик версия)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Экранды чоңойтуу"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Өлчөмүн өзгөртүү"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Колдонмону бул жерге жылдырууга болбойт"</string> diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml index fd47465de5da..671f92447204 100644 --- a/libs/WindowManager/Shell/res/values-lo/strings.xml +++ b/libs/WindowManager/Shell/res/values-lo/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ບໍ່ໄດ້ແກ້ໄຂມັນບໍ?\nແຕະເພື່ອແປງກັບຄືນ"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ບໍ່ມີບັນຫາກ້ອງຖ່າຍຮູບບໍ? ແຕະເພື່ອປິດໄວ້."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"ສາມາດເບິ່ງເມນູແອັບໄດ້ບ່ອນນີ້"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"ເຂົ້າສູ່ມຸມມອງເດັສທັອບເພື່ອເປີດຫຼາຍແອັບພ້ອມກັນ"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"ກັບຄືນໄປຫາໂໝດເຕັມຈໍໄດ້ທຸກເວລາຈາກເມນູແອັບ"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ເບິ່ງ ແລະ ເຮັດຫຼາຍຂຶ້ນ"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ລາກໄປໄວ້ໃນແອັບອື່ນເພື່ອແບ່ງໜ້າຈໍ"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"ຊື່ຜູ້ໃຊ້ແອັບ"</string> <string name="app_icon_text" msgid="2823268023931811747">"ໄອຄອນແອັບ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ເຕັມຈໍ"</string> - <string name="desktop_text" msgid="1582173066857454541">"ມຸມມອງຢູ່ເດັສທັອບ"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"ແບ່ງໜ້າຈໍ"</string> <string name="more_button_text" msgid="3655388105592893530">"ເພີ່ມເຕີມ"</string> <string name="float_button_text" msgid="9221657008391364581">"ລອຍ"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"ປ່ຽນອັດຕາສ່ວນຮູບ"</string> <string name="close_text" msgid="4986518933445178928">"ປິດ"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"ປິດເມນູ"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ມຸມມອງຢູ່ເດັສທັອບ)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ປັບຈໍໃຫຍ່ສຸດ"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ປັບຂະໜາດ"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ບໍ່ສາມາດຍ້າຍແອັບມາບ່ອນນີ້ໄດ້"</string> diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml index 902ef048b11e..794c5ab02c19 100644 --- a/libs/WindowManager/Shell/res/values-lt/strings.xml +++ b/libs/WindowManager/Shell/res/values-lt/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nepavyko pataisyti?\nPalieskite, kad grąžintumėte"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nėra jokių problemų dėl kameros? Palieskite, kad atsisakytumėte."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Programos meniu rasite čia"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Įjunkite rodinio versiją staliniams kompiuteriams, kad vienu metu atidarytumėte kelias programas"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Bet kada iš programos meniu grįžkite į viso ekrano režimą"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Daugiau turinio ir funkcijų"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Vilkite kitoje programoje, kad galėtumėte naudoti išskaidyto ekrano režimą"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Programos kreipinys"</string> <string name="app_icon_text" msgid="2823268023931811747">"Programos piktograma"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Visas ekranas"</string> - <string name="desktop_text" msgid="1582173066857454541">"Rodinio versija staliniams kompiuteriams"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Išskaidyto ekrano režimas"</string> <string name="more_button_text" msgid="3655388105592893530">"Daugiau"</string> <string name="float_button_text" msgid="9221657008391364581">"Slankusis langas"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Keisti kraštinių santykį"</string> <string name="close_text" msgid="4986518933445178928">"Uždaryti"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Uždaryti meniu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ (rodinio versija staliniams kompiuteriams)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Išskleisti ekraną"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Pakeisti dydį"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Programos negalima perkelti čia"</string> diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml index b4095dfd6f1e..5b44112c76d5 100644 --- a/libs/WindowManager/Shell/res/values-lv/strings.xml +++ b/libs/WindowManager/Shell/res/values-lv/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Vai problēma netika novērsta?\nPieskarieties, lai atjaunotu."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Vai nav problēmu ar kameru? Pieskarieties, lai nerādītu."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Šeit ir pieejama lietotņu izvēlne"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Lai atvērtu vairākas lietotnes vienlaikus, pārejiet uz skatu datorā"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"No lietotnes izvēlnes varat jebkurā brīdī atgriezties pilnekrāna režīmā."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Uzziniet un paveiciet vairāk"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Lai izmantotu sadalītu ekrānu, ievelciet vēl vienu lietotni"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Lietotnes turis"</string> <string name="app_icon_text" msgid="2823268023931811747">"Lietotnes ikona"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pilnekrāna režīms"</string> - <string name="desktop_text" msgid="1582173066857454541">"Skats datorā"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Sadalīt ekrānu"</string> <string name="more_button_text" msgid="3655388105592893530">"Vairāk"</string> <string name="float_button_text" msgid="9221657008391364581">"Peldošs"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Mainīt malu attiecību"</string> <string name="close_text" msgid="4986518933445178928">"Aizvērt"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Aizvērt izvēlni"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (skats datorā)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimizēt ekrānu"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Mainīt lielumu"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Lietotni nevar pārvietot šeit."</string> diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml index be97489d6159..96bf9b67144e 100644 --- a/libs/WindowManager/Shell/res/values-mk/strings.xml +++ b/libs/WindowManager/Shell/res/values-mk/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не се поправи?\nДопрете за враќање"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нема проблеми со камерата? Допрете за отфрлање."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Менито со апликации може да го најдете овде"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Влезете во приказот на компјутер за да отворите повеќе апликации заедно"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Вратете се на цел екран од менито со апликации кога сакате"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Погледнете и направете повеќе"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Повлечете друга апликација за поделен екран"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Прекар на апликацијата"</string> <string name="app_icon_text" msgid="2823268023931811747">"Икона на апликацијата"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Цел екран"</string> - <string name="desktop_text" msgid="1582173066857454541">"Приказ на компјутер"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Поделен екран"</string> <string name="more_button_text" msgid="3655388105592893530">"Повеќе"</string> <string name="float_button_text" msgid="9221657008391364581">"Лебдечко"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Промени го соодносот"</string> <string name="close_text" msgid="4986518933445178928">"Затворете"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Затворете го менито"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (приказ на компјутер)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Максимизирај го екранот"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Смени големина"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Апликацијата не може да се премести овде"</string> diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml index cb84dec8a254..8085601076ef 100644 --- a/libs/WindowManager/Shell/res/values-ml/strings.xml +++ b/libs/WindowManager/Shell/res/values-ml/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"അത് പരിഹരിച്ചില്ലേ?\nപുനഃസ്ഥാപിക്കാൻ ടാപ്പ് ചെയ്യുക"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ക്യാമറാ പ്രശ്നങ്ങളൊന്നുമില്ലേ? നിരസിക്കാൻ ടാപ്പ് ചെയ്യുക."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"ആപ്പ് മെനു ഇവിടെ കണ്ടെത്താനാകും"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"ഒന്നിലധികം ആപ്പുകൾ ഒരുമിച്ച് തുറക്കാൻ ഡെസ്ക്ടോപ്പ് വ്യൂവിൽ പ്രവേശിക്കുക"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"ആപ്പ് മെനുവിൽ നിന്ന് ഏതുസമയത്തും പൂർണ്ണ സ്ക്രീനിലേക്ക് മടങ്ങുക"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"കൂടുതൽ കാണുക, ചെയ്യുക"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"സ്ക്രീൻ വിഭജന മോഡിന്, മറ്റൊരു ആപ്പ് വലിച്ചിടുക"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"ആപ്പ് ഹാൻഡിൽ"</string> <string name="app_icon_text" msgid="2823268023931811747">"ആപ്പ് ഐക്കൺ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"പൂർണ്ണസ്ക്രീൻ"</string> - <string name="desktop_text" msgid="1582173066857454541">"ഡെസ്ക്ടോപ്പ് വ്യൂ"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"സ്ക്രീൻ വിഭജനം"</string> <string name="more_button_text" msgid="3655388105592893530">"കൂടുതൽ"</string> <string name="float_button_text" msgid="9221657008391364581">"ഫ്ലോട്ട്"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"വീക്ഷണ അനുപാതം മാറ്റുക"</string> <string name="close_text" msgid="4986518933445178928">"അടയ്ക്കുക"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"മെനു അടയ്ക്കുക"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ഡെസ്ക്ടോപ്പ് വ്യൂ)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"സ്ക്രീൻ വലുതാക്കുക"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"വലുപ്പം മാറ്റുക"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ആപ്പ് ഇവിടേക്ക് നീക്കാനാകില്ല"</string> diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml index d8efd8b2a103..5efe62d7d837 100644 --- a/libs/WindowManager/Shell/res/values-mn/strings.xml +++ b/libs/WindowManager/Shell/res/values-mn/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Үүнийг засаагүй юу?\nБуцаахын тулд товшино уу"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерын асуудал байхгүй юу? Хаахын тулд товшино уу."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Аппын цэсийг эндээс олох боломжтой"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Олон аппыг хамтад нь нээхийн тулд дэлгэц дээр харагдах байдалд орно уу"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Аппын цэсээс бүтэн дэлгэц рүү хүссэн үедээ буцна уу"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Харж илүү ихийг хий"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Дэлгэц хуваах горимд ашиглахын тулд өөр аппыг чирнэ үү"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Аппын бариул"</string> <string name="app_icon_text" msgid="2823268023931811747">"Aппын дүрс тэмдэг"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Бүтэн дэлгэц"</string> - <string name="desktop_text" msgid="1582173066857454541">"Дэлгэц дээр харагдах байдал"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Дэлгэцийг хуваах"</string> <string name="more_button_text" msgid="3655388105592893530">"Бусад"</string> <string name="float_button_text" msgid="9221657008391364581">"Хөвөгч"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Аспектын харьцааг өөрчлөх"</string> <string name="close_text" msgid="4986518933445178928">"Хаах"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Цэсийг хаах"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (дэлгэц дээр харагдах байдал)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Дэлгэцийг томруулах"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Хэмжээг өөрчлөх"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Аппыг ийш зөөх боломжгүй"</string> diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml index d09a78426669..e10c8d82440d 100644 --- a/libs/WindowManager/Shell/res/values-mr/strings.xml +++ b/libs/WindowManager/Shell/res/values-mr/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"निराकरण झाले नाही?\nरिव्हर्ट करण्यासाठी कृपया टॅप करा"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"कॅमेराशी संबंधित कोणत्याही समस्या नाहीत का? डिसमिस करण्यासाठी टॅप करा."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"ॲप मेनू इथे आढळू शकतो"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"एकाहून अधिक ॲप्स एकत्र उघडण्यासाठी डेस्कटॉप दृश्यात एंटर करा"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"ॲप मेनूमधून कधीही फुल स्क्रीनवर परत या"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"पहा आणि आणखी बरेच काही करा"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"स्प्लिट स्क्रीन वापरण्यासाठी दुसरे ॲप ड्रॅग करा"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"अॅपचे हँडल"</string> <string name="app_icon_text" msgid="2823268023931811747">"अॅप आयकन"</string> <string name="fullscreen_text" msgid="1162316685217676079">"फुलस्क्रीन"</string> - <string name="desktop_text" msgid="1582173066857454541">"डेस्कटॉप दृश्य"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"स्प्लिट स्क्रीन"</string> <string name="more_button_text" msgid="3655388105592893530">"आणखी"</string> <string name="float_button_text" msgid="9221657008391364581">"फ्लोट"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"आस्पेक्ट रेशो बदला"</string> <string name="close_text" msgid="4986518933445178928">"बंद करा"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"मेनू बंद करा"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (डेस्कटॉप दृश्य)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रीन मोठी करा"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"आकार बदला"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"अॅप इथे हलवू शकत नाही"</string> diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml index e954b0f8937e..e18e7ec68640 100644 --- a/libs/WindowManager/Shell/res/values-ms/strings.xml +++ b/libs/WindowManager/Shell/res/values-ms/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Isu tidak dibetulkan?\nKetik untuk kembali"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Tiada isu kamera? Ketik untuk mengetepikan."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Menu apl boleh ditemukan di sini"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Masuki paparan desktop untuk membuka berbilang apl serentak"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Kembali kepada skrin penuh pada bila-bila masa daripada menu apl"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Lihat dan lakukan lebih"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Seret masuk apl lain untuk menggunakan skrin pisah"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Pengendalian apl"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikon Apl"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Skrin penuh"</string> - <string name="desktop_text" msgid="1582173066857454541">"Paparan Desktop"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Skrin Pisah"</string> <string name="more_button_text" msgid="3655388105592893530">"Lagi"</string> <string name="float_button_text" msgid="9221657008391364581">"Terapung"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Tukar nisbah bidang"</string> <string name="close_text" msgid="4986518933445178928">"Tutup"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Tutup Menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Paparan Desktop)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimumkan Skrin"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Ubah saiz"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Apl tidak boleh dialihkan ke sini"</string> diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml index 2342564930b4..334a79799d53 100644 --- a/libs/WindowManager/Shell/res/values-my/strings.xml +++ b/libs/WindowManager/Shell/res/values-my/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ကောင်းမသွားဘူးလား။\nပြန်ပြောင်းရန် တို့ပါ"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ကင်မရာပြဿနာ မရှိဘူးလား။ ပယ်ရန် တို့ပါ။"</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"အက်ပ်မီနူးကို ဤနေရာတွင် တွေ့နိုင်သည်"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"အက်ပ်များစွာကို အတူတကွဖွင့်ရန်အတွက် ဒက်စ်တော့မြင်ကွင်းသို့ ဝင်ရောက်နိုင်သည်"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"အက်ပ်မီနူးမှ ဖန်သားပြင်အပြည့်သို့ အချိန်မရွေး ပြန်သွားနိုင်သည်"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ကြည့်ပြီး ပိုမိုလုပ်ဆောင်ပါ"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းအတွက် အက်ပ်နောက်တစ်ခုကို ဖိဆွဲပါ"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"အက်ပ်သုံးသူအမည်"</string> <string name="app_icon_text" msgid="2823268023931811747">"အက်ပ်သင်္ကေတ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ဖန်သားပြင်အပြည့်"</string> - <string name="desktop_text" msgid="1582173066857454541">"ဒက်စ်တော့ မြင်ကွင်း"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"မျက်နှာပြင် ခွဲ၍ပြသရန်"</string> <string name="more_button_text" msgid="3655388105592893530">"ပိုပြပါ"</string> <string name="float_button_text" msgid="9221657008391364581">"မျှောရန်"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"အချိုးအစား ပြောင်းရန်"</string> <string name="close_text" msgid="4986518933445178928">"ပိတ်ရန်"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"မီနူး ပိတ်ရန်"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ဒက်စ်တော့ မြင်ကွင်း)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"စခရင်ကို ချဲ့မည်"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"အရွယ်ပြင်ရန်"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"အက်ပ်ကို ဤနေရာသို့ ရွှေ့၍မရပါ"</string> diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml index fb61a105eaaa..7e21b475b2fa 100644 --- a/libs/WindowManager/Shell/res/values-nb/strings.xml +++ b/libs/WindowManager/Shell/res/values-nb/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ble ikke problemet løst?\nTrykk for å gå tilbake"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Har du ingen kameraproblemer? Trykk for å lukke."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Her finner du appmenyen"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Gå til skrivebordsvisningen for å åpne flere apper samtidig"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Du kan gå tilbake til fullskjermmodusen når som helst fra appmenyen"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Se og gjør mer"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Dra inn en annen app for å bruke delt skjerm"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Apphåndtak"</string> <string name="app_icon_text" msgid="2823268023931811747">"Appikon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Fullskjerm"</string> - <string name="desktop_text" msgid="1582173066857454541">"Datamaskinvisning"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Delt skjerm"</string> <string name="more_button_text" msgid="3655388105592893530">"Mer"</string> <string name="float_button_text" msgid="9221657008391364581">"Svevende"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Endre høyde/bredde-forholdet"</string> <string name="close_text" msgid="4986518933445178928">"Lukk"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Lukk menyen"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (datamaskinvisning)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimer skjermen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Endre størrelse"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Appen kan ikke flyttes hit"</string> diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml index fdfa227b8080..976f8378606a 100644 --- a/libs/WindowManager/Shell/res/values-ne/strings.xml +++ b/libs/WindowManager/Shell/res/values-ne/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"समस्या हल भएन?\nपहिलेको जस्तै बनाउन ट्याप गर्नुहोस्"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"क्यामेरासम्बन्धी कुनै पनि समस्या छैन? खारेज गर्न ट्याप गर्नुहोस्।"</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"एपको मेनु यहाँ भेट्टाउन सकिन्छ"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"एकभन्दा बढी एपहरू सँगै देखाउन डेस्कटप भ्यू हाल्नुहोस्"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"जुनसुकै बेला एपको मेनुबाट फुल स्क्रिनमा फर्कनुहोस्"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"थप कुरा हेर्नुहोस् र गर्नुहोस्"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"स्प्लिट स्क्रिन मोड प्रयोग गर्न अर्को एप ड्रयाग एन्ड ड्रप गर्नुहोस्"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"एपको ह्यान्डल"</string> <string name="app_icon_text" msgid="2823268023931811747">"एपको आइकन"</string> <string name="fullscreen_text" msgid="1162316685217676079">"फुल स्क्रिन"</string> - <string name="desktop_text" msgid="1582173066857454541">"डेस्कटप भ्यू"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"स्प्लिट स्क्रिन"</string> <string name="more_button_text" msgid="3655388105592893530">"थप"</string> <string name="float_button_text" msgid="9221657008391364581">"फ्लोट"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"एस्पेक्ट रेसियो परिवर्तन गर्नुहोस्"</string> <string name="close_text" msgid="4986518933445178928">"बन्द गर्नुहोस्"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"मेनु बन्द गर्नुहोस्"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (डेस्कटप भ्यू)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रिन ठुलो बनाउनुहोस्"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"आकार बदल्नुहोस्"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"एप सारेर यहाँ ल्याउन सकिएन"</string> diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml index 578877c65dd1..7178e418a5aa 100644 --- a/libs/WindowManager/Shell/res/values-nl/strings.xml +++ b/libs/WindowManager/Shell/res/values-nl/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Is dit geen oplossing?\nTik om terug te zetten."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Geen cameraproblemen? Tik om te sluiten."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Het app-menu vind je hier"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Ga naar de desktopweergave om meerdere apps tegelijk te openen"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Ga wanneer je wilt terug naar volledig scherm vanuit het app-menu"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Zie en doe meer"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Sleep een andere app hier naartoe om het scherm te splitsen"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"App-handgreep"</string> <string name="app_icon_text" msgid="2823268023931811747">"App-icoon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Volledig scherm"</string> - <string name="desktop_text" msgid="1582173066857454541">"Desktopweergave"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Gesplitst scherm"</string> <string name="more_button_text" msgid="3655388105592893530">"Meer"</string> <string name="float_button_text" msgid="9221657008391364581">"Zwevend"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Beeldverhouding wijzigen"</string> <string name="close_text" msgid="4986518933445178928">"Sluiten"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Menu sluiten"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (desktopweergave)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Scherm maximaliseren"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Formaat aanpassen"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Kan de app niet hierheen verplaatsen"</string> diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml index 62ee4a049a1d..19cc8ced6517 100644 --- a/libs/WindowManager/Shell/res/values-or/strings.xml +++ b/libs/WindowManager/Shell/res/values-or/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ଏହାର ସମାଧାନ ହୋଇନାହିଁ?\nଫେରିଯିବା ପାଇଁ ଟାପ କରନ୍ତୁ"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"କ୍ୟାମେରାରେ କିଛି ସମସ୍ୟା ନାହିଁ? ଖାରଜ କରିବାକୁ ଟାପ କରନ୍ତୁ।"</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"ଆପ ମେନୁ ଏଠାରେ ମିଳିପାରିବ"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"ଏକାଠି ଏକାଧିକ ଆପ୍ସ ଖୋଲିବାକୁ ଡେସ୍କଟପ ଭ୍ୟୁରେ ପ୍ରବେଶ କରନ୍ତୁ"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"ଆପ ମେନୁରୁ ଯେ କୌଣସି ସମୟରେ ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନକୁ ଫେରନ୍ତୁ"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ଦେଖନ୍ତୁ ଏବଂ ଆହୁରି ଅନେକ କିଛି କରନ୍ତୁ"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ପାଇଁ ଅନ୍ୟ ଏକ ଆପକୁ ଡ୍ରାଗ କରନ୍ତୁ"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"ଆପର ହେଣ୍ଡେଲ"</string> <string name="app_icon_text" msgid="2823268023931811747">"ଆପ ଆଇକନ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ପୂର୍ଣ୍ଣସ୍କ୍ରିନ"</string> - <string name="desktop_text" msgid="1582173066857454541">"ଡେସ୍କଟପ ଭ୍ୟୁ"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ"</string> <string name="more_button_text" msgid="3655388105592893530">"ଅଧିକ"</string> <string name="float_button_text" msgid="9221657008391364581">"ଫ୍ଲୋଟ"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"ଚଉଡ଼ା ଓ ଉଚ୍ଚତାର ଅନୁପାତ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string> <string name="close_text" msgid="4986518933445178928">"ବନ୍ଦ କରନ୍ତୁ"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"ମେନୁ ବନ୍ଦ କରନ୍ତୁ"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ଡେସ୍କଟପ ଭ୍ୟୁ)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ସ୍କ୍ରିନକୁ ବଡ଼ କରନ୍ତୁ"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ରିସାଇଜ କରନ୍ତୁ"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ଆପକୁ ଏଠାକୁ ମୁଭ କରାଯାଇପାରିବ ନାହିଁ"</string> diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml index 4dde6d292148..7e8929003017 100644 --- a/libs/WindowManager/Shell/res/values-pa/strings.xml +++ b/libs/WindowManager/Shell/res/values-pa/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ਕੀ ਇਹ ਠੀਕ ਨਹੀਂ ਹੋਈ?\nਵਾਪਸ ਉਹੀ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ਕੀ ਕੈਮਰੇ ਸੰਬੰਧੀ ਕੋਈ ਸਮੱਸਿਆ ਨਹੀਂ ਹੈ? ਖਾਰਜ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"ਐਪ ਮੀਨੂ ਇੱਥੇ ਮਿਲ ਸਕਦਾ ਹੈ"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"ਕਈ ਐਪਾਂ ਨੂੰ ਇਕੱਠੇ ਖੋਲ੍ਹਣ ਲਈ ਡੈਸਕਟਾਪ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਦਾਖਲ ਹੋਵੋ"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"ਐਪ ਮੀਨੂ ਤੋਂ ਕਿਸੇ ਵੀ ਸਮੇਂ ਪੂਰੀ ਸਕ੍ਰੀਨ \'ਤੇ ਵਾਪਸ ਜਾਓ"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ਦੇਖੋ ਅਤੇ ਹੋਰ ਬਹੁਤ ਕੁਝ ਕਰੋ"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੇ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ ਵਿੱਚ ਘਸੀਟੋ"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"ਐਪ ਹੈਂਡਲ"</string> <string name="app_icon_text" msgid="2823268023931811747">"ਐਪ ਪ੍ਰਤੀਕ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ਪੂਰੀ-ਸਕ੍ਰੀਨ"</string> - <string name="desktop_text" msgid="1582173066857454541">"ਡੈਸਕਟਾਪ ਦ੍ਰਿਸ਼"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ"</string> <string name="more_button_text" msgid="3655388105592893530">"ਹੋਰ"</string> <string name="float_button_text" msgid="9221657008391364581">"ਫ਼ਲੋਟ"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"ਆਕਾਰ ਅਨੁਪਾਤ ਬਦਲੋ"</string> <string name="close_text" msgid="4986518933445178928">"ਬੰਦ ਕਰੋ"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"ਮੀਨੂ ਬੰਦ ਕਰੋ"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ਡੈਸਕਟਾਪ ਦ੍ਰਿਸ਼)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ਸਕ੍ਰੀਨ ਦਾ ਆਕਾਰ ਵਧਾਓ"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ਆਕਾਰ ਬਦਲੋ"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ਐਪ ਨੂੰ ਇੱਥੇ ਨਹੀਂ ਲਿਜਾਇਆ ਜਾ ਸਕਦਾ"</string> diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml index 50861bac617b..58a691f83cca 100644 --- a/libs/WindowManager/Shell/res/values-pl/strings.xml +++ b/libs/WindowManager/Shell/res/values-pl/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Naprawa się nie udała?\nKliknij, aby cofnąć"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Brak problemów z aparatem? Kliknij, aby zamknąć"</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Tu znajdziesz menu aplikacji"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Aby otworzyć kilka aplikacji jednocześnie, przejdź do widoku pulpitu"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Z menu aplikacji w każdej chwili możesz wrócić do pełnego ekranu"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Zobacz i zrób więcej"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Aby podzielić ekran, przeciągnij drugą aplikację"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Uchwyt aplikacji"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacji"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pełny ekran"</string> - <string name="desktop_text" msgid="1582173066857454541">"Wersja na komputery"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Podzielony ekran"</string> <string name="more_button_text" msgid="3655388105592893530">"Więcej"</string> <string name="float_button_text" msgid="9221657008391364581">"Pływające"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Zmień format obrazu"</string> <string name="close_text" msgid="4986518933445178928">"Zamknij"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zamknij menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (wersja na komputery)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksymalizuj ekran"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Zmień rozmiar"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Nie można przenieść aplikacji tutaj"</string> diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml index a8f7403a94db..2d9bc2bc5b80 100644 --- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Não tem problemas com a câmera? Toque para dispensar."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"O menu do app está aqui"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Acesse a versão para computadores para abrir vários apps ao mesmo tempo"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Volte para a tela cheia a qualquer momento no menu do app"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Veja e faça mais"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arraste outro app para dividir a tela"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Identificador do app"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ícone do app"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Tela cheia"</string> - <string name="desktop_text" msgid="1582173066857454541">"Versão para computadores"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Tela dividida"</string> <string name="more_button_text" msgid="3655388105592893530">"Mais"</string> <string name="float_button_text" msgid="9221657008391364581">"Ponto flutuante"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Mudar a proporção"</string> <string name="close_text" msgid="4986518933445178928">"Fechar"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (versão para computadores)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ampliar tela"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Redimensionar"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Não é possível mover o app para cá"</string> diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml index 04d404287327..765a2071a037 100644 --- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Não foi corrigido?\nToque para reverter"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nenhum problema com a câmara? Toque para ignorar."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"O menu da app pode ser encontrado aqui"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Entre na vista de computador para abrir várias apps em conjunto"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Regresse ao ecrã inteiro em qualquer altura a partir do menu da app"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Veja e faça mais"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arraste outra app para usar o ecrã dividido"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Indicador da app"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ícone da app"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Ecrã inteiro"</string> - <string name="desktop_text" msgid="1582173066857454541">"Vista de computador"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Ecrã dividido"</string> <string name="more_button_text" msgid="3655388105592893530">"Mais"</string> <string name="float_button_text" msgid="9221657008391364581">"Flutuar"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Alterar formato"</string> <string name="close_text" msgid="4986518933445178928">"Fechar"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (vista de computador)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar ecrã"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Redimensionar"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Não é possível mover a app para aqui"</string> diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml index a8f7403a94db..2d9bc2bc5b80 100644 --- a/libs/WindowManager/Shell/res/values-pt/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Não tem problemas com a câmera? Toque para dispensar."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"O menu do app está aqui"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Acesse a versão para computadores para abrir vários apps ao mesmo tempo"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Volte para a tela cheia a qualquer momento no menu do app"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Veja e faça mais"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arraste outro app para dividir a tela"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Identificador do app"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ícone do app"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Tela cheia"</string> - <string name="desktop_text" msgid="1582173066857454541">"Versão para computadores"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Tela dividida"</string> <string name="more_button_text" msgid="3655388105592893530">"Mais"</string> <string name="float_button_text" msgid="9221657008391364581">"Ponto flutuante"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Mudar a proporção"</string> <string name="close_text" msgid="4986518933445178928">"Fechar"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (versão para computadores)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ampliar tela"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Redimensionar"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Não é possível mover o app para cá"</string> diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml index d781d0893fa6..68d045fdbe29 100644 --- a/libs/WindowManager/Shell/res/values-ro/strings.xml +++ b/libs/WindowManager/Shell/res/values-ro/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nu ai remediat problema?\nAtinge pentru a reveni"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nu ai probleme cu camera foto? Atinge pentru a închide."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Meniul aplicației poate fi găsit aici"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Accesează afișarea pe desktop pentru a deschide mai multe aplicații simultan"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Revino oricând la ecranul complet din meniul aplicației"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Vezi și fă mai multe"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Trage în altă aplicație pentru a folosi ecranul împărțit"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Handle de aplicație"</string> <string name="app_icon_text" msgid="2823268023931811747">"Pictograma aplicației"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Ecran complet"</string> - <string name="desktop_text" msgid="1582173066857454541">"Afișare pe desktop"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Ecran împărțit"</string> <string name="more_button_text" msgid="3655388105592893530">"Mai multe"</string> <string name="float_button_text" msgid="9221657008391364581">"Flotantă"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Schimbă raportul de dimensiuni"</string> <string name="close_text" msgid="4986518933445178928">"Închide"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Închide meniul"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (afișare pe desktop)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizează fereastra"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Redimensionează"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplicația nu poate fi mutată aici"</string> diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml index 1837c31cbeef..8e683b8afb79 100644 --- a/libs/WindowManager/Shell/res/values-ru/strings.xml +++ b/libs/WindowManager/Shell/res/values-ru/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не помогло?\nНажмите, чтобы отменить изменения."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нет проблем с камерой? Нажмите, чтобы закрыть."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Здесь вы найдете меню приложения"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Чтобы открыть сразу несколько приложений, перейдите в режим компьютера"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Вернуться в полноэкранный режим можно из меню приложения"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Выполняйте несколько задач одновременно"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Перетащите сюда другое приложение, чтобы использовать разделение экрана."</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Обозначение приложения"</string> <string name="app_icon_text" msgid="2823268023931811747">"Значок приложения"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Полноэкранный режим"</string> - <string name="desktop_text" msgid="1582173066857454541">"Версия для ПК"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Разделить экран"</string> <string name="more_button_text" msgid="3655388105592893530">"Ещё"</string> <string name="float_button_text" msgid="9221657008391364581">"Плавающее окно"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Изменить соотношение сторон"</string> <string name="close_text" msgid="4986518933445178928">"Закрыть"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Закрыть меню"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" (версия для ПК)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Развернуть на весь экран"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Изменить размер"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Приложение нельзя сюда переместить"</string> diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml index d2fc08229793..6d548395bfac 100644 --- a/libs/WindowManager/Shell/res/values-si/strings.xml +++ b/libs/WindowManager/Shell/res/values-si/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"එය විසඳුවේ නැතිද?\nප්රතිවර්තනය කිරීමට තට්ටු කරන්න"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"කැමරා ගැටලු නොමැතිද? ඉවත දැමීමට තට්ටු කරන්න"</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"යෙදුම් මෙනුව මෙතැනින් සොයා ගත හැක"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"යෙදුම් කිහිපයක් එකට විවෘත කිරීමට ඩෙස්ක්ටොප් දසුනට ඇතුළු වන්න"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"යෙදුම් මෙනුවෙන් ඕනෑම වේලාවක පූර්ණ තිරය වෙත ආපසු යන්න"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"බලන්න සහ තවත් දේ කරන්න"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"බෙදුම් තිරය සඳහා වෙනත් යෙදුමකට අදින්න"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"යෙදුම් හසුරුව"</string> <string name="app_icon_text" msgid="2823268023931811747">"යෙදුම් නිරූපකය"</string> <string name="fullscreen_text" msgid="1162316685217676079">"පූර්ණ තිරය"</string> - <string name="desktop_text" msgid="1582173066857454541">"ඩෙස්ක්ටොප් දසුන"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"බෙදුම් තිරය"</string> <string name="more_button_text" msgid="3655388105592893530">"තව"</string> <string name="float_button_text" msgid="9221657008391364581">"පාවෙන"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"දර්ශන අනුපාතය වෙනස් කරන්න"</string> <string name="close_text" msgid="4986518933445178928">"වසන්න"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"මෙනුව වසන්න"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ඩෙස්ක්ටොප් දසුන)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"තිරය උපරිම කරන්න"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ප්රතිප්රමාණය කරන්න"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"යෙදුම මෙතැනට ගෙන යා නොහැක"</string> diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml index a9c81a2e59ad..c04b03873dc7 100644 --- a/libs/WindowManager/Shell/res/values-sk/strings.xml +++ b/libs/WindowManager/Shell/res/values-sk/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nevyriešilo sa to?\nKlepnutím sa vráťte."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemáte problémy s kamerou? Klepnutím zatvoríte."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Ponuku aplikácie nájdete tu"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Prejdite do zobrazenia v počítači a otvorte viac aplikácií naraz"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Z ponuky aplikácie sa môžete kedykoľvek vrátiť na celú obrazovku"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Zobrazte si a zvládnite toho viac"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Rozdelenú obrazovku môžete použiť presunutím do inej aplikácie"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Rukoväť aplikácie"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikácie"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Celá obrazovka"</string> - <string name="desktop_text" msgid="1582173066857454541">"Zobrazenie v počítači"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Rozdelená obrazovka"</string> <string name="more_button_text" msgid="3655388105592893530">"Viac"</string> <string name="float_button_text" msgid="9221657008391364581">"Plávajúce"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Zmeniť pomer strán"</string> <string name="close_text" msgid="4986518933445178928">"Zavrieť"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zavrieť ponuku"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (zobrazenie v počítači)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximalizovať obrazovku"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Zmeniť veľkosť"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikácia sa sem nedá presunúť"</string> diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml index 8dcca185e374..22d7bfe978cc 100644 --- a/libs/WindowManager/Shell/res/values-sl/strings.xml +++ b/libs/WindowManager/Shell/res/values-sl/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"To ni odpravilo težave?\nDotaknite se za povrnitev"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nimate težav s fotoaparatom? Dotaknite se za opustitev."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Meni aplikacije najdete tukaj"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Preklopite v pogled za namizni računalnik, če želite odpreti več aplikacij hkrati"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"V meniju aplikacije se lahko kadar koli vrnete v celozaslonski način"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Oglejte si in naredite več"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Za razdeljeni zaslon povlecite sem še eno aplikacijo."</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Identifikator aplikacije"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Celozaslonsko"</string> - <string name="desktop_text" msgid="1582173066857454541">"Pogled za namizni računalnik"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Razdeljen zaslon"</string> <string name="more_button_text" msgid="3655388105592893530">"Več"</string> <string name="float_button_text" msgid="9221657008391364581">"Lebdeče"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Sprememba razmerja stranic"</string> <string name="close_text" msgid="4986518933445178928">"Zapri"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zapri meni"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (pogled za namizni računalnik)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimiraj zaslon"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Spremeni velikost"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacije ni mogoče premakniti sem"</string> diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml index 6f8bdef18dfe..9330ec3edde5 100644 --- a/libs/WindowManager/Shell/res/values-sq/strings.xml +++ b/libs/WindowManager/Shell/res/values-sq/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nuk u rregullua?\nTrokit për ta rikthyer"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nuk ka probleme me kamerën? Trokit për ta shpërfillur."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Menyja e aplikacioneve mund të gjendet këtu"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Kalo te pamja e desktopit për të hapur disa aplikacione së bashku"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Kthehu tek ekrani i plotë në çdo kohë nga menyja e aplikacioneve"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Shiko dhe bëj më shumë"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Zvarrite në një aplikacion tjetër për ekranin e ndarë"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Emërtimi i aplikacionit"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona e aplikacionit"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Ekrani i plotë"</string> - <string name="desktop_text" msgid="1582173066857454541">"Pamja e desktopit"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Ekrani i ndarë"</string> <string name="more_button_text" msgid="3655388105592893530">"Më shumë"</string> <string name="float_button_text" msgid="9221657008391364581">"Pluskuese"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Ndrysho raportin e pamjes"</string> <string name="close_text" msgid="4986518933445178928">"Mbyll"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Mbyll menynë"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Pamja e desktopit)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimizo ekranin"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Ndrysho përmasat"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacioni nuk mund të zhvendoset këtu"</string> diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml index 287d34fc1de8..5bdad159b146 100644 --- a/libs/WindowManager/Shell/res/values-sr/strings.xml +++ b/libs/WindowManager/Shell/res/values-sr/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблем није решен?\nДодирните да бисте вратили"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Немате проблема са камером? Додирните да бисте одбацили."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Мени апликације можете да пронађете овде"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Уђите у приказ за рачунаре да бисте истовремено отворили више апликација"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Вратите се на цео екран било када из менија апликације"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Видите и урадите више"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Превуците другу апликацију да бисте користили подељени екран"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Идентификатор апликације"</string> <string name="app_icon_text" msgid="2823268023931811747">"Икона апликације"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Преко целог екрана"</string> - <string name="desktop_text" msgid="1582173066857454541">"Приказ за рачунаре"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Подељени екран"</string> <string name="more_button_text" msgid="3655388105592893530">"Још"</string> <string name="float_button_text" msgid="9221657008391364581">"Плутајуће"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Промени размеру"</string> <string name="close_text" msgid="4986518933445178928">"Затворите"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Затворите мени"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (приказ за рачунаре)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Повећај екран"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Прилагоди"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Апликација не може да се премести овде"</string> diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml index d8893dfab5f1..40a0a5aa6288 100644 --- a/libs/WindowManager/Shell/res/values-sv/strings.xml +++ b/libs/WindowManager/Shell/res/values-sv/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Löstes inte problemet?\nTryck för att återställa"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Inga problem med kameran? Tryck för att ignorera."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Appmenyn finns här"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Starta datorvyn för att öppna flera appar samtidigt"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Återgå till helskärm när som helst från appmenyn"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Se och gör mer"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Dra till en annan app för att dela upp skärmen"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Apphandtag"</string> <string name="app_icon_text" msgid="2823268023931811747">"Appikon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Helskärm"</string> - <string name="desktop_text" msgid="1582173066857454541">"Datorvy"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Delad skärm"</string> <string name="more_button_text" msgid="3655388105592893530">"Mer"</string> <string name="float_button_text" msgid="9221657008391364581">"Svävande"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Ändra bildformat"</string> <string name="close_text" msgid="4986518933445178928">"Stäng"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Stäng menyn"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (datorvy)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximera skärmen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Ändra storlek"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Det går inte att flytta appen hit"</string> diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml index 3ee43f3a69a8..20429e17d0d6 100644 --- a/libs/WindowManager/Shell/res/values-sw/strings.xml +++ b/libs/WindowManager/Shell/res/values-sw/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Umeshindwa kurekebisha?\nGusa ili urejeshe nakala ya awali"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Je, hakuna hitilafu za kamera? Gusa ili uondoe."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Unaweza kupata menyu ya programu hapa"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Tumia mwonekano wa kompyuta ili ufungue programu nyingi pamoja"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Rudi kwenye skrini nzima wakati wowote ukitumia menyu ya programu"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Angalia na ufanye zaidi"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Buruta katika programu nyingine ili utumie skrini iliyogawanywa"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Utambulisho wa programu"</string> <string name="app_icon_text" msgid="2823268023931811747">"Aikoni ya Programu"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Skrini nzima"</string> - <string name="desktop_text" msgid="1582173066857454541">"Mwonekano wa Kompyuta"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Gawa Skrini"</string> <string name="more_button_text" msgid="3655388105592893530">"Zaidi"</string> <string name="float_button_text" msgid="9221657008391364581">"Inayoelea"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Badilisha uwiano"</string> <string name="close_text" msgid="4986518933445178928">"Funga"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Funga Menyu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Mwonekano wa Kompyuta)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Panua Dirisha kwenye Skrini"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Badilisha ukubwa"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Imeshindwa kuhamishia programu hapa"</string> diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml index a0e7c6acfb05..74ecfdcf73a9 100644 --- a/libs/WindowManager/Shell/res/values-ta/strings.xml +++ b/libs/WindowManager/Shell/res/values-ta/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"சிக்கல்கள் சரிசெய்யப்படவில்லையா?\nமாற்றியமைக்க தட்டவும்"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"கேமரா தொடர்பான சிக்கல்கள் எதுவும் இல்லையா? நிராகரிக்க தட்டவும்."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"ஆப்ஸ் மெனுவை இங்கே பார்க்கலாம்"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"பல ஆப்ஸை ஒன்றாகத் திறக்க டெஸ்க்டாப் காட்சிக்குச் செல்லலாம்"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"ஆப்ஸ் மெனுவிலிருந்து எப்போது வேண்டுமானாலும் முழுத்திரைக்குத் திரும்பலாம்"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"பலவற்றைப் பார்த்தல் மற்றும் செய்தல்"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"திரைப் பிரிப்புக்கு மற்றொரு ஆப்ஸை இழுக்கலாம்"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"ஆப்ஸ் ஹேண்டில்"</string> <string name="app_icon_text" msgid="2823268023931811747">"ஆப்ஸ் ஐகான்"</string> <string name="fullscreen_text" msgid="1162316685217676079">"முழுத்திரை"</string> - <string name="desktop_text" msgid="1582173066857454541">"டெஸ்க்டாப் காட்சி"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"திரையைப் பிரிக்கும்"</string> <string name="more_button_text" msgid="3655388105592893530">"கூடுதல் விருப்பத்தேர்வுகள்"</string> <string name="float_button_text" msgid="9221657008391364581">"மிதக்கும் சாளரம்"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"தோற்ற விகிதத்தை மாற்று"</string> <string name="close_text" msgid="4986518933445178928">"மூடும்"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"மெனுவை மூடும்"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (டெஸ்க்டாப் காட்சி)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"திரையைப் பெரிதாக்கு"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"அளவை மாற்று"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ஆப்ஸை இங்கே நகர்த்த முடியாது"</string> diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml index e0930132e6f3..f46c9b628d1a 100644 --- a/libs/WindowManager/Shell/res/values-te/strings.xml +++ b/libs/WindowManager/Shell/res/values-te/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"దాని సమస్యను పరిష్కరించలేదా?\nపూర్వస్థితికి మార్చడానికి ట్యాప్ చేయండి"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"కెమెరా సమస్యలు లేవా? తీసివేయడానికి ట్యాప్ చేయండి."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"యాప్ మెనూను ఇక్కడ పొందవచ్చు"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"పలు యాప్లను ఒకేసారి తెరవడానికి డెస్క్టాప్ వీక్షణకు ఎంటర్ అవ్వండి"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"యాప్ మెనూ నుండి ఏ సమయంలోనైనా ఫుల్ స్క్రీన్కు తిరిగి రండి"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"చూసి, మరిన్ని చేయండి"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"స్ప్లిట్ స్క్రీన్ కోసం మరొక యాప్లోకి లాగండి"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"యాప్ హ్యాండిల్"</string> <string name="app_icon_text" msgid="2823268023931811747">"యాప్ చిహ్నం"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ఫుల్-స్క్రీన్"</string> - <string name="desktop_text" msgid="1582173066857454541">"డెస్క్టాప్ వీక్షణ"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"స్ప్లిట్ స్క్రీన్"</string> <string name="more_button_text" msgid="3655388105592893530">"మరిన్ని"</string> <string name="float_button_text" msgid="9221657008391364581">"ఫ్లోట్"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"ఆకార నిష్పత్తిని మార్చండి"</string> <string name="close_text" msgid="4986518933445178928">"మూసివేయండి"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"మెనూను మూసివేయండి"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (డెస్క్టాప్ వీక్షణ)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"స్క్రీన్ సైజ్ను పెంచండి"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"సైజ్ మార్చండి"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"యాప్ను ఇక్కడకి తరలించడం సాధ్యం కాదు"</string> diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml index 594ee6c97689..60632ada32bb 100644 --- a/libs/WindowManager/Shell/res/values-th/strings.xml +++ b/libs/WindowManager/Shell/res/values-th/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"หากไม่ได้แก้ไข\nแตะเพื่อเปลี่ยนกลับ"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"หากไม่พบปัญหากับกล้อง แตะเพื่อปิด"</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"ดูเมนูแอปที่นี่ได้"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"เข้าสู่มุมมองบนเดสก์ท็อปเพื่อเปิดหลายแอปพร้อมกัน"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"กลับไปที่โหมดเต็มหน้าจอได้ทุกเมื่อจากเมนูแอป"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"รับชมและทำสิ่งต่างๆ ได้มากขึ้น"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ลากไปไว้ในแอปอื่นเพื่อแยกหน้าจอ"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"แฮนเดิลแอป"</string> <string name="app_icon_text" msgid="2823268023931811747">"ไอคอนแอป"</string> <string name="fullscreen_text" msgid="1162316685217676079">"เต็มหน้าจอ"</string> - <string name="desktop_text" msgid="1582173066857454541">"มุมมองบนเดสก์ท็อป"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"แยกหน้าจอ"</string> <string name="more_button_text" msgid="3655388105592893530">"เพิ่มเติม"</string> <string name="float_button_text" msgid="9221657008391364581">"ล่องลอย"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"เปลี่ยนสัดส่วนการแสดงผล"</string> <string name="close_text" msgid="4986518933445178928">"ปิด"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"ปิดเมนู"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (มุมมองบนเดสก์ท็อป)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ขยายหน้าจอให้ใหญ่สุด"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ปรับขนาด"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ย้ายแอปมาที่นี่ไม่ได้"</string> diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml index f13de5b7846b..ae6df04c255c 100644 --- a/libs/WindowManager/Shell/res/values-tl/strings.xml +++ b/libs/WindowManager/Shell/res/values-tl/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Hindi ito naayos?\nI-tap para i-revert"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Walang isyu sa camera? I-tap para i-dismiss."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Makikita rito ang menu ng app"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Pumasok sa desktop view para magbukas ng maraming app nang sabay-sabay"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Bumalik sa full screen anumang oras mula sa menu ng app"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Tumingin at gumawa ng higit pa"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Mag-drag ng isa pang app para sa split screen"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Handle ng app"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icon ng App"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Fullscreen"</string> - <string name="desktop_text" msgid="1582173066857454541">"Desktop View"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Split Screen"</string> <string name="more_button_text" msgid="3655388105592893530">"Higit pa"</string> <string name="float_button_text" msgid="9221657008391364581">"Float"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Baguhin ang aspect ratio"</string> <string name="close_text" msgid="4986518933445178928">"Isara"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Isara ang Menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Desktop View)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"I-maximize ang Screen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"I-resize"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Hindi mailipat dito ang app"</string> diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml index 61fae05cc71c..116740ef93f7 100644 --- a/libs/WindowManager/Shell/res/values-tr/strings.xml +++ b/libs/WindowManager/Shell/res/values-tr/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Bu işlem sorunu düzeltmedi mi?\nİşlemi geri almak için dokunun"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kameranızda sorun yok mu? Kapatmak için dokunun."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Uygulama menüsünü burada bulabilirsiniz"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Birden fazla uygulamayı birlikte açmak için masaüstü görünümüne geçin"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Uygulama menüsünden dilediğiniz zaman tam ekrana dönebilirsiniz"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Daha fazlasını görün ve yapın"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Bölünmüş ekran için başka bir uygulamayı sürükleyin"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Uygulama tanıtıcısı"</string> <string name="app_icon_text" msgid="2823268023931811747">"Uygulama Simgesi"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Tam Ekran"</string> - <string name="desktop_text" msgid="1582173066857454541">"Masaüstü görünümü"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Bölünmüş Ekran"</string> <string name="more_button_text" msgid="3655388105592893530">"Daha Fazla"</string> <string name="float_button_text" msgid="9221657008391364581">"Havada Süzülen"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"En boy oranını değiştir"</string> <string name="close_text" msgid="4986518933445178928">"Kapat"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Menüyü kapat"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (masaüstü görünümü)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranı Büyüt"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Yeniden boyutlandır"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Uygulama buraya taşınamıyor"</string> diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml index ada82dfdc126..54af06762029 100644 --- a/libs/WindowManager/Shell/res/values-uk/strings.xml +++ b/libs/WindowManager/Shell/res/values-uk/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблему не вирішено?\nНатисніть, щоб скасувати зміни"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Немає проблем із камерою? Торкніться, щоб закрити."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Тут ви знайдете меню додатка"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Щоб відкрити кілька додатків одночасно, перейдіть у режим робочого стола"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"З меню додатка можна будь-коли повернутися в повноекранний режим"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Більше простору та можливостей"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Щоб перейти в режим розділення екрана, перетягніть сюди інший додаток"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Дескриптор додатка"</string> <string name="app_icon_text" msgid="2823268023931811747">"Значок додатка"</string> <string name="fullscreen_text" msgid="1162316685217676079">"На весь екран"</string> - <string name="desktop_text" msgid="1582173066857454541">"Версія для ПК"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Розділити екран"</string> <string name="more_button_text" msgid="3655388105592893530">"Більше"</string> <string name="float_button_text" msgid="9221657008391364581">"Плаваюче вікно"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Змінити формат"</string> <string name="close_text" msgid="4986518933445178928">"Закрити"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Закрити меню"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (версія для ПК)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Розгорнути екран"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Змінити розмір"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Сюди не можна перемістити додаток"</string> diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml index ded104cfd718..635bc4086c0d 100644 --- a/libs/WindowManager/Shell/res/values-ur/strings.xml +++ b/libs/WindowManager/Shell/res/values-ur/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"یہ حل نہیں ہوا؟\nلوٹانے کیلئے تھپتھپائیں"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"کوئی کیمرے کا مسئلہ نہیں ہے؟ برخاست کرنے کیلئے تھپتھپائیں۔"</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"ایپ کا مینو یہاں پایا جا سکتا ہے"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"متعدد ایپس کو ایک ساتھ کھولنے کے لیے ڈیسک ٹاپ منظر میں داخل ہوں"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"ایپ مینو سے کسی بھی وقت فُل اسکرین پر واپس جائیں"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"دیکھیں اور بہت کچھ کریں"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"اسپلٹ اسکرین کے ليے دوسری ایپ میں گھسیٹیں"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"ایپ ہینڈل"</string> <string name="app_icon_text" msgid="2823268023931811747">"ایپ کا آئیکن"</string> <string name="fullscreen_text" msgid="1162316685217676079">"مکمل اسکرین"</string> - <string name="desktop_text" msgid="1582173066857454541">"ڈیسک ٹاپ منظر"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"اسپلٹ اسکرین"</string> <string name="more_button_text" msgid="3655388105592893530">"مزید"</string> <string name="float_button_text" msgid="9221657008391364581">"فلوٹ"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"تناسبی شرح کو تبدیل کریں"</string> <string name="close_text" msgid="4986518933445178928">"بند کریں"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"مینیو بند کریں"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ڈیسک ٹاپ منظر)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"اسکرین کو بڑا کریں"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"سائز تبدیل کریں"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ایپ کو یہاں منتقل نہیں کیا جا سکتا"</string> @@ -154,7 +157,7 @@ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ونڈو کا سائز زیادہ سے زیادہ یا بحال کریں"</string> <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"ایپ ونڈو سائز بڑا کریں"</string> <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"ونڈو سائز بحال کریں"</string> - <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"ایپ ونڈو چھوٹا کریں"</string> + <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"ایپ ونڈو چھوٹی کریں"</string> <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"ایپ ونڈو بند کریں"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"بطور ڈیفالٹ ترتیبات کھولیں"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"اس ایپ کے لیے ویب لنکس کھولنے کا طریقہ منتخب کریں"</string> diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml index 8a9dad029276..6ce2bd859bea 100644 --- a/libs/WindowManager/Shell/res/values-uz/strings.xml +++ b/libs/WindowManager/Shell/res/values-uz/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Tuzatilmadimi?\nQaytarish uchun bosing"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kamera muammosizmi? Yopish uchun bosing."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Ilova menyusi shu yerda chiqadi"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Bir nechta ilovani birga ochish uchun kompyuter versiyasiga kiring"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Ilova menyusi orqali istalganda butun ekranga qaytish mumkin"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Yana boshqa amallar"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Ekranni ikkiga ajratish uchun boshqa ilovani bu yerga torting"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Ilova identifikatori"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ilova belgisi"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Butun ekran"</string> - <string name="desktop_text" msgid="1582173066857454541">"Desktop versiya"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Ekranni ikkiga ajratish"</string> <string name="more_button_text" msgid="3655388105592893530">"Yana"</string> <string name="float_button_text" msgid="9221657008391364581">"Pufakli"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Tomonlar nisbatini oʻzgartirish"</string> <string name="close_text" msgid="4986518933445178928">"Yopish"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Menyuni yopish"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (desktop versiya)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranni yoyish"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Oʻlchamini oʻzgartirish"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ilova bu yerga surilmaydi"</string> diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml index d6c8bc6173fb..67f80c142ea3 100644 --- a/libs/WindowManager/Shell/res/values-vi/strings.xml +++ b/libs/WindowManager/Shell/res/values-vi/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Bạn chưa khắc phục vấn đề?\nHãy nhấn để hủy bỏ"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Không có vấn đề với máy ảnh? Hãy nhấn để đóng."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Bạn có thể tìm thấy trình đơn ứng dụng tại đây"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Chuyển sang chế độ xem trên máy tính để bàn để mở nhiều ứng dụng cùng lúc"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Trở về chế độ toàn màn hình bất cứ lúc nào từ trình đơn ứng dụng"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Xem và làm được nhiều việc hơn"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Kéo một ứng dụng khác vào để chia đôi màn hình"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Ô điều khiển ứng dụng"</string> <string name="app_icon_text" msgid="2823268023931811747">"Biểu tượng ứng dụng"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Toàn màn hình"</string> - <string name="desktop_text" msgid="1582173066857454541">"Chế độ xem trên máy tính để bàn"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Chia đôi màn hình"</string> <string name="more_button_text" msgid="3655388105592893530">"Tuỳ chọn khác"</string> <string name="float_button_text" msgid="9221657008391364581">"Nổi"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Thay đổi tỷ lệ khung hình"</string> <string name="close_text" msgid="4986518933445178928">"Đóng"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Đóng trình đơn"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Chế độ xem trên máy tính để bàn)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Mở rộng màn hình"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Đổi kích thước"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Không di chuyển được ứng dụng đến đây"</string> diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml index 1009afc62f55..b29711df14b9 100644 --- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"没有解决此问题?\n点按即可恢复"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相机没有问题?点按即可忽略。"</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"您可以在此处找到应用菜单"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"进入桌面版视图可同时打开多个应用"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"随时从应用菜单返回全屏模式"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"查看和处理更多任务"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"拖入另一个应用,即可使用分屏模式"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"应用手柄"</string> <string name="app_icon_text" msgid="2823268023931811747">"应用图标"</string> <string name="fullscreen_text" msgid="1162316685217676079">"全屏"</string> - <string name="desktop_text" msgid="1582173066857454541">"桌面版视图"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"分屏"</string> <string name="more_button_text" msgid="3655388105592893530">"更多"</string> <string name="float_button_text" msgid="9221657008391364581">"悬浮"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"更改宽高比"</string> <string name="close_text" msgid="4986518933445178928">"关闭"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"关闭菜单"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g>(桌面版视图)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"最大化屏幕"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"调整大小"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"无法将应用移至此处"</string> diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml index edd67c17fcf4..74e6b5c1e491 100644 --- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"未能修正問題?\n輕按即可還原"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相機冇問題?㩒一下就可以即可閂咗佢。"</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"你可在這裡找到應用程式選單"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"進入桌面電腦檢視模式以同時開啟多個應用程式"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"你可隨時從應用程式選單返回全螢幕"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"瀏覽更多內容及執行更多操作"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"拖入另一個應用程式即可分割螢幕"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"應用程式控點"</string> <string name="app_icon_text" msgid="2823268023931811747">"應用程式圖示"</string> <string name="fullscreen_text" msgid="1162316685217676079">"全螢幕"</string> - <string name="desktop_text" msgid="1582173066857454541">"桌面電腦檢視模式"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"分割螢幕"</string> <string name="more_button_text" msgid="3655388105592893530">"更多"</string> <string name="float_button_text" msgid="9221657008391364581">"浮動"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"變更長寬比"</string> <string name="close_text" msgid="4986518933445178928">"關閉"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"關閉選單"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (桌面電腦檢視模式)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"畫面最大化"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"調整大小"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"應用程式無法移至這裡"</string> diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml index 32d87f3f8ce6..575b217229bd 100644 --- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"未修正問題嗎?\n輕觸即可還原"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相機沒問題嗎?輕觸即可關閉。"</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"你可以在這裡查看應用程式選單"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"進入電腦檢視畫面可以同時開啟多個應用程式"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"你隨時可以從應用程式選單返回全螢幕模式"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"瀏覽更多內容及執行更多操作"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"拖進另一個應用程式即可使用分割畫面模式"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"應用程式控制代碼"</string> <string name="app_icon_text" msgid="2823268023931811747">"應用程式圖示"</string> <string name="fullscreen_text" msgid="1162316685217676079">"全螢幕"</string> - <string name="desktop_text" msgid="1582173066857454541">"電腦檢視畫面"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"分割畫面"</string> <string name="more_button_text" msgid="3655388105592893530">"更多"</string> <string name="float_button_text" msgid="9221657008391364581">"浮動"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"變更顯示比例"</string> <string name="close_text" msgid="4986518933445178928">"關閉"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"關閉選單"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (電腦檢視畫面)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"畫面最大化"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"調整大小"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"應用程式無法移至此處"</string> diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml index 94f0d3476c5e..30403cd21862 100644 --- a/libs/WindowManager/Shell/res/values-zu/strings.xml +++ b/libs/WindowManager/Shell/res/values-zu/strings.xml @@ -100,7 +100,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Akuyilungisanga?\nThepha ukuze ubuyele"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Azikho izinkinga zekhamera? Thepha ukuze ucashise."</string> <string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Imenyu ye-app ingatholakala lapha"</string> - <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"Faka ukubuka kwedeskithophu ukuze uvule ama-app amaningi ndawonye"</string> + <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) --> + <skip /> <string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Buyela esikrinini esigcwele noma nini ukusuka kumenyu ye-app"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Bona futhi wenze okuningi"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Hudula kwenye i-app mayelana nokuhlukanisa isikrini"</string> @@ -121,7 +122,8 @@ <string name="handle_text" msgid="4419667835599523257">"Inkomba ye-App"</string> <string name="app_icon_text" msgid="2823268023931811747">"Isithonjana Se-app"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Isikrini esigcwele"</string> - <string name="desktop_text" msgid="1582173066857454541">"Ukubuka Kwedeskithophu"</string> + <!-- no translation found for desktop_text (9058641752519570266) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Hlukanisa isikrini"</string> <string name="more_button_text" msgid="3655388105592893530">"Okwengeziwe"</string> <string name="float_button_text" msgid="9221657008391364581">"Iflowuthi"</string> @@ -134,7 +136,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Shintsha ukubukeka kwesilinganiselo"</string> <string name="close_text" msgid="4986518933445178928">"Vala"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Vala Imenyu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Ukubuka Kwedeskithophu)"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Khulisa Isikrini Sifike Ekugcineni"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Shintsha usayizi"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"I-app ayikwazi ukuhanjiswa lapha"</string> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 60044ad51d83..9ebbf71138b0 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -437,9 +437,6 @@ <!-- Height of button (32dp) + 2 * margin (5dp each). --> <dimen name="freeform_decor_caption_height">42dp</dimen> - <!-- Height of desktop mode caption for freeform tasks. --> - <dimen name="desktop_mode_freeform_decor_caption_height">40dp</dimen> - <!-- Height of desktop mode caption for fullscreen tasks. --> <dimen name="desktop_mode_fullscreen_decor_caption_height">36dp</dimen> @@ -573,7 +570,10 @@ <dimen name="desktop_mode_handle_menu_corner_radius">26dp</dimen> <!-- The radius of the caption menu icon. --> - <dimen name="desktop_mode_caption_icon_radius">32dp</dimen> + <dimen name="desktop_mode_caption_icon_radius">24dp</dimen> + + <!-- The radius of the icon in the header menu's app info pill. --> + <dimen name="desktop_mode_handle_menu_icon_radius">32dp</dimen> <!-- The radius of the caption menu shadow. --> <dimen name="desktop_mode_handle_menu_shadow_radius">2dp</dimen> diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt index 2dbbeaebd3c0..651e776891db 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt @@ -73,7 +73,11 @@ class DropTargetManager( val newDragZone = state.getMatchingDragZone(x = x, y = y) state.currentDragZone = newDragZone if (oldDragZone != newDragZone) { - dragZoneChangedListener.onDragZoneChanged(from = oldDragZone, to = newDragZone) + dragZoneChangedListener.onDragZoneChanged( + draggedObject = state.draggedObject, + from = oldDragZone, + to = newDragZone + ) updateDropTarget() } } @@ -136,7 +140,7 @@ class DropTargetManager( /** Stores the current drag state. */ private inner class DragState( private val dragZones: List<DragZone>, - draggedObject: DraggedObject + val draggedObject: DraggedObject ) { val initialDragZone = if (draggedObject.initialLocation.isOnLeft(isLayoutRtl)) { @@ -157,7 +161,7 @@ class DropTargetManager( fun onInitialDragZoneSet(dragZone: DragZone) /** Called when the object was dragged to a different drag zone. */ - fun onDragZoneChanged(from: DragZone, to: DragZone) + fun onDragZoneChanged(draggedObject: DraggedObject, from: DragZone, to: DragZone) /** Called when the drag has ended with the zone it ended in. */ fun onDragEnded(zone: DragZone) 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 3e95a0b1100f..efc952644f0b 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 @@ -2644,12 +2644,7 @@ public class BubbleController implements ConfigurationChangeListener, } private void moveBubbleToFullscreen(String key) { - Bubble b = mBubbleData.getBubbleInStackWithKey(key); - if (b == null) { - Log.w(TAG, "can't find bubble with key " + key + " to move to fullscreen"); - return; - } - b.getTaskView().moveToFullscreen(); + // TODO b/388858013: convert the bubble to full screen } private boolean isDeviceLocked() { 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 2c2451cab999..8ac9230c36c3 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 @@ -238,7 +238,6 @@ public class BubbleExpandedView extends LinearLayout { mContext.createContextAsUser( mBubble.getUser(), Context.CONTEXT_RESTRICTED); Intent fillInIntent = new Intent(); - fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); PendingIntent pi = PendingIntent.getActivity( context, /* requestCode= */ 0, @@ -467,6 +466,11 @@ public class BubbleExpandedView extends LinearLayout { new BubbleTaskViewListener.Callback() { @Override public void onTaskCreated() { + // The taskId is saved to use for removeTask, + // preventing appearance in recent tasks. + mTaskId = ((BubbleTaskViewListener) mCurrentTaskViewListener) + .getTaskId(); + setContentVisibility(true); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewListener.java index 63d713495177..9c20e3af9ab4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewListener.java @@ -130,7 +130,6 @@ public class BubbleTaskViewListener implements TaskView.Listener { mContext.createContextAsUser( mBubble.getUser(), Context.CONTEXT_RESTRICTED); Intent fillInIntent = new Intent(); - fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); // First try get pending intent from the bubble PendingIntent pi = mBubble.getPendingIntent(); if (pi == null) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java index d5f2dbdbf5f5..51a5b12edb84 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java @@ -639,7 +639,7 @@ public class BubbleTransitions { @Override public void continueCollapse() { mBubble.cleanupTaskView(); - if (mTaskLeash == null) return; + if (mTaskLeash == null || !mTaskLeash.isValid()) return; SurfaceControl.Transaction t = new SurfaceControl.Transaction(); t.reparent(mTaskLeash, mRootLeash); t.apply(); 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 6c840f020f90..3997412ab459 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 @@ -55,6 +55,7 @@ import com.android.wm.shell.shared.bubbles.DeviceConfig; import com.android.wm.shell.shared.bubbles.DismissView; import com.android.wm.shell.shared.bubbles.DragZone; import com.android.wm.shell.shared.bubbles.DragZoneFactory; +import com.android.wm.shell.shared.bubbles.DraggedObject; import com.android.wm.shell.shared.bubbles.DropTargetManager; import kotlin.Unit; @@ -168,8 +169,8 @@ public class BubbleBarLayerView extends FrameLayout } @Override - public void onDragZoneChanged(@NonNull DragZone from, - @NonNull DragZone to) { + public void onDragZoneChanged(@NonNull DraggedObject draggedObject, + @NonNull DragZone from, @NonNull DragZone to) { final boolean isBubbleLeft = to instanceof DragZone.Bubble.Left; final boolean isBubbleRight = to instanceof DragZone.Bubble.Right; if ((isBubbleLeft || isBubbleRight) @@ -447,9 +448,9 @@ public class BubbleBarLayerView extends FrameLayout bubble.cleanupViews(!inTransition); endAction.run(); }; - if (mBubbleData.getBubbles().isEmpty()) { - // we're removing the last bubble. collapse the expanded view and cleanup bubble views - // at the end. + if (mBubbleData.getBubbles().isEmpty() || inTransition) { + // If we are removing the last bubble or removing the current bubble via transition, + // collapse the expanded view and clean up bubbles at the end. collapse(cleanUp); } else { cleanUp.run(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java index dd2050a5fd5d..f73788486d04 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java @@ -440,11 +440,18 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged statsToken); } - // In case of a hide, the statsToken should not been send yet (as the animation - // is still ongoing). It will be sent at the end of the animation - boolean hideAnimOngoing = !mImeRequestedVisible && mAnimation != null; - setVisibleDirectly(mImeRequestedVisible || mAnimation != null, - hideAnimOngoing ? null : statsToken); + boolean hideAnimOngoing; + boolean reportVisible; + if (android.view.inputmethod.Flags.reportAnimatingInsetsTypes()) { + hideAnimOngoing = false; + reportVisible = mImeRequestedVisible; + } else { + // In case of a hide, the statsToken should not been send yet (as the animation + // is still ongoing). It will be sent at the end of the animation. + hideAnimOngoing = !mImeRequestedVisible && mAnimation != null; + reportVisible = mImeRequestedVisible || mAnimation != null; + } + setVisibleDirectly(reportVisible, hideAnimOngoing ? null : statsToken); } } @@ -628,7 +635,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged + " showing:" + (mAnimationDirection == DIRECTION_SHOW)); } if (android.view.inputmethod.Flags.reportAnimatingInsetsTypes()) { - setAnimating(true); + setAnimating(true /* imeAnimationOngoing */); } int flags = dispatchStartPositioning(mDisplayId, imeTop(hiddenY, defaultY), imeTop(shownY, defaultY), mAnimationDirection == DIRECTION_SHOW, @@ -678,7 +685,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged if (!android.view.inputmethod.Flags.refactorInsetsController()) { dispatchEndPositioning(mDisplayId, mCancelled, t); } else if (android.view.inputmethod.Flags.reportAnimatingInsetsTypes()) { - setAnimating(false); + setAnimating(false /* imeAnimationOngoing */); } if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) { ImeTracker.forLogging().onProgress(mStatsToken, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index 92c3020a14e6..179f03b8a975 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -98,6 +98,7 @@ import com.android.wm.shell.desktopmode.DesktopModeKeyGestureHandler; import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver; import com.android.wm.shell.desktopmode.DesktopModeMoveToDisplayTransitionHandler; import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger; +import com.android.wm.shell.desktopmode.DesktopPipTransitionObserver; import com.android.wm.shell.desktopmode.DesktopTaskChangeListener; import com.android.wm.shell.desktopmode.DesktopTasksController; import com.android.wm.shell.desktopmode.DesktopTasksLimiter; @@ -780,6 +781,7 @@ public abstract class WMShellModule { OverviewToDesktopTransitionObserver overviewToDesktopTransitionObserver, DesksOrganizer desksOrganizer, Optional<DesksTransitionObserver> desksTransitionObserver, + Optional<DesktopPipTransitionObserver> desktopPipTransitionObserver, UserProfileContexts userProfileContexts, DesktopModeCompatPolicy desktopModeCompatPolicy, DragToDisplayTransitionHandler dragToDisplayTransitionHandler, @@ -823,6 +825,7 @@ public abstract class WMShellModule { overviewToDesktopTransitionObserver, desksOrganizer, desksTransitionObserver.get(), + desktopPipTransitionObserver.get(), userProfileContexts, desktopModeCompatPolicy, dragToDisplayTransitionHandler, @@ -1225,6 +1228,7 @@ public abstract class WMShellModule { Transitions transitions, ShellTaskOrganizer shellTaskOrganizer, Optional<DesktopMixedTransitionHandler> desktopMixedTransitionHandler, + Optional<DesktopPipTransitionObserver> desktopPipTransitionObserver, Optional<BackAnimationController> backAnimationController, DesktopWallpaperActivityTokenProvider desktopWallpaperActivityTokenProvider, ShellInit shellInit) { @@ -1237,6 +1241,7 @@ public abstract class WMShellModule { transitions, shellTaskOrganizer, desktopMixedTransitionHandler.get(), + desktopPipTransitionObserver.get(), backAnimationController.get(), desktopWallpaperActivityTokenProvider, shellInit))); @@ -1258,6 +1263,19 @@ public abstract class WMShellModule { @WMSingleton @Provides + static Optional<DesktopPipTransitionObserver> provideDesktopPipTransitionObserver( + Context context + ) { + if (DesktopModeStatus.canEnterDesktopMode(context) + && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue()) { + return Optional.of( + new DesktopPipTransitionObserver()); + } + return Optional.empty(); + } + + @WMSingleton + @Provides static Optional<DesktopMixedTransitionHandler> provideDesktopMixedTransitionHandler( Context context, Transitions transitions, @@ -1472,7 +1490,9 @@ public abstract class WMShellModule { RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, IWindowManager windowManager, ShellTaskOrganizer shellTaskOrganizer, - DesktopWallpaperActivityTokenProvider desktopWallpaperActivityTokenProvider + DesktopWallpaperActivityTokenProvider desktopWallpaperActivityTokenProvider, + InputManager inputManager, + @ShellMainThread Handler mainHandler ) { if (!DesktopModeStatus.canEnterDesktopMode(context)) { return Optional.empty(); @@ -1484,7 +1504,9 @@ public abstract class WMShellModule { rootTaskDisplayAreaOrganizer, windowManager, shellTaskOrganizer, - desktopWallpaperActivityTokenProvider)); + desktopWallpaperActivityTokenProvider, + inputManager, + mainHandler)); } // diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayModeController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayModeController.kt index e89aafe267ed..904d86282c39 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayModeController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayModeController.kt @@ -22,6 +22,8 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.app.WindowConfiguration.windowingModeToString import android.content.Context +import android.hardware.input.InputManager +import android.os.Handler import android.provider.Settings import android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS import android.view.Display.DEFAULT_DISPLAY @@ -29,11 +31,13 @@ import android.view.IWindowManager import android.view.WindowManager.TRANSIT_CHANGE import android.window.DesktopExperienceFlags import android.window.WindowContainerTransaction +import com.android.internal.annotations.VisibleForTesting import com.android.internal.protolog.ProtoLog import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.desktopmode.desktopwallpaperactivity.DesktopWallpaperActivityTokenProvider import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE +import com.android.wm.shell.shared.annotations.ShellMainThread import com.android.wm.shell.transition.Transitions /** Controls the display windowing mode in desktop mode */ @@ -44,8 +48,26 @@ class DesktopDisplayModeController( private val windowManager: IWindowManager, private val shellTaskOrganizer: ShellTaskOrganizer, private val desktopWallpaperActivityTokenProvider: DesktopWallpaperActivityTokenProvider, + private val inputManager: InputManager, + @ShellMainThread private val mainHandler: Handler, ) { + private val onTabletModeChangedListener = + object : InputManager.OnTabletModeChangedListener { + override fun onTabletModeChanged(whenNanos: Long, inTabletMode: Boolean) { + refreshDisplayWindowingMode() + } + } + + init { + if (DesktopExperienceFlags.FORM_FACTOR_BASED_DESKTOP_FIRST_SWITCH.isTrue) { + inputManager.registerOnTabletModeChangedListener( + onTabletModeChangedListener, + mainHandler, + ) + } + } + fun refreshDisplayWindowingMode() { if (!DesktopExperienceFlags.ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING.isTrue) return @@ -89,10 +111,20 @@ class DesktopDisplayModeController( transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null) } - private fun getTargetWindowingModeForDefaultDisplay(): Int { + @VisibleForTesting + fun getTargetWindowingModeForDefaultDisplay(): Int { if (isExtendedDisplayEnabled() && hasExternalDisplay()) { return WINDOWING_MODE_FREEFORM } + if (DesktopExperienceFlags.FORM_FACTOR_BASED_DESKTOP_FIRST_SWITCH.isTrue) { + if (isInClamshellMode()) { + return WINDOWING_MODE_FREEFORM + } + return WINDOWING_MODE_FULLSCREEN + } + + // If form factor-based desktop first switch is disabled, use the default display windowing + // mode here to keep the freeform mode for some form factors (e.g., FEATURE_PC). return windowManager.getWindowingMode(DEFAULT_DISPLAY) } @@ -108,6 +140,8 @@ class DesktopDisplayModeController( private fun hasExternalDisplay() = rootTaskDisplayAreaOrganizer.getDisplayIds().any { it != DEFAULT_DISPLAY } + private fun isInClamshellMode() = inputManager.isInTabletMode() == InputManager.SWITCH_STATE_OFF + private fun logV(msg: String, vararg arguments: Any?) { ProtoLog.v(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt index 5269318943d9..1ea545f3ab67 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt @@ -56,7 +56,6 @@ class DesktopModeKeyGestureHandler( override fun handleKeyGestureEvent(event: KeyGestureEvent, focusedToken: IBinder?): Boolean { if ( - !isKeyGestureSupported(event.keyGestureType) || !desktopTasksController.isPresent || !desktopModeWindowDecorViewModel.isPresent ) { @@ -136,19 +135,6 @@ class DesktopModeKeyGestureHandler( } } - override fun isKeyGestureSupported(gestureType: Int): Boolean = - when (gestureType) { - KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY -> - enableMoveToNextDisplayShortcut() - KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW, - KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW, - KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW, - KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW -> - DesktopModeFlags.ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS.isTrue && - manageKeyGestures() - else -> false - } - // TODO: b/364154795 - wait for the completion of moveToNextDisplay transition, otherwise it // will pick a wrong task when a user quickly perform other actions with keyboard shortcuts // after moveToNextDisplay, and move this to FocusTransitionObserver class. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt index fa98d0339a65..a8b0bafee724 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt @@ -18,10 +18,8 @@ package com.android.wm.shell.desktopmode -import android.annotation.DimenRes import android.app.ActivityManager.RunningTaskInfo import android.app.TaskInfo -import android.content.Context import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK import android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK import android.content.Intent.FLAG_ACTIVITY_NEW_TASK @@ -38,7 +36,6 @@ import android.graphics.Rect import android.os.SystemProperties import android.util.Size import android.window.DesktopModeFlags -import com.android.wm.shell.R import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayLayout @@ -265,13 +262,6 @@ fun isTaskBoundsEqual(taskBounds: Rect, stableBounds: Rect): Boolean { return taskBounds == stableBounds } -/** Returns the app header height in desktop mode in pixels. */ -fun getAppHeaderHeight(context: Context): Int = - context.resources.getDimensionPixelSize(getAppHeaderHeightId()) - -/** Returns the resource id of the app header height in desktop mode. */ -@DimenRes fun getAppHeaderHeightId(): Int = R.dimen.desktop_mode_freeform_decor_caption_height - /** * Returns the task bounds a launching task should inherit from an existing running instance. * Returns null if there are no bounds to inherit. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java index b3b4d59090e8..1938e76cad49 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java @@ -19,6 +19,7 @@ package com.android.wm.shell.desktopmode; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; +import static com.android.internal.policy.SystemBarUtils.getDesktopViewAppHeaderHeightPx; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.NO_INDICATOR; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR; @@ -212,8 +213,7 @@ public class DesktopModeVisualIndicator { com.android.wm.shell.R.dimen.desktop_mode_transition_region_thickness); // Because drags in freeform use task position for indicator calculation, we need to // account for the possibility of the task going off the top of the screen by captionHeight - final int captionHeight = mContext.getResources().getDimensionPixelSize( - com.android.wm.shell.R.dimen.desktop_mode_freeform_decor_caption_height); + final int captionHeight = getDesktopViewAppHeaderHeightPx(mContext); final Region fullscreenRegion = calculateFullscreenRegion(layout, captionHeight); final Region splitLeftRegion = calculateSplitLeftRegion(layout, transitionAreaWidth, captionHeight); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopPipTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopPipTransitionObserver.kt new file mode 100644 index 000000000000..efd3866e1bc4 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopPipTransitionObserver.kt @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2025 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.desktopmode + +import android.app.WindowConfiguration.WINDOWING_MODE_PINNED +import android.os.IBinder +import android.window.DesktopModeFlags +import android.window.TransitionInfo +import com.android.internal.protolog.ProtoLog +import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE + +/** + * Observer of PiP in Desktop Mode transitions. At the moment, this is specifically tracking a PiP + * transition for a task that is entering PiP via the minimize button on the caption bar. + */ +class DesktopPipTransitionObserver { + private val pendingPipTransitions = mutableMapOf<IBinder, PendingPipTransition>() + + /** Adds a pending PiP transition to be tracked. */ + fun addPendingPipTransition(transition: PendingPipTransition) { + if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue) return + pendingPipTransitions[transition.token] = transition + } + + /** + * Called when any transition is ready, which may include transitions not tracked by this + * observer. + */ + fun onTransitionReady(transition: IBinder, info: TransitionInfo) { + if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue) return + val pipTransition = pendingPipTransitions.remove(transition) ?: return + + logD("Desktop PiP transition ready: %s", transition) + for (change in info.changes) { + val taskInfo = change.taskInfo + if (taskInfo == null || taskInfo.taskId == -1) { + continue + } + + if ( + taskInfo.taskId == pipTransition.taskId && + taskInfo.windowingMode == WINDOWING_MODE_PINNED + ) { + logD("Desktop PiP transition was successful") + pipTransition.onSuccess() + return + } + } + logD("Change with PiP task not found in Desktop PiP transition; likely failed") + } + + /** + * Data tracked for a pending PiP transition. + * + * @property token the PiP transition that is started. + * @property taskId task id of the task entering PiP. + * @property onSuccess callback to be invoked if the PiP transition is successful. + */ + data class PendingPipTransition(val token: IBinder, val taskId: Int, val onSuccess: () -> Unit) + + private fun logD(msg: String, vararg arguments: Any?) { + ProtoLog.d(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) + } + + private companion object { + private const val TAG = "DesktopPipTransitionObserver" + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt index 8636bc1f56c2..0c2ee4648a43 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt @@ -68,7 +68,6 @@ class DesktopRepository( * @property topTransparentFullscreenTaskId the task id of any current top transparent * fullscreen task launched on top of the desk. Cleared when the transparent task is closed or * sent to back. (top is at index 0). - * @property pipTaskId the task id of PiP task entered while in Desktop Mode. */ private data class Desk( val deskId: Int, @@ -81,7 +80,6 @@ class DesktopRepository( val freeformTasksInZOrder: ArrayList<Int> = ArrayList(), var fullImmersiveTaskId: Int? = null, var topTransparentFullscreenTaskId: Int? = null, - var pipTaskId: Int? = null, ) { fun deepCopy(): Desk = Desk( @@ -94,7 +92,6 @@ class DesktopRepository( freeformTasksInZOrder = ArrayList(freeformTasksInZOrder), fullImmersiveTaskId = fullImmersiveTaskId, topTransparentFullscreenTaskId = topTransparentFullscreenTaskId, - pipTaskId = pipTaskId, ) // TODO: b/362720497 - remove when multi-desktops is enabled where instances aren't @@ -107,7 +104,6 @@ class DesktopRepository( freeformTasksInZOrder.clear() fullImmersiveTaskId = null topTransparentFullscreenTaskId = null - pipTaskId = null } } @@ -127,9 +123,6 @@ class DesktopRepository( /* Tracks last bounds of task before toggled to immersive state. */ private val boundsBeforeFullImmersiveByTaskId = SparseArray<Rect>() - /* Callback for when a pending PiP transition has been aborted. */ - private var onPipAbortedCallback: ((Int, Int) -> Unit)? = null - private var desktopGestureExclusionListener: Consumer<Region>? = null private var desktopGestureExclusionExecutor: Executor? = null @@ -611,57 +604,6 @@ class DesktopRepository( } /** - * Set whether the given task is the Desktop-entered PiP task in this display's active desk. - * - * TODO: b/389960283 - add explicit [deskId] argument. - */ - fun setTaskInPip(displayId: Int, taskId: Int, enterPip: Boolean) { - val activeDesk = - desktopData.getActiveDesk(displayId) - ?: error("Expected active desk in display: $displayId") - if (enterPip) { - activeDesk.pipTaskId = taskId - } else { - activeDesk.pipTaskId = - if (activeDesk.pipTaskId == taskId) null - else { - logW( - "setTaskInPip: taskId=%d did not match saved taskId=%d", - taskId, - activeDesk.pipTaskId, - ) - activeDesk.pipTaskId - } - } - } - - /** - * Returns whether the given task is the Desktop-entered PiP task in this display's active desk. - * - * TODO: b/389960283 - add explicit [deskId] argument. - */ - fun isTaskMinimizedPipInDisplay(displayId: Int, taskId: Int): Boolean = - desktopData.getActiveDesk(displayId)?.pipTaskId == taskId - - /** - * Saves callback to handle a pending PiP transition being aborted. - * - * TODO: b/389960283 - add explicit [deskId] argument. - */ - fun setOnPipAbortedCallback(callbackIfPipAborted: ((displayId: Int, pipTaskId: Int) -> Unit)?) { - onPipAbortedCallback = callbackIfPipAborted - } - - /** - * Invokes callback to handle a pending PiP transition with the given task id being aborted. - * - * TODO: b/389960283 - add explicit [deskId] argument. - */ - fun onPipAborted(displayId: Int, pipTaskId: Int) { - onPipAbortedCallback?.invoke(displayId, pipTaskId) - } - - /** * Set whether the given task is the full-immersive task in this display's active desk. * * TODO: b/389960283 - consider forcing callers to use [setTaskInFullImmersiveStateInDesk] with 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 d0356d55035d..1f0774c24143 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 @@ -76,6 +76,7 @@ import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_SNAP_RESIZE import com.android.internal.jank.InteractionJankMonitor +import com.android.internal.policy.SystemBarUtils.getDesktopViewAppHeaderHeightPx import com.android.internal.protolog.ProtoLog import com.android.internal.util.LatencyTracker import com.android.window.flags.Flags @@ -214,6 +215,7 @@ class DesktopTasksController( private val overviewToDesktopTransitionObserver: OverviewToDesktopTransitionObserver, private val desksOrganizer: DesksOrganizer, private val desksTransitionObserver: DesksTransitionObserver, + private val desktopPipTransitionObserver: DesktopPipTransitionObserver, private val userProfileContexts: UserProfileContexts, private val desktopModeCompatPolicy: DesktopModeCompatPolicy, private val dragToDisplayTransitionHandler: DragToDisplayTransitionHandler, @@ -787,10 +789,30 @@ class DesktopTasksController( fun minimizeTask(taskInfo: RunningTaskInfo, minimizeReason: MinimizeReason) { val wct = WindowContainerTransaction() - + val taskId = taskInfo.taskId + val displayId = taskInfo.displayId + val deskId = + taskRepository.getDeskIdForTask(taskInfo.taskId) + ?: if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { + logW("minimizeTask: desk not found for task: ${taskInfo.taskId}") + return + } else { + getDefaultDeskId(taskInfo.displayId) + } + val isLastTask = + if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { + taskRepository.isOnlyVisibleNonClosingTaskInDesk( + taskId = taskId, + deskId = checkNotNull(deskId) { "Expected non-null deskId" }, + displayId = displayId, + ) + } else { + taskRepository.isOnlyVisibleNonClosingTask(taskId = taskId, displayId = displayId) + } val isMinimizingToPip = DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue && - (taskInfo.pictureInPictureParams?.isAutoEnterEnabled() ?: false) + (taskInfo.pictureInPictureParams?.isAutoEnterEnabled ?: false) + // If task is going to PiP, start a PiP transition instead of a minimize transition if (isMinimizingToPip) { val requestInfo = @@ -804,75 +826,60 @@ class DesktopTasksController( ) val requestRes = transitions.dispatchRequest(Binder(), requestInfo, /* skip= */ null) wct.merge(requestRes.second, true) - freeformTaskTransitionStarter.startPipTransition(wct) - taskRepository.setTaskInPip(taskInfo.displayId, taskInfo.taskId, enterPip = true) - taskRepository.setOnPipAbortedCallback { displayId, taskId -> - minimizeTaskInner(shellTaskOrganizer.getRunningTaskInfo(taskId)!!, minimizeReason) - taskRepository.setTaskInPip(displayId, taskId, enterPip = false) - } - return - } - - minimizeTaskInner(taskInfo, minimizeReason) - } - private fun minimizeTaskInner(taskInfo: RunningTaskInfo, minimizeReason: MinimizeReason) { - val taskId = taskInfo.taskId - val deskId = taskRepository.getDeskIdForTask(taskInfo.taskId) - if (deskId == null && DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { - logW("minimizeTaskInner: desk not found for task: ${taskInfo.taskId}") - return - } - val displayId = taskInfo.displayId - val wct = WindowContainerTransaction() - - snapEventHandler.removeTaskIfTiled(displayId, taskId) - val willExitDesktop = willExitDesktop(taskId, displayId, forceExitDesktop = false) - val desktopExitRunnable = - performDesktopExitCleanUp( - wct = wct, - deskId = deskId, - displayId = displayId, - willExitDesktop = willExitDesktop, - ) - // Notify immersive handler as it might need to exit immersive state. - val exitResult = - desktopImmersiveController.exitImmersiveIfApplicable( - wct = wct, - taskInfo = taskInfo, - reason = DesktopImmersiveController.ExitReason.MINIMIZED, - ) - if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { - desksOrganizer.minimizeTask( - wct = wct, - deskId = checkNotNull(deskId) { "Expected non-null deskId" }, - task = taskInfo, + desktopPipTransitionObserver.addPendingPipTransition( + DesktopPipTransitionObserver.PendingPipTransition( + token = freeformTaskTransitionStarter.startPipTransition(wct), + taskId = taskInfo.taskId, + onSuccess = { + onDesktopTaskEnteredPip( + taskId = taskId, + deskId = deskId, + displayId = taskInfo.displayId, + taskIsLastVisibleTaskBeforePip = isLastTask, + ) + }, + ) ) } else { - wct.reorder(taskInfo.token, /* onTop= */ false) - } - val isLastTask = + snapEventHandler.removeTaskIfTiled(displayId, taskId) + val willExitDesktop = willExitDesktop(taskId, displayId, forceExitDesktop = false) + val desktopExitRunnable = + performDesktopExitCleanUp( + wct = wct, + deskId = deskId, + displayId = displayId, + willExitDesktop = willExitDesktop, + ) + // Notify immersive handler as it might need to exit immersive state. + val exitResult = + desktopImmersiveController.exitImmersiveIfApplicable( + wct = wct, + taskInfo = taskInfo, + reason = DesktopImmersiveController.ExitReason.MINIMIZED, + ) if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { - taskRepository.isOnlyVisibleNonClosingTaskInDesk( - taskId = taskId, + desksOrganizer.minimizeTask( + wct = wct, deskId = checkNotNull(deskId) { "Expected non-null deskId" }, - displayId = displayId, + task = taskInfo, ) } else { - taskRepository.isOnlyVisibleNonClosingTask(taskId = taskId, displayId = displayId) + wct.reorder(taskInfo.token, /* onTop= */ false) } - val transition = - freeformTaskTransitionStarter.startMinimizedModeTransition(wct, taskId, isLastTask) - desktopTasksLimiter.ifPresent { - it.addPendingMinimizeChange( - transition = transition, - displayId = displayId, - taskId = taskId, - minimizeReason = minimizeReason, - ) + val transition = + freeformTaskTransitionStarter.startMinimizedModeTransition(wct, taskId, isLastTask) + desktopTasksLimiter.ifPresent { + it.addPendingMinimizeChange( + transition = transition, + displayId = displayId, + taskId = taskId, + minimizeReason = minimizeReason, + ) + } + exitResult.asExit()?.runOnTransitionStart?.invoke(transition) + desktopExitRunnable?.invoke(transition) } - exitResult.asExit()?.runOnTransitionStart?.invoke(transition) - desktopExitRunnable?.invoke(transition) } /** Move a task with given `taskId` to fullscreen */ @@ -1840,7 +1847,11 @@ class DesktopTasksController( displayId: Int, forceExitDesktop: Boolean, ): Boolean { - if (forceExitDesktop && DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { + if ( + forceExitDesktop && + (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue || + DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue) + ) { // |forceExitDesktop| is true when the callers knows we'll exit desktop, such as when // explicitly going fullscreen, so there's no point in checking the desktop state. return true @@ -1857,6 +1868,33 @@ class DesktopTasksController( return true } + /** Potentially perform Desktop cleanup after a task successfully enters PiP. */ + @VisibleForTesting + fun onDesktopTaskEnteredPip( + taskId: Int, + deskId: Int, + displayId: Int, + taskIsLastVisibleTaskBeforePip: Boolean, + ) { + if ( + !willExitDesktop(taskId, displayId, forceExitDesktop = taskIsLastVisibleTaskBeforePip) + ) { + return + } + + val wct = WindowContainerTransaction() + val desktopExitRunnable = + performDesktopExitCleanUp( + wct = wct, + deskId = deskId, + displayId = displayId, + willExitDesktop = true, + ) + + val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null) + desktopExitRunnable?.invoke(transition) + } + private fun performDesktopExitCleanupIfNeeded( taskId: Int, deskId: Int? = null, @@ -2631,7 +2669,7 @@ class DesktopTasksController( // Caption insets stay fixed and don't scale with bounds. val captionInsets = if (desktopModeCompatPolicy.shouldExcludeCaptionFromAppBounds(taskInfo)) { - getAppHeaderHeight(context) + getDesktopViewAppHeaderHeightPx(context) } else { 0 } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt index 7dabeb7c9d15..c670ac3c4488 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt @@ -23,7 +23,6 @@ import android.os.IBinder import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CLOSE import android.view.WindowManager.TRANSIT_OPEN -import android.view.WindowManager.TRANSIT_PIP import android.view.WindowManager.TRANSIT_TO_BACK import android.window.DesktopExperienceFlags import android.window.DesktopModeFlags @@ -41,8 +40,6 @@ import com.android.wm.shell.shared.TransitionUtil import com.android.wm.shell.shared.desktopmode.DesktopModeStatus import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.Transitions -import com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP -import com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP /** * A [Transitions.TransitionObserver] that observes shell transitions and updates the @@ -55,6 +52,7 @@ class DesktopTasksTransitionObserver( private val transitions: Transitions, private val shellTaskOrganizer: ShellTaskOrganizer, private val desktopMixedTransitionHandler: DesktopMixedTransitionHandler, + private val desktopPipTransitionObserver: DesktopPipTransitionObserver, private val backAnimationController: BackAnimationController, private val desktopWallpaperActivityTokenProvider: DesktopWallpaperActivityTokenProvider, shellInit: ShellInit, @@ -63,8 +61,6 @@ class DesktopTasksTransitionObserver( data class CloseWallpaperTransition(val transition: IBinder, val displayId: Int) private var transitionToCloseWallpaper: CloseWallpaperTransition? = null - /* Pending PiP transition and its associated display id and task id. */ - private var pendingPipTransitionAndPipTask: Triple<IBinder, Int, Int>? = null private var currentProfileId: Int init { @@ -98,33 +94,7 @@ class DesktopTasksTransitionObserver( removeTaskIfNeeded(info) } removeWallpaperOnLastTaskClosingIfNeeded(transition, info) - - val desktopRepository = desktopUserRepositories.getProfile(currentProfileId) - info.changes.forEach { change -> - change.taskInfo?.let { taskInfo -> - if ( - DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue && - desktopRepository.isTaskMinimizedPipInDisplay( - taskInfo.displayId, - taskInfo.taskId, - ) - ) { - when (info.type) { - TRANSIT_PIP -> - pendingPipTransitionAndPipTask = - Triple(transition, taskInfo.displayId, taskInfo.taskId) - - TRANSIT_EXIT_PIP, - TRANSIT_REMOVE_PIP -> - desktopRepository.setTaskInPip( - taskInfo.displayId, - taskInfo.taskId, - enterPip = false, - ) - } - } - } - } + desktopPipTransitionObserver.onTransitionReady(transition, info) } private fun removeTaskIfNeeded(info: TransitionInfo) { @@ -299,18 +269,6 @@ class DesktopTasksTransitionObserver( } } transitionToCloseWallpaper = null - } else if (pendingPipTransitionAndPipTask?.first == transition) { - val desktopRepository = desktopUserRepositories.getProfile(currentProfileId) - if (aborted) { - pendingPipTransitionAndPipTask?.let { - desktopRepository.onPipAborted( - /*displayId=*/ it.second, - /* taskId=*/ it.third, - ) - } - } - desktopRepository.setOnPipAbortedCallback(null) - pendingPipTransitionAndPipTask = null } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java index 383afcf6f821..f81f330e50c4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java @@ -20,6 +20,7 @@ import android.app.PictureInPictureParams; import android.content.Context; import android.graphics.Matrix; import android.graphics.Rect; +import android.os.Bundle; import android.os.SystemProperties; import android.view.SurfaceControl; import android.window.WindowContainerToken; @@ -47,7 +48,7 @@ import java.util.function.Supplier; /** * Scheduler for Shell initiated PiP transitions and animations. */ -public class PipScheduler { +public class PipScheduler implements PipTransitionState.PipTransitionStateChangedListener { private static final String TAG = PipScheduler.class.getSimpleName(); /** @@ -71,6 +72,7 @@ public class PipScheduler { private final PipSurfaceTransactionHelper mPipSurfaceTransactionHelper; @Nullable private Runnable mUpdateMovementBoundsRunnable; + @Nullable private PipAlphaAnimator mOverlayFadeoutAnimator; private PipAlphaAnimatorSupplier mPipAlphaAnimatorSupplier; private Supplier<PictureInPictureParams> mPipParamsSupplier; @@ -85,6 +87,7 @@ public class PipScheduler { mPipBoundsState = pipBoundsState; mMainExecutor = mainExecutor; mPipTransitionState = pipTransitionState; + mPipTransitionState.addPipTransitionStateChangedListener(this); mPipDesktopState = pipDesktopState; mSplitScreenControllerOptional = splitScreenControllerOptional; @@ -238,12 +241,16 @@ public class PipScheduler { void startOverlayFadeoutAnimation(@NonNull SurfaceControl overlayLeash, boolean withStartDelay, @NonNull Runnable onAnimationEnd) { - PipAlphaAnimator animator = mPipAlphaAnimatorSupplier.get(mContext, overlayLeash, + mOverlayFadeoutAnimator = mPipAlphaAnimatorSupplier.get(mContext, overlayLeash, null /* startTx */, null /* finishTx */, PipAlphaAnimator.FADE_OUT); - animator.setDuration(CONTENT_OVERLAY_FADE_OUT_DURATION_MS); - animator.setStartDelay(withStartDelay ? EXTRA_CONTENT_OVERLAY_FADE_OUT_DELAY_MS : 0); - animator.setAnimationEndCallback(onAnimationEnd); - animator.start(); + mOverlayFadeoutAnimator.setDuration(CONTENT_OVERLAY_FADE_OUT_DURATION_MS); + mOverlayFadeoutAnimator.setStartDelay(withStartDelay + ? EXTRA_CONTENT_OVERLAY_FADE_OUT_DELAY_MS : 0); + mOverlayFadeoutAnimator.setAnimationEndCallback(() -> { + onAnimationEnd.run(); + mOverlayFadeoutAnimator = null; + }); + mOverlayFadeoutAnimator.start(); } void setUpdateMovementBoundsRunnable(@Nullable Runnable updateMovementBoundsRunnable) { @@ -289,6 +296,21 @@ public class PipScheduler { mSurfaceControlTransactionFactory = factory; } + @Override + public void onPipTransitionStateChanged(@PipTransitionState.TransitionState int oldState, + @PipTransitionState.TransitionState int newState, + @android.annotation.Nullable Bundle extra) { + switch (newState) { + case PipTransitionState.EXITING_PIP: + case PipTransitionState.SCHEDULED_BOUNDS_CHANGE: + if (mOverlayFadeoutAnimator != null && mOverlayFadeoutAnimator.isStarted()) { + mOverlayFadeoutAnimator.end(); + mOverlayFadeoutAnimator = null; + } + break; + } + } + @VisibleForTesting interface PipAlphaAnimatorSupplier { PipAlphaAnimator get(@NonNull Context context, @@ -303,6 +325,17 @@ public class PipScheduler { mPipAlphaAnimatorSupplier = supplier; } + @VisibleForTesting + void setOverlayFadeoutAnimator(@NonNull PipAlphaAnimator animator) { + mOverlayFadeoutAnimator = animator; + } + + @VisibleForTesting + @Nullable + PipAlphaAnimator getOverlayFadeoutAnimator() { + return mOverlayFadeoutAnimator; + } + void setPipParamsSupplier(@NonNull Supplier<PictureInPictureParams> pipParamsSupplier) { mPipParamsSupplier = pipParamsSupplier; } 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 c370c0cb0930..75c09829e551 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 @@ -93,7 +93,6 @@ import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.IActivityTaskManager; import android.app.PendingIntent; -import android.app.PictureInPictureParams; import android.app.TaskInfo; import android.content.ActivityNotFoundException; import android.content.Context; @@ -2249,10 +2248,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, setRootForceTranslucent(true, wct); if (!enableFlexibleSplit()) { - //TODO(b/373709676) Need to figure out how adjacentRoots work for flex split + // TODO: consider support 3 splits // Make the stages adjacent to each other so they occlude what's behind them. - wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token); + wct.setAdjacentRootSet(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token); mSplitLayout.getInvisibleBounds(mTempRect1); wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1); } @@ -2263,7 +2262,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, }); mLaunchAdjacentController.setLaunchAdjacentRoot(mSideStage.mRootTaskInfo.token); } else { - // TODO(b/373709676) Need to figure out how adjacentRoots work for flex split + // TODO: consider support 3 splits } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java index 5e8c1fe2aa8d..2d7fec3a5302 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java @@ -445,9 +445,4 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL private static int getCaptionHeightIdStatic(@WindowingMode int windowingMode) { return R.dimen.freeform_decor_caption_height; } - - @Override - int getCaptionViewId() { - return R.id.caption; - } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecoration.java index 3182745d813e..88f64bca280d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecoration.java @@ -108,11 +108,6 @@ public class CarWindowDecoration extends WindowDecoration<WindowDecorLinearLayou return new Rect(); } - @Override - int getCaptionViewId() { - return R.id.caption; - } - private void updateRelayoutParams( RelayoutParams relayoutParams, ActivityManager.RunningTaskInfo taskInfo, 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 673c3f66cb6c..1b5fdbb973d5 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 @@ -27,6 +27,7 @@ import static android.view.MotionEvent.ACTION_UP; import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION; import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS; +import static com.android.internal.policy.SystemBarUtils.getDesktopViewAppHeaderHeightId; import static com.android.wm.shell.shared.desktopmode.DesktopModeStatus.canEnterDesktopMode; import static com.android.wm.shell.shared.desktopmode.DesktopModeStatus.canEnterDesktopModeOrShowAppHandle; import static com.android.wm.shell.shared.desktopmode.DesktopModeStatus.isDesktopModeSupportedOnDisplay; @@ -1096,8 +1097,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin return Resources.ID_NULL; } - private PointF calculateMaximizeMenuPosition(int menuWidth, int menuHeight) { - final PointF position = new PointF(); + private Point calculateMaximizeMenuPosition(int menuWidth, int menuHeight) { + final Point position = new Point(); final Resources resources = mContext.getResources(); final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(mTaskInfo.displayId); @@ -1112,11 +1113,11 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final int[] maximizeButtonLocation = new int[2]; maximizeWindowButton.getLocationInWindow(maximizeButtonLocation); - float menuLeft = (mPositionInParent.x + maximizeButtonLocation[0] - ((float) (menuWidth - - maximizeWindowButton.getWidth()) / 2)); - float menuTop = (mPositionInParent.y + captionHeight); - final float menuRight = menuLeft + menuWidth; - final float menuBottom = menuTop + menuHeight; + int menuLeft = (mPositionInParent.x + maximizeButtonLocation[0] - (menuWidth + - maximizeWindowButton.getWidth()) / 2); + int menuTop = (mPositionInParent.y + captionHeight); + final int menuRight = menuLeft + menuWidth; + final int menuBottom = menuTop + menuHeight; // If the menu is out of screen bounds, shift it as needed if (menuLeft < 0) { @@ -1128,7 +1129,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin menuTop = (displayHeight - menuHeight); } - return new PointF(menuLeft, menuTop); + return new Point(menuLeft, menuTop); } boolean isHandleMenuActive() { @@ -1768,18 +1769,13 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin private static int getCaptionHeightIdStatic(@WindowingMode int windowingMode) { return windowingMode == WINDOWING_MODE_FULLSCREEN ? com.android.internal.R.dimen.status_bar_height_default - : DesktopModeUtils.getAppHeaderHeightId(); + : getDesktopViewAppHeaderHeightId(); } private int getCaptionHeight(@WindowingMode int windowingMode) { return loadDimensionPixelSize(mContext.getResources(), getCaptionHeightId(windowingMode)); } - @Override - int getCaptionViewId() { - return R.id.desktop_mode_caption; - } - void setAnimatingTaskResizeOrReposition(boolean animatingTaskResizeOrReposition) { if (mRelayoutParams.mLayoutResId == R.layout.desktop_mode_app_handle) return; final boolean inFullImmersive = 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 ad3525af3f94..5d1a7a0cc3a2 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 @@ -26,7 +26,7 @@ import android.content.res.ColorStateList import android.content.res.Resources import android.graphics.Paint import android.graphics.PixelFormat -import android.graphics.PointF +import android.graphics.Point import android.graphics.Rect import android.graphics.drawable.Drawable import android.graphics.drawable.GradientDrawable @@ -90,7 +90,7 @@ class MaximizeMenu( private val displayController: DisplayController, private val taskInfo: RunningTaskInfo, private val decorWindowContext: Context, - private val positionSupplier: (Int, Int) -> PointF, + private val positionSupplier: (Int, Int) -> Point, private val transactionSupplier: Supplier<Transaction> = Supplier { Transaction() } ) { private var maximizeMenu: AdditionalViewHostViewContainer? = null @@ -100,14 +100,14 @@ class MaximizeMenu( private val cornerRadius = loadDimensionPixelSize( R.dimen.desktop_mode_maximize_menu_corner_radius ).toFloat() - private lateinit var menuPosition: PointF + private lateinit var menuPosition: Point private val menuPadding = loadDimensionPixelSize(R.dimen.desktop_mode_menu_padding) /** Position the menu relative to the caption's position. */ fun positionMenu(t: Transaction) { menuPosition = positionSupplier(maximizeMenuView?.measureWidth() ?: 0, maximizeMenuView?.measureHeight() ?: 0) - t.setPosition(leash, menuPosition.x, menuPosition.y) + t.setPosition(leash, menuPosition.x.toFloat(), menuPosition.y.toFloat()) } /** Creates and shows the maximize window. */ @@ -208,8 +208,8 @@ class MaximizeMenu( val menuHeight = menuView.measureHeight() menuPosition = positionSupplier(menuWidth, menuHeight) val lp = WindowManager.LayoutParams( - menuWidth.toInt(), - menuHeight.toInt(), + menuWidth, + menuHeight, WindowManager.LayoutParams.TYPE_APPLICATION, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, @@ -222,7 +222,7 @@ class MaximizeMenu( // Bring menu to front when open t.setLayer(leash, TaskConstants.TASK_CHILD_LAYER_FLOATING_MENU) - .setPosition(leash, menuPosition.x, menuPosition.y) + .setPosition(leash, menuPosition.x.toFloat(), menuPosition.y.toFloat()) .setCornerRadius(leash, cornerRadius) .show(leash) maximizeMenu = @@ -1047,7 +1047,7 @@ interface MaximizeMenuFactory { displayController: DisplayController, taskInfo: RunningTaskInfo, decorWindowContext: Context, - positionSupplier: (Int, Int) -> PointF, + positionSupplier: (Int, Int) -> Point, transactionSupplier: Supplier<Transaction> ): MaximizeMenu } @@ -1060,7 +1060,7 @@ object DefaultMaximizeMenuFactory : MaximizeMenuFactory { displayController: DisplayController, taskInfo: RunningTaskInfo, decorWindowContext: Context, - positionSupplier: (Int, Int) -> PointF, + positionSupplier: (Int, Int) -> Point, transactionSupplier: Supplier<Transaction> ): MaximizeMenu { return MaximizeMenu( 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 bde46a1bc375..68e3d6e277e5 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 @@ -629,32 +629,16 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> */ private void updateCaptionVisibility(View rootView, @NonNull RelayoutParams params) { mIsCaptionVisible = params.mIsCaptionVisible; - setCaptionVisibility(rootView, mIsCaptionVisible); } void setTaskDragResizer(TaskDragResizer taskDragResizer) { mTaskDragResizer = taskDragResizer; } - // TODO(b/346441962): Move these three methods closer to implementing or View-level classes to - // keep implementation details more encapsulated. - private void setCaptionVisibility(View rootView, boolean visible) { - if (rootView == null) { - return; - } - final int v = visible ? View.VISIBLE : View.GONE; - final View captionView = rootView.findViewById(getCaptionViewId()); - captionView.setVisibility(v); - } - int getCaptionHeightId(@WindowingMode int windowingMode) { return Resources.ID_NULL; } - int getCaptionViewId() { - return Resources.ID_NULL; - } - /** * Obtains the {@link Display} instance for the display ID in {@link #mTaskInfo} if it exists or * registers {@link #mOnDisplaysChangedListener} if it doesn't. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt index c3d15df6eae5..9c55f0ecda93 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.windowdecor.tiling import android.app.ActivityManager.RunningTaskInfo +import android.app.WindowConfiguration.WINDOWING_MODE_PINNED import android.content.Context import android.content.res.Configuration import android.content.res.Resources @@ -28,9 +29,11 @@ import android.view.SurfaceControl import android.view.SurfaceControl.Transaction import android.view.WindowManager.TRANSIT_CHANGE import android.view.WindowManager.TRANSIT_OPEN +import android.view.WindowManager.TRANSIT_PIP import android.view.WindowManager.TRANSIT_TO_BACK import android.view.WindowManager.TRANSIT_TO_FRONT import android.window.TransitionInfo +import android.window.TransitionInfo.Change import android.window.TransitionRequestInfo import android.window.WindowContainerTransaction import com.android.internal.annotations.VisibleForTesting @@ -422,6 +425,8 @@ class DesktopTilingWindowDecoration( change.taskInfo?.let { if (it.isFullscreen || isMinimized(change.mode, info.type)) { removeTaskIfTiled(it.taskId, /* taskVanished= */ false, it.isFullscreen) + } else if (isEnteringPip(change, info.type)) { + removeTaskIfTiled(it.taskId, /* taskVanished= */ true, it.isFullscreen) } } } @@ -434,6 +439,27 @@ class DesktopTilingWindowDecoration( infoType == TRANSIT_OPEN)) } + private fun isEnteringPip(change: Change, transitType: Int): Boolean { + if (change.taskInfo != null && change.taskInfo?.windowingMode == WINDOWING_MODE_PINNED) { + // - TRANSIT_PIP: type (from RootWindowContainer) + // - TRANSIT_OPEN (from apps that enter PiP instantly on opening, mostly from + // CTS/Flicker tests). + // - TRANSIT_TO_FRONT, though uncommon with triggering PiP, should semantically also + // be allowed to animate if the task in question is pinned already - see b/308054074. + // - TRANSIT_CHANGE: This can happen if the request to enter PIP happens when we are + // collecting for another transition, such as TRANSIT_CHANGE (display rotation). + if ( + transitType == TRANSIT_PIP || + transitType == TRANSIT_OPEN || + transitType == TRANSIT_TO_FRONT || + transitType == TRANSIT_CHANGE + ) { + return true + } + } + return false + } + class AppResizingHelper( val taskInfo: RunningTaskInfo, val desktopModeWindowDecoration: DesktopModeWindowDecoration, @@ -550,12 +576,16 @@ class DesktopTilingWindowDecoration( taskVanished: Boolean = false, shouldDelayUpdate: Boolean = false, ) { + val taskRepository = desktopUserRepositories.current if (taskId == leftTaskResizingHelper?.taskInfo?.taskId) { removeTask(leftTaskResizingHelper, taskVanished, shouldDelayUpdate) leftTaskResizingHelper = null - rightTaskResizingHelper - ?.desktopModeWindowDecoration - ?.updateDisabledResizingEdge(NONE, shouldDelayUpdate) + val taskId = rightTaskResizingHelper?.taskInfo?.taskId + if (taskId != null && taskRepository.isVisibleTask(taskId)) { + rightTaskResizingHelper + ?.desktopModeWindowDecoration + ?.updateDisabledResizingEdge(NONE, shouldDelayUpdate) + } tearDownTiling() return } @@ -563,9 +593,12 @@ class DesktopTilingWindowDecoration( if (taskId == rightTaskResizingHelper?.taskInfo?.taskId) { removeTask(rightTaskResizingHelper, taskVanished, shouldDelayUpdate) rightTaskResizingHelper = null - leftTaskResizingHelper - ?.desktopModeWindowDecoration - ?.updateDisabledResizingEdge(NONE, shouldDelayUpdate) + val taskId = leftTaskResizingHelper?.taskInfo?.taskId + if (taskId != null && taskRepository.isVisibleTask(taskId)) { + leftTaskResizingHelper + ?.desktopModeWindowDecoration + ?.updateDisabledResizingEdge(NONE, shouldDelayUpdate) + } tearDownTiling() } } @@ -600,7 +633,6 @@ class DesktopTilingWindowDecoration( fun onOverviewAnimationStateChange(isRunning: Boolean) { if (!isTilingManagerInitialised) return - if (isRunning) { desktopTilingDividerWindowManager?.hideDividerBar() } else if (allTiledTasksVisible()) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleAnimator.kt new file mode 100644 index 000000000000..f0a85306d177 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleAnimator.kt @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2025 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.animation.ObjectAnimator +import android.view.View +import android.view.View.Visibility +import android.view.animation.PathInterpolator +import android.widget.ImageButton +import androidx.core.animation.doOnEnd +import com.android.wm.shell.shared.animation.Interpolators + +/** + * Animates the Desktop View's app handle. + */ +class AppHandleAnimator( + private val appHandleView: View, + private val captionHandle: ImageButton, +) { + companion object { + // Constants for animating the whole caption + private const val APP_HANDLE_ALPHA_FADE_IN_ANIMATION_DURATION_MS: Long = 275L + private const val APP_HANDLE_ALPHA_FADE_OUT_ANIMATION_DURATION_MS: Long = 340 + private val APP_HANDLE_ANIMATION_INTERPOLATOR = PathInterpolator( + 0.4f, + 0f, + 0.2f, + 1f + ) + + // Constants for animating the caption's handle + private const val HANDLE_ANIMATION_DURATION: Long = 100 + private val HANDLE_ANIMATION_INTERPOLATOR = Interpolators.FAST_OUT_SLOW_IN + } + + private var animator: ObjectAnimator? = null + + /** Animates the given caption view to the given visibility after a visibility change. */ + fun animateVisibilityChange(@Visibility visible: Int) { + when (visible) { + View.VISIBLE -> animateShowAppHandle() + else -> animateHideAppHandle() + } + } + + /** Animate appearance/disappearance of caption's handle. */ + fun animateCaptionHandleAlpha(startValue: Float, endValue: Float) { + cancel() + animator = ObjectAnimator.ofFloat(captionHandle, View.ALPHA, startValue, endValue).apply { + duration = HANDLE_ANIMATION_DURATION + interpolator = HANDLE_ANIMATION_INTERPOLATOR + start() + } + } + + private fun animateShowAppHandle() { + cancel() + appHandleView.alpha = 0f + appHandleView.visibility = View.VISIBLE + animator = ObjectAnimator.ofFloat(appHandleView, View.ALPHA, 1f).apply { + duration = APP_HANDLE_ALPHA_FADE_IN_ANIMATION_DURATION_MS + interpolator = APP_HANDLE_ANIMATION_INTERPOLATOR + start() + } + } + + private fun animateHideAppHandle() { + cancel() + animator = ObjectAnimator.ofFloat(appHandleView, View.ALPHA, 0f).apply { + duration = APP_HANDLE_ALPHA_FADE_OUT_ANIMATION_DURATION_MS + interpolator = APP_HANDLE_ANIMATION_INTERPOLATOR + doOnEnd { + appHandleView.visibility = View.GONE + } + start() + } + } + + /** + * Cancels any active animations. + */ + fun cancel() { + animator?.removeAllListeners() + animator?.cancel() + animator = null + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt index d9df899f8b40..7ab3303be618 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt @@ -15,7 +15,6 @@ */ package com.android.wm.shell.windowdecor.viewholder -import android.animation.ObjectAnimator import android.app.ActivityManager.RunningTaskInfo import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.content.res.ColorStateList @@ -40,8 +39,8 @@ import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.Accessibilit import com.android.internal.policy.SystemBarUtils import com.android.window.flags.Flags import com.android.wm.shell.R -import com.android.wm.shell.shared.animation.Interpolators import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper +import com.android.wm.shell.windowdecor.AppHandleAnimator import com.android.wm.shell.windowdecor.WindowManagerWrapper import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer @@ -57,10 +56,6 @@ internal class AppHandleViewHolder( private val handler: Handler ) : WindowDecorationViewHolder<AppHandleViewHolder.HandleData>(rootView) { - companion object { - private const val CAPTION_HANDLE_ANIMATION_DURATION: Long = 100 - } - data class HandleData( val taskInfo: RunningTaskInfo, val position: Point, @@ -73,6 +68,7 @@ internal class AppHandleViewHolder( private val captionView: View = rootView.requireViewById(R.id.desktop_mode_caption) private val captionHandle: ImageButton = rootView.requireViewById(R.id.caption_handle) private val inputManager = context.getSystemService(InputManager::class.java) + private val animator: AppHandleAnimator = AppHandleAnimator(rootView, captionHandle) private var statusBarInputLayerExists = false // An invisible View that takes up the same coordinates as captionHandle but is layered @@ -111,6 +107,7 @@ internal class AppHandleViewHolder( height: Int, isCaptionVisible: Boolean ) { + setVisibility(isCaptionVisible) captionHandle.imageTintList = ColorStateList.valueOf(getCaptionHandleBarColor(taskInfo)) this.taskInfo = taskInfo // If handle is not in status bar region(i.e., bottom stage in vertical split), @@ -132,11 +129,11 @@ internal class AppHandleViewHolder( } override fun onHandleMenuOpened() { - animateCaptionHandleAlpha(startValue = 1f, endValue = 0f) + animator.animateCaptionHandleAlpha(startValue = 1f, endValue = 0f) } override fun onHandleMenuClosed() { - animateCaptionHandleAlpha(startValue = 0f, endValue = 1f) + animator.animateCaptionHandleAlpha(startValue = 0f, endValue = 1f) } private fun createStatusBarInputLayer(handlePosition: Point, @@ -240,6 +237,16 @@ internal class AppHandleViewHolder( } } + private fun setVisibility(visible: Boolean) { + val v = if (visible) View.VISIBLE else View.GONE + if (captionView.visibility == v) return + if (!DesktopModeFlags.ENABLE_DESKTOP_APP_HANDLE_ANIMATION.isTrue()) { + captionView.visibility = v + return + } + animator.animateVisibilityChange(v) + } + private fun getCaptionHandleBarColor(taskInfo: RunningTaskInfo): Int { return if (shouldUseLightCaptionColors(taskInfo)) { context.getColor(R.color.desktop_mode_caption_handle_bar_light) @@ -265,15 +272,7 @@ internal class AppHandleViewHolder( } ?: false } - /** Animate appearance/disappearance of caption handle as the handle menu is animated. */ - private fun animateCaptionHandleAlpha(startValue: Float, endValue: Float) { - val animator = - ObjectAnimator.ofFloat(captionHandle, View.ALPHA, startValue, endValue).apply { - duration = CAPTION_HANDLE_ANIMATION_DURATION - interpolator = Interpolators.FAST_OUT_SLOW_IN - } - animator.start() + override fun close() { + animator.cancel() } - - override fun close() {} } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayModeControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayModeControllerTest.kt index cc37c440f650..450989dd334d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayModeControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayModeControllerTest.kt @@ -21,9 +21,12 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.content.ContentResolver +import android.hardware.input.InputManager import android.os.Binder +import android.os.Handler import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.FlagsParameterization import android.provider.Settings import android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS import android.view.Display.DEFAULT_DISPLAY @@ -44,6 +47,7 @@ import com.android.wm.shell.transition.Transitions import com.google.common.truth.Truth.assertThat import com.google.testing.junit.testparameterinjector.TestParameter import com.google.testing.junit.testparameterinjector.TestParameterInjector +import com.google.testing.junit.testparameterinjector.TestParameterValuesProvider import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -64,13 +68,18 @@ import org.mockito.kotlin.whenever */ @SmallTest @RunWith(TestParameterInjector::class) -class DesktopDisplayModeControllerTest : ShellTestCase() { +class DesktopDisplayModeControllerTest( + @TestParameter(valuesProvider = FlagsParameterizationProvider::class) + flags: FlagsParameterization +) : ShellTestCase() { private val transitions = mock<Transitions>() private val rootTaskDisplayAreaOrganizer = mock<RootTaskDisplayAreaOrganizer>() private val mockWindowManager = mock<IWindowManager>() private val shellTaskOrganizer = mock<ShellTaskOrganizer>() private val desktopWallpaperActivityTokenProvider = mock<DesktopWallpaperActivityTokenProvider>() + private val inputManager = mock<InputManager>() + private val mainHandler = mock<Handler>() private lateinit var controller: DesktopDisplayModeController @@ -82,6 +91,10 @@ class DesktopDisplayModeControllerTest : ShellTestCase() { private val defaultTDA = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0) private val wallpaperToken = MockToken().token() + init { + mSetFlagsRule.setFlagsParameterization(flags) + } + @Before fun setUp() { whenever(transitions.startTransition(anyInt(), any(), isNull())).thenReturn(Binder()) @@ -95,27 +108,20 @@ class DesktopDisplayModeControllerTest : ShellTestCase() { mockWindowManager, shellTaskOrganizer, desktopWallpaperActivityTokenProvider, + inputManager, + mainHandler, ) runningTasks.add(freeformTask) runningTasks.add(fullscreenTask) whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenReturn(ArrayList(runningTasks)) whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(wallpaperToken) + setTabletModeStatus(SwitchState.UNKNOWN) } - private fun testDisplayWindowingModeSwitch( - defaultWindowingMode: Int, - extendedDisplayEnabled: Boolean, - expectToSwitch: Boolean, - ) { - defaultTDA.configuration.windowConfiguration.windowingMode = defaultWindowingMode - whenever(mockWindowManager.getWindowingMode(anyInt())).thenReturn(defaultWindowingMode) - val settingsSession = - ExtendedDisplaySettingsSession( - context.contentResolver, - if (extendedDisplayEnabled) 1 else 0, - ) - - settingsSession.use { + private fun testDisplayWindowingModeSwitchOnDisplayConnected(expectToSwitch: Boolean) { + defaultTDA.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN + whenever(mockWindowManager.getWindowingMode(anyInt())).thenReturn(WINDOWING_MODE_FULLSCREEN) + ExtendedDisplaySettingsSession(context.contentResolver, 1).use { connectExternalDisplay() if (expectToSwitch) { // Assumes [connectExternalDisplay] properly triggered the switching transition. @@ -133,7 +139,7 @@ class DesktopDisplayModeControllerTest : ShellTestCase() { assertThat(arg.firstValue.changes[wallpaperToken.asBinder()]?.windowingMode) .isEqualTo(WINDOWING_MODE_FULLSCREEN) assertThat(arg.secondValue.changes[defaultTDA.token.asBinder()]?.windowingMode) - .isEqualTo(defaultWindowingMode) + .isEqualTo(WINDOWING_MODE_FULLSCREEN) assertThat(arg.secondValue.changes[wallpaperToken.asBinder()]?.windowingMode) .isEqualTo(WINDOWING_MODE_FULLSCREEN) } else { @@ -144,25 +150,64 @@ class DesktopDisplayModeControllerTest : ShellTestCase() { @Test @DisableFlags(Flags.FLAG_ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING) - fun displayWindowingModeSwitchOnDisplayConnected_flagDisabled( - @TestParameter param: ModeSwitchTestCase - ) { - testDisplayWindowingModeSwitch( - param.defaultWindowingMode, - param.extendedDisplayEnabled, - // When the flag is disabled, never switch. - expectToSwitch = false, - ) + fun displayWindowingModeSwitchOnDisplayConnected_flagDisabled() { + // When the flag is disabled, never switch. + testDisplayWindowingModeSwitchOnDisplayConnected(/* expectToSwitch= */ false) } @Test @EnableFlags(Flags.FLAG_ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING) - fun displayWindowingModeSwitchOnDisplayConnected(@TestParameter param: ModeSwitchTestCase) { - testDisplayWindowingModeSwitch( - param.defaultWindowingMode, - param.extendedDisplayEnabled, - param.expectToSwitchByDefault, - ) + fun displayWindowingModeSwitchOnDisplayConnected() { + testDisplayWindowingModeSwitchOnDisplayConnected(/* expectToSwitch= */ true) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING) + @DisableFlags(Flags.FLAG_FORM_FACTOR_BASED_DESKTOP_FIRST_SWITCH) + fun testTargetWindowingMode_formfactorDisabled( + @TestParameter param: ExternalDisplayBasedTargetModeTestCase, + @TestParameter tabletModeStatus: SwitchState, + ) { + whenever(mockWindowManager.getWindowingMode(anyInt())) + .thenReturn(param.defaultWindowingMode) + if (param.hasExternalDisplay) { + connectExternalDisplay() + } else { + disconnectExternalDisplay() + } + setTabletModeStatus(tabletModeStatus) + + ExtendedDisplaySettingsSession( + context.contentResolver, + if (param.extendedDisplayEnabled) 1 else 0, + ) + .use { + assertThat(controller.getTargetWindowingModeForDefaultDisplay()) + .isEqualTo(param.expectedWindowingMode) + } + } + + @Test + @EnableFlags( + Flags.FLAG_ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING, + Flags.FLAG_FORM_FACTOR_BASED_DESKTOP_FIRST_SWITCH, + ) + fun testTargetWindowingMode(@TestParameter param: FormFactorBasedTargetModeTestCase) { + if (param.hasExternalDisplay) { + connectExternalDisplay() + } else { + disconnectExternalDisplay() + } + setTabletModeStatus(param.tabletModeStatus) + + ExtendedDisplaySettingsSession( + context.contentResolver, + if (param.extendedDisplayEnabled) 1 else 0, + ) + .use { + assertThat(controller.getTargetWindowingModeForDefaultDisplay()) + .isEqualTo(param.expectedWindowingMode) + } } @Test @@ -217,6 +262,10 @@ class DesktopDisplayModeControllerTest : ShellTestCase() { controller.refreshDisplayWindowingMode() } + private fun setTabletModeStatus(status: SwitchState) { + whenever(inputManager.isInTabletMode()).thenReturn(status.value) + } + private class ExtendedDisplaySettingsSession( private val contentResolver: ContentResolver, private val overrideValue: Int, @@ -233,33 +282,158 @@ class DesktopDisplayModeControllerTest : ShellTestCase() { } } + private class FlagsParameterizationProvider : TestParameterValuesProvider() { + override fun provideValues( + context: TestParameterValuesProvider.Context + ): List<FlagsParameterization> { + return FlagsParameterization.allCombinationsOf( + Flags.FLAG_FORM_FACTOR_BASED_DESKTOP_FIRST_SWITCH + ) + } + } + companion object { const val EXTERNAL_DISPLAY_ID = 100 - enum class ModeSwitchTestCase( + enum class SwitchState(val value: Int) { + UNKNOWN(InputManager.SWITCH_STATE_UNKNOWN), + ON(InputManager.SWITCH_STATE_ON), + OFF(InputManager.SWITCH_STATE_OFF), + } + + enum class ExternalDisplayBasedTargetModeTestCase( val defaultWindowingMode: Int, + val hasExternalDisplay: Boolean, val extendedDisplayEnabled: Boolean, - val expectToSwitchByDefault: Boolean, + val expectedWindowingMode: Int, ) { - FULLSCREEN_DISPLAY( + FREEFORM_EXTERNAL_EXTENDED( + defaultWindowingMode = WINDOWING_MODE_FREEFORM, + hasExternalDisplay = true, + extendedDisplayEnabled = true, + expectedWindowingMode = WINDOWING_MODE_FREEFORM, + ), + FULLSCREEN_EXTERNAL_EXTENDED( defaultWindowingMode = WINDOWING_MODE_FULLSCREEN, + hasExternalDisplay = true, + extendedDisplayEnabled = true, + expectedWindowingMode = WINDOWING_MODE_FREEFORM, + ), + FREEFORM_NO_EXTERNAL_EXTENDED( + defaultWindowingMode = WINDOWING_MODE_FREEFORM, + hasExternalDisplay = false, extendedDisplayEnabled = true, - expectToSwitchByDefault = true, + expectedWindowingMode = WINDOWING_MODE_FREEFORM, + ), + FULLSCREEN_NO_EXTERNAL_EXTENDED( + defaultWindowingMode = WINDOWING_MODE_FULLSCREEN, + hasExternalDisplay = false, + extendedDisplayEnabled = true, + expectedWindowingMode = WINDOWING_MODE_FULLSCREEN, + ), + FREEFORM_EXTERNAL_MIRROR( + defaultWindowingMode = WINDOWING_MODE_FREEFORM, + hasExternalDisplay = true, + extendedDisplayEnabled = false, + expectedWindowingMode = WINDOWING_MODE_FREEFORM, ), - FULLSCREEN_DISPLAY_MIRRORING( + FULLSCREEN_EXTERNAL_MIRROR( defaultWindowingMode = WINDOWING_MODE_FULLSCREEN, + hasExternalDisplay = true, extendedDisplayEnabled = false, - expectToSwitchByDefault = false, + expectedWindowingMode = WINDOWING_MODE_FULLSCREEN, ), - FREEFORM_DISPLAY( + FREEFORM_NO_EXTERNAL_MIRROR( defaultWindowingMode = WINDOWING_MODE_FREEFORM, + hasExternalDisplay = false, + extendedDisplayEnabled = false, + expectedWindowingMode = WINDOWING_MODE_FREEFORM, + ), + FULLSCREEN_NO_EXTERNAL_MIRROR( + defaultWindowingMode = WINDOWING_MODE_FULLSCREEN, + hasExternalDisplay = false, + extendedDisplayEnabled = false, + expectedWindowingMode = WINDOWING_MODE_FULLSCREEN, + ), + } + + enum class FormFactorBasedTargetModeTestCase( + val hasExternalDisplay: Boolean, + val extendedDisplayEnabled: Boolean, + val tabletModeStatus: SwitchState, + val expectedWindowingMode: Int, + ) { + EXTERNAL_EXTENDED_TABLET( + hasExternalDisplay = true, extendedDisplayEnabled = true, - expectToSwitchByDefault = false, + tabletModeStatus = SwitchState.ON, + expectedWindowingMode = WINDOWING_MODE_FREEFORM, ), - FREEFORM_DISPLAY_MIRRORING( - defaultWindowingMode = WINDOWING_MODE_FREEFORM, + NO_EXTERNAL_EXTENDED_TABLET( + hasExternalDisplay = false, + extendedDisplayEnabled = true, + tabletModeStatus = SwitchState.ON, + expectedWindowingMode = WINDOWING_MODE_FULLSCREEN, + ), + EXTERNAL_MIRROR_TABLET( + hasExternalDisplay = true, + extendedDisplayEnabled = false, + tabletModeStatus = SwitchState.ON, + expectedWindowingMode = WINDOWING_MODE_FULLSCREEN, + ), + NO_EXTERNAL_MIRROR_TABLET( + hasExternalDisplay = false, + extendedDisplayEnabled = false, + tabletModeStatus = SwitchState.ON, + expectedWindowingMode = WINDOWING_MODE_FULLSCREEN, + ), + EXTERNAL_EXTENDED_CLAMSHELL( + hasExternalDisplay = true, + extendedDisplayEnabled = true, + tabletModeStatus = SwitchState.OFF, + expectedWindowingMode = WINDOWING_MODE_FREEFORM, + ), + NO_EXTERNAL_EXTENDED_CLAMSHELL( + hasExternalDisplay = false, + extendedDisplayEnabled = true, + tabletModeStatus = SwitchState.OFF, + expectedWindowingMode = WINDOWING_MODE_FREEFORM, + ), + EXTERNAL_MIRROR_CLAMSHELL( + hasExternalDisplay = true, + extendedDisplayEnabled = false, + tabletModeStatus = SwitchState.OFF, + expectedWindowingMode = WINDOWING_MODE_FREEFORM, + ), + NO_EXTERNAL_MIRROR_CLAMSHELL( + hasExternalDisplay = false, + extendedDisplayEnabled = false, + tabletModeStatus = SwitchState.OFF, + expectedWindowingMode = WINDOWING_MODE_FREEFORM, + ), + EXTERNAL_EXTENDED_UNKNOWN( + hasExternalDisplay = true, + extendedDisplayEnabled = true, + tabletModeStatus = SwitchState.UNKNOWN, + expectedWindowingMode = WINDOWING_MODE_FREEFORM, + ), + NO_EXTERNAL_EXTENDED_UNKNOWN( + hasExternalDisplay = false, + extendedDisplayEnabled = true, + tabletModeStatus = SwitchState.UNKNOWN, + expectedWindowingMode = WINDOWING_MODE_FULLSCREEN, + ), + EXTERNAL_MIRROR_UNKNOWN( + hasExternalDisplay = true, + extendedDisplayEnabled = false, + tabletModeStatus = SwitchState.UNKNOWN, + expectedWindowingMode = WINDOWING_MODE_FULLSCREEN, + ), + NO_EXTERNAL_MIRROR_UNKNOWN( + hasExternalDisplay = false, extendedDisplayEnabled = false, - expectToSwitchByDefault = false, + tabletModeStatus = SwitchState.UNKNOWN, + expectedWindowingMode = WINDOWING_MODE_FULLSCREEN, ), } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopPipTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopPipTransitionObserverTest.kt new file mode 100644 index 000000000000..ef394d81cc57 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopPipTransitionObserverTest.kt @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2025 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.desktopmode + +import android.app.WindowConfiguration.WINDOWING_MODE_PINNED +import android.os.Binder +import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.SetFlagsRule +import android.testing.AndroidTestingRunner +import android.view.WindowManager.TRANSIT_PIP +import android.window.TransitionInfo +import androidx.test.filters.SmallTest +import com.android.window.flags.Flags +import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.TestRunningTaskInfoBuilder +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.mock + +/** + * Tests for [DesktopPipTransitionObserver]. + * + * Build/Install/Run: atest WMShellUnitTests:DesktopPipTransitionObserverTest + */ +@SmallTest +@RunWith(AndroidTestingRunner::class) +class DesktopPipTransitionObserverTest : ShellTestCase() { + + @JvmField @Rule val setFlagsRule = SetFlagsRule() + + private lateinit var observer: DesktopPipTransitionObserver + + private val transition = Binder() + private var onSuccessInvokedCount = 0 + + @Before + fun setUp() { + observer = DesktopPipTransitionObserver() + + onSuccessInvokedCount = 0 + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PIP) + fun onTransitionReady_taskInPinnedWindowingMode_onSuccessInvoked() { + val taskId = 1 + val pipTransition = createPendingPipTransition(taskId) + val successfulChange = createChange(taskId, WINDOWING_MODE_PINNED) + observer.addPendingPipTransition(pipTransition) + + observer.onTransitionReady( + transition = transition, + info = TransitionInfo( + TRANSIT_PIP, /* flags= */ + 0 + ).apply { addChange(successfulChange) }, + ) + + assertThat(onSuccessInvokedCount).isEqualTo(1) + } + + private fun createPendingPipTransition( + taskId: Int + ): DesktopPipTransitionObserver.PendingPipTransition { + return DesktopPipTransitionObserver.PendingPipTransition( + token = transition, + taskId = taskId, + onSuccess = { onSuccessInvokedCount += 1 }, + ) + } + + private fun createChange(taskId: Int, windowingMode: Int): TransitionInfo.Change { + return TransitionInfo.Change(mock(), mock()).apply { + taskInfo = + TestRunningTaskInfoBuilder() + .setTaskId(taskId) + .setWindowingMode(windowingMode) + .build() + } + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt index f84a1a38bdfc..3813f752cae8 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt @@ -1225,36 +1225,6 @@ class DesktopRepositoryTest(flags: FlagsParameterization) : ShellTestCase() { } @Test - fun setTaskInPip_savedAsMinimizedPipInDisplay() { - assertThat(repo.isTaskMinimizedPipInDisplay(DEFAULT_DESKTOP_ID, taskId = 1)).isFalse() - - repo.setTaskInPip(DEFAULT_DESKTOP_ID, taskId = 1, enterPip = true) - - assertThat(repo.isTaskMinimizedPipInDisplay(DEFAULT_DESKTOP_ID, taskId = 1)).isTrue() - } - - @Test - fun removeTaskInPip_removedAsMinimizedPipInDisplay() { - repo.setTaskInPip(DEFAULT_DESKTOP_ID, taskId = 1, enterPip = true) - assertThat(repo.isTaskMinimizedPipInDisplay(DEFAULT_DESKTOP_ID, taskId = 1)).isTrue() - - repo.setTaskInPip(DEFAULT_DESKTOP_ID, taskId = 1, enterPip = false) - - assertThat(repo.isTaskMinimizedPipInDisplay(DEFAULT_DESKTOP_ID, taskId = 1)).isFalse() - } - - @Test - fun setTaskInPip_multipleDisplays_bothAreInPip() { - repo.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) - repo.setActiveDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) - repo.setTaskInPip(DEFAULT_DESKTOP_ID, taskId = 1, enterPip = true) - repo.setTaskInPip(SECOND_DISPLAY, taskId = 2, enterPip = true) - - assertThat(repo.isTaskMinimizedPipInDisplay(DEFAULT_DESKTOP_ID, taskId = 1)).isTrue() - assertThat(repo.isTaskMinimizedPipInDisplay(SECOND_DISPLAY, taskId = 2)).isTrue() - } - - @Test @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun addTask_deskDoesNotExists_createsDesk() { repo.addTask(displayId = 999, taskId = 6, isVisible = true) 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 34c5ebd6d94d..14af57372ed6 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 @@ -87,6 +87,7 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession import com.android.dx.mockito.inline.extended.ExtendedMockito.never import com.android.dx.mockito.inline.extended.StaticMockitoSession import com.android.internal.jank.InteractionJankMonitor +import com.android.internal.policy.SystemBarUtils.getDesktopViewAppHeaderHeightPx import com.android.window.flags.Flags import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE import com.android.window.flags.Flags.FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS @@ -263,6 +264,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Mock private lateinit var desksOrganizer: DesksOrganizer @Mock private lateinit var userProfileContexts: UserProfileContexts @Mock private lateinit var desksTransitionsObserver: DesksTransitionObserver + @Mock private lateinit var desktopPipTransitionObserver: DesktopPipTransitionObserver @Mock private lateinit var packageManager: PackageManager @Mock private lateinit var mockDisplayContext: Context @Mock private lateinit var dragToDisplayTransitionHandler: DragToDisplayTransitionHandler @@ -391,6 +393,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(wallpaperToken) whenever(userProfileContexts[anyInt()]).thenReturn(context) whenever(userProfileContexts.getOrCreate(anyInt())).thenReturn(context) + whenever(freeformTaskTransitionStarter.startPipTransition(any())).thenReturn(Binder()) controller = createController() controller.setSplitScreenController(splitScreenController) @@ -455,6 +458,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() overviewToDesktopTransitionObserver, desksOrganizer, desksTransitionsObserver, + desktopPipTransitionObserver, userProfileContexts, desktopModeCompatPolicy, dragToDisplayTransitionHandler, @@ -1464,7 +1468,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) val finalBounds = findBoundsChange(wct, task) - val captionInsets = getAppHeaderHeight(context) + val captionInsets = getDesktopViewAppHeaderHeightPx(context) finalBounds!!.top += captionInsets val finalAspectRatio = maxOf(finalBounds.height(), finalBounds.width()) / @@ -1486,7 +1490,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) val finalBounds = findBoundsChange(wct, task) - val captionInsets = getAppHeaderHeight(context) + val captionInsets = getDesktopViewAppHeaderHeightPx(context) finalBounds!!.top += captionInsets val finalAspectRatio = maxOf(finalBounds.height(), finalBounds.width()) / @@ -3469,6 +3473,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PIP) fun onPipTaskMinimize_autoEnterEnabled_startPipTransition() { val task = setUpPipTask(autoEnterEnabled = true) val handler = mock(TransitionHandler::class.java) @@ -3483,6 +3488,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PIP) fun onPipTaskMinimize_autoEnterDisabled_startMinimizeTransition() { val task = setUpPipTask(autoEnterEnabled = false) whenever( @@ -3502,6 +3508,90 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() } @Test + @EnableFlags( + Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER, + Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PIP, + ) + fun onDesktopTaskEnteredPip_pipIsLastTask_removesWallpaper() { + val task = setUpPipTask(autoEnterEnabled = true) + + controller.onDesktopTaskEnteredPip( + taskId = task.taskId, + deskId = DEFAULT_DISPLAY, + displayId = task.displayId, + taskIsLastVisibleTaskBeforePip = true, + ) + + // Wallpaper is moved to the back + val wct = getLatestTransition() + wct.assertReorder(wallpaperToken, /* toTop= */ false) + } + + @Test + @EnableFlags( + Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PIP, + Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND, + ) + fun onDesktopTaskEnteredPip_pipIsLastTask_deactivatesDesk() { + val deskId = DEFAULT_DISPLAY + val task = setUpPipTask(autoEnterEnabled = true, deskId = deskId) + val transition = Binder() + whenever(transitions.startTransition(any(), any(), anyOrNull())).thenReturn(transition) + + controller.onDesktopTaskEnteredPip( + taskId = task.taskId, + deskId = deskId, + displayId = task.displayId, + taskIsLastVisibleTaskBeforePip = true, + ) + + verify(desksOrganizer).deactivateDesk(any(), eq(deskId)) + verify(desksTransitionsObserver) + .addPendingTransition(DeskTransition.DeactivateDesk(transition, deskId)) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PIP) + fun onDesktopTaskEnteredPip_pipIsLastTask_launchesHome() { + val task = setUpPipTask(autoEnterEnabled = true) + + controller.onDesktopTaskEnteredPip( + taskId = task.taskId, + deskId = DEFAULT_DISPLAY, + displayId = task.displayId, + taskIsLastVisibleTaskBeforePip = true, + ) + + val wct = getLatestTransition() + wct.assertPendingIntent(launchHomeIntent(DEFAULT_DISPLAY)) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PIP) + fun onDesktopTaskEnteredPip_pipIsNotLastTask_doesntExitDesktopMode() { + val task = setUpPipTask(autoEnterEnabled = true) + val deskId = DEFAULT_DISPLAY + setUpFreeformTask(deskId = deskId) // launch another freeform task + val transition = Binder() + whenever(transitions.startTransition(any(), any(), anyOrNull())).thenReturn(transition) + + controller.onDesktopTaskEnteredPip( + taskId = task.taskId, + deskId = deskId, + displayId = task.displayId, + taskIsLastVisibleTaskBeforePip = false, + ) + + // No transition to exit Desktop mode is started + verifyWCTNotExecuted() + verify(desktopModeEnterExitTransitionListener, never()) + .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION) + verify(desksOrganizer, never()).deactivateDesk(any(), eq(deskId)) + verify(desksTransitionsObserver, never()) + .addPendingTransition(DeskTransition.DeactivateDesk(transition, deskId)) + } + + @Test fun onDesktopWindowMinimize_singleActiveTask_noWallpaperActivityToken_doesntRemoveWallpaper() { val task = setUpFreeformTask(active = true) val transition = Binder() @@ -7614,8 +7704,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() return task } - private fun setUpPipTask(autoEnterEnabled: Boolean): RunningTaskInfo = - setUpFreeformTask().apply { + private fun setUpPipTask( + autoEnterEnabled: Boolean, + displayId: Int = DEFAULT_DISPLAY, + deskId: Int = DEFAULT_DISPLAY, + ): RunningTaskInfo = + setUpFreeformTask(displayId = displayId, deskId = deskId).apply { pictureInPictureParams = PictureInPictureParams.Builder().setAutoEnterEnabled(autoEnterEnabled).build() } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt index a7dc706eb6c9..ec64c2fa2337 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt @@ -22,7 +22,6 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.content.ComponentName import android.content.Context import android.content.Intent -import android.os.Binder import android.os.IBinder import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags @@ -30,7 +29,6 @@ import android.view.Display.DEFAULT_DISPLAY import android.view.WindowManager import android.view.WindowManager.TRANSIT_CLOSE import android.view.WindowManager.TRANSIT_OPEN -import android.view.WindowManager.TRANSIT_PIP import android.view.WindowManager.TRANSIT_TO_BACK import android.view.WindowManager.TRANSIT_TO_FRONT import android.window.IWindowContainerToken @@ -41,7 +39,6 @@ import android.window.WindowContainerTransaction import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER import com.android.modules.utils.testing.ExtendedMockitoRule import com.android.window.flags.Flags -import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PIP import com.android.wm.shell.MockToken import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.back.BackAnimationController @@ -51,8 +48,6 @@ import com.android.wm.shell.desktopmode.desktopwallpaperactivity.DesktopWallpape import com.android.wm.shell.shared.desktopmode.DesktopModeStatus import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.Transitions -import com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP -import com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertWithMessage import org.junit.Before @@ -90,6 +85,7 @@ class DesktopTasksTransitionObserverTest { private val userRepositories = mock<DesktopUserRepositories>() private val taskRepository = mock<DesktopRepository>() private val mixedHandler = mock<DesktopMixedTransitionHandler>() + private val pipTransitionObserver = mock<DesktopPipTransitionObserver>() private val backAnimationController = mock<BackAnimationController>() private val desktopWallpaperActivityTokenProvider = mock<DesktopWallpaperActivityTokenProvider>() @@ -114,6 +110,7 @@ class DesktopTasksTransitionObserverTest { transitions, shellTaskOrganizer, mixedHandler, + pipTransitionObserver, backAnimationController, desktopWallpaperActivityTokenProvider, shellInit, @@ -349,56 +346,6 @@ class DesktopTasksTransitionObserverTest { verify(desktopWallpaperActivityTokenProvider).removeToken(wallpaperTask.displayId) } - @Test - @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PIP) - fun pendingPipTransitionAborted_taskRepositoryOnPipAbortedInvoked() { - val task = createTaskInfo(1, WINDOWING_MODE_FREEFORM) - val pipTransition = Binder() - whenever(taskRepository.isTaskMinimizedPipInDisplay(any(), any())).thenReturn(true) - - transitionObserver.onTransitionReady( - transition = pipTransition, - info = createOpenChangeTransition(task, type = TRANSIT_PIP), - startTransaction = mock(), - finishTransaction = mock(), - ) - transitionObserver.onTransitionFinished(transition = pipTransition, aborted = true) - - verify(taskRepository).onPipAborted(task.displayId, task.taskId) - } - - @Test - @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PIP) - fun exitPipTransition_taskRepositoryClearTaskInPip() { - val task = createTaskInfo(1, WINDOWING_MODE_FREEFORM) - whenever(taskRepository.isTaskMinimizedPipInDisplay(any(), any())).thenReturn(true) - - transitionObserver.onTransitionReady( - transition = mock(), - info = createOpenChangeTransition(task, type = TRANSIT_EXIT_PIP), - startTransaction = mock(), - finishTransaction = mock(), - ) - - verify(taskRepository).setTaskInPip(task.displayId, task.taskId, enterPip = false) - } - - @Test - @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PIP) - fun removePipTransition_taskRepositoryClearTaskInPip() { - val task = createTaskInfo(1, WINDOWING_MODE_FREEFORM) - whenever(taskRepository.isTaskMinimizedPipInDisplay(any(), any())).thenReturn(true) - - transitionObserver.onTransitionReady( - transition = mock(), - info = createOpenChangeTransition(task, type = TRANSIT_REMOVE_PIP), - startTransaction = mock(), - finishTransaction = mock(), - ) - - verify(taskRepository).setTaskInPip(task.displayId, task.taskId, enterPip = false) - } - private fun createBackNavigationTransition( task: RunningTaskInfo?, type: Int = TRANSIT_TO_BACK, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt index c40a04c47b9b..b511fc34fa89 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt @@ -22,6 +22,7 @@ import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW +import android.app.WindowConfiguration.WINDOWING_MODE_PINNED import android.content.ComponentName import android.graphics.Rect import android.view.Display.DEFAULT_DISPLAY @@ -45,6 +46,17 @@ object DesktopTestHelpers { .apply { bounds?.let { setBounds(it) } } .build() + fun createPinnedTask(displayId: Int = DEFAULT_DISPLAY, bounds: Rect? = null): RunningTaskInfo = + TestRunningTaskInfoBuilder() + .setDisplayId(displayId) + .setParentTaskId(displayId) + .setToken(MockToken().token()) + .setActivityType(ACTIVITY_TYPE_STANDARD) + .setWindowingMode(WINDOWING_MODE_PINNED) + .setLastActiveTime(100) + .apply { bounds?.let { setBounds(it) } } + .build() + fun createFullscreenTaskBuilder(displayId: Int = DEFAULT_DISPLAY): TestRunningTaskInfoBuilder = TestRunningTaskInfoBuilder() .setDisplayId(displayId) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java index 275e4882a79d..42f65dd71f16 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java @@ -17,6 +17,7 @@ package com.android.wm.shell.pip2.phone; 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; @@ -86,6 +87,7 @@ public class PipSchedulerTest { @Mock private SurfaceControl.Transaction mMockTransaction; @Mock private PipAlphaAnimator mMockAlphaAnimator; @Mock private SplitScreenController mMockSplitScreenController; + @Mock private SurfaceControl mMockLeash; @Captor private ArgumentCaptor<Runnable> mRunnableArgumentCaptor; @Captor private ArgumentCaptor<WindowContainerTransaction> mWctArgumentCaptor; @@ -315,6 +317,30 @@ public class PipSchedulerTest { verify(mMockAlphaAnimator, never()).start(); } + @Test + public void onPipTransitionStateChanged_exiting_endAnimation() { + mPipScheduler.setOverlayFadeoutAnimator(mMockAlphaAnimator); + when(mMockAlphaAnimator.isStarted()).thenReturn(true); + mPipScheduler.onPipTransitionStateChanged(PipTransitionState.ENTERED_PIP, + PipTransitionState.EXITING_PIP, null); + + verify(mMockAlphaAnimator, times(1)).end(); + assertNull("mOverlayFadeoutAnimator should be reset to null", + mPipScheduler.getOverlayFadeoutAnimator()); + } + + @Test + public void onPipTransitionStateChanged_scheduledBoundsChange_endAnimation() { + mPipScheduler.setOverlayFadeoutAnimator(mMockAlphaAnimator); + when(mMockAlphaAnimator.isStarted()).thenReturn(true); + mPipScheduler.onPipTransitionStateChanged(PipTransitionState.ENTERED_PIP, + PipTransitionState.SCHEDULED_BOUNDS_CHANGE, null); + + verify(mMockAlphaAnimator, times(1)).end(); + assertNull("mOverlayFadeoutAnimator should be reset to null", + mPipScheduler.getOverlayFadeoutAnimator()); + } + private void setNullPipTaskToken() { when(mMockPipTransitionState.getPipTaskToken()).thenReturn(null); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt index 95498cbbe53c..3b21e365e911 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt @@ -352,7 +352,7 @@ class DropTargetManagerTest { initialDragZone = dragZone } - override fun onDragZoneChanged(from: DragZone, to: DragZone) { + override fun onDragZoneChanged(draggedObject: DraggedObject, from: DragZone, to: DragZone) { fromDragZone = from toDragZone = to } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java index e246329446dc..5dff21860ef4 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java @@ -211,11 +211,19 @@ public class StageCoordinatorTests extends ShellTestCase { when(mSplitLayout.getDividerLeash()).thenReturn(dividerLeash); mRootTask = new TestRunningTaskInfoBuilder().build(); - SurfaceControl rootLeash = new SurfaceControl.Builder().setName("test").build(); + SurfaceControl rootLeash = new SurfaceControl.Builder().setName("splitRoot").build(); mStageCoordinator.onTaskAppeared(mRootTask, rootLeash); mSideStage.mRootTaskInfo = new TestRunningTaskInfoBuilder().build(); mMainStage.mRootTaskInfo = new TestRunningTaskInfoBuilder().build(); + SurfaceControl mainRootLeash = new SurfaceControl.Builder().setName("mainRoot").build(); + SurfaceControl sideRootLeash = new SurfaceControl.Builder().setName("sideRoot").build(); + mMainStage.mRootLeash = mainRootLeash; + mSideStage.mRootLeash = sideRootLeash; + SurfaceControl mainDimLayer = new SurfaceControl.Builder().setName("mainDim").build(); + SurfaceControl sideDimLayer = new SurfaceControl.Builder().setName("sideDim").build(); + mMainStage.mDimLayer = mainDimLayer; + mSideStage.mDimLayer = sideDimLayer; doReturn(mock(SplitDecorManager.class)).when(mMainStage).getSplitDecorManager(); doReturn(mock(SplitDecorManager.class)).when(mSideStage).getSplitDecorManager(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/RemoteTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/RemoteTransitionHandlerTest.kt new file mode 100644 index 000000000000..048981d634ef --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/RemoteTransitionHandlerTest.kt @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2025 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.transition + +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper +import android.view.WindowManager +import android.window.RemoteTransition +import android.window.TransitionFilter +import android.window.TransitionInfo +import android.window.TransitionRequestInfo +import android.window.WindowContainerTransaction +import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.TestSyncExecutor +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.mock + +/** + * Test class for [RemoteTransitionHandler]. + * + * atest WMShellUnitTests:RemoteTransitionHandlerTest + */ +@RunWithLooper +@RunWith(AndroidTestingRunner::class) +class RemoteTransitionHandlerTest : ShellTestCase() { + + private val testExecutor: TestSyncExecutor = TestSyncExecutor() + + private val testRemoteTransition = RemoteTransition(TestRemoteTransition()) + private lateinit var handler: RemoteTransitionHandler + + @Before + fun setUp() { + handler = RemoteTransitionHandler(testExecutor) + } + + @Test + fun handleRequest_noRemoteTransition_returnsNull() { + val request = TransitionRequestInfo(WindowManager.TRANSIT_OPEN, null, null) + + assertNull(handler.handleRequest(mock(), request)) + } + + @Test + fun handleRequest_testRemoteTransition_returnsWindowContainerTransaction() { + val request = TransitionRequestInfo(WindowManager.TRANSIT_OPEN, null, testRemoteTransition) + + assertTrue(handler.handleRequest(mock(), request) is WindowContainerTransaction) + } + + @Test + fun startAnimation_noRemoteTransition_returnsFalse() { + val request = TransitionRequestInfo(WindowManager.TRANSIT_OPEN, null, null) + handler.handleRequest(mock(), request) + + val isHandled = handler.startAnimation( + /* transition= */ mock(), + /* info= */ createTransitionInfo(), + /* startTransaction= */ mock(), + /* finishTransaction= */ mock(), + /* finishCallback= */ {}, + ) + + assertFalse(isHandled) + } + + @Test + fun startAnimation_remoteTransition_returnsTrue() { + val request = TransitionRequestInfo(WindowManager.TRANSIT_OPEN, null, testRemoteTransition) + handler.addFiltered(TransitionFilter(), testRemoteTransition) + handler.handleRequest(mock(), request) + + val isHandled = handler.startAnimation( + /* transition= */ testRemoteTransition.remoteTransition.asBinder(), + /* info= */ createTransitionInfo(), + /* startTransaction= */ mock(), + /* finishTransaction= */ mock(), + /* finishCallback= */ {}, + ) + + assertTrue(isHandled) + } + + private fun createTransitionInfo( + type: Int = WindowManager.TRANSIT_OPEN, + changeMode: Int = WindowManager.TRANSIT_CLOSE, + ): TransitionInfo = + TransitionInfo(type, /* flags= */ 0).apply { + addChange( + TransitionInfo.Change(mock(), mock()).apply { + mode = changeMode + parent = null + } + ) + } +}
\ No newline at end of file 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 1371b38a579f..878324937f1a 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 @@ -60,7 +60,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.TypedArray; -import android.graphics.PointF; +import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; import android.net.Uri; @@ -1805,7 +1805,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { @NonNull DisplayController displayController, @NonNull ActivityManager.RunningTaskInfo taskInfo, @NonNull Context decorWindowContext, - @NonNull Function2<? super Integer,? super Integer,? extends PointF> + @NonNull Function2<? super Integer,? super Integer,? extends Point> positionSupplier, @NonNull Supplier<SurfaceControl.Transaction> transactionSupplier) { return mMaximizeMenu; 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 9a2e2fad50be..cda343f3538b 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 @@ -1232,11 +1232,6 @@ public class WindowDecorationTests extends ShellTestCase { } @Override - int getCaptionViewId() { - return R.id.caption; - } - - @Override TestView inflateLayout(Context context, int layoutResId) { if (layoutResId == R.layout.caption_layout) { return mMockView; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt index bc8faedd77a9..e4424f3c57f2 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt @@ -16,6 +16,7 @@ package com.android.wm.shell.windowdecor.tiling import android.app.ActivityManager +import android.app.ActivityManager.RunningTaskInfo import android.content.Context import android.content.res.Resources import android.graphics.Rect @@ -24,8 +25,10 @@ import android.testing.AndroidTestingRunner import android.view.MotionEvent import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CHANGE +import android.view.WindowManager.TRANSIT_PIP import android.view.WindowManager.TRANSIT_TO_FRONT import android.window.TransitionInfo +import android.window.TransitionInfo.Change import android.window.WindowContainerTransaction import androidx.test.filters.SmallTest import com.android.wm.shell.RootTaskDisplayAreaOrganizer @@ -40,6 +43,7 @@ import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeT import com.android.wm.shell.desktopmode.DesktopRepository import com.android.wm.shell.desktopmode.DesktopTasksController import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask +import com.android.wm.shell.desktopmode.DesktopTestHelpers.createPinnedTask import com.android.wm.shell.desktopmode.DesktopUserRepositories import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler @@ -552,6 +556,37 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() { } @Test + fun taskTiled_shouldBeRemoved_whenEnteringPip() { + val task1 = createPipTask() + val stableBounds = STABLE_BOUNDS_MOCK + whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout) + whenever(displayLayout.getStableBounds(any())).thenAnswer { i -> + (i.arguments.first() as Rect).set(stableBounds) + } + whenever(context.resources).thenReturn(resources) + whenever(resources.getDimensionPixelSize(any())).thenReturn(split_divider_width) + whenever(tiledTaskHelper.taskInfo).thenReturn(task1) + whenever(tiledTaskHelper.desktopModeWindowDecoration).thenReturn(desktopWindowDecoration) + tilingDecoration.onAppTiled( + task1, + desktopWindowDecoration, + DesktopTasksController.SnapPosition.LEFT, + BOUNDS, + ) + tilingDecoration.leftTaskResizingHelper = tiledTaskHelper + val changeInfo = createPipChangeTransition(task1) + tilingDecoration.onTransitionReady( + transition = mock(), + info = changeInfo, + startTransaction = mock(), + finishTransaction = mock(), + ) + + assertThat(tilingDecoration.leftTaskResizingHelper).isNull() + verify(tiledTaskHelper, times(1)).dispose() + } + + @Test fun taskNotTiled_shouldNotBeRemoved_whenNotTiled() { val task1 = createVisibleTask() val task2 = createVisibleTask() @@ -652,6 +687,23 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() { whenever(userRepositories.current.isVisibleTask(eq(it.taskId))).thenReturn(true) } + private fun createPipTask() = + createPinnedTask().also { + whenever(userRepositories.current.isVisibleTask(eq(it.taskId))).thenReturn(true) + } + + private fun createPipChangeTransition(task: RunningTaskInfo?, type: Int = TRANSIT_PIP) = + TransitionInfo(type, /* flags= */ 0).apply { + addChange( + Change(mock(), mock()).apply { + mode = TRANSIT_PIP + parent = null + taskInfo = task + flags = flags + } + ) + } + companion object { private val NON_STABLE_BOUNDS_MOCK = Rect(50, 55, 100, 100) private val STABLE_BOUNDS_MOCK = Rect(0, 0, 100, 100) diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index a18c5f5f92f6..8ecd6ba9b253 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -6520,41 +6520,79 @@ base::expected<StringPiece16, NullOrIOError> StringPoolRef::string16() const { } bool ResTable::getResourceFlags(uint32_t resID, uint32_t* outFlags) const { - if (mError != NO_ERROR) { - return false; - } + if (mError != NO_ERROR) { + return false; + } - const ssize_t p = getResourcePackageIndex(resID); - const int t = Res_GETTYPE(resID); - const int e = Res_GETENTRY(resID); + const ssize_t p = getResourcePackageIndex(resID); + const int t = Res_GETTYPE(resID); + const int e = Res_GETENTRY(resID); - if (p < 0) { - if (Res_GETPACKAGE(resID)+1 == 0) { - ALOGW("No package identifier when getting flags for resource number 0x%08x", resID); - } else { - ALOGW("No known package when getting flags for resource number 0x%08x", resID); - } - return false; - } - if (t < 0) { - ALOGW("No type identifier when getting flags for resource number 0x%08x", resID); - return false; + if (p < 0) { + if (Res_GETPACKAGE(resID)+1 == 0) { + ALOGW("No package identifier when getting flags for resource number 0x%08x", resID); + } else { + ALOGW("No known package when getting flags for resource number 0x%08x", resID); } + return false; + } + if (t < 0) { + ALOGW("No type identifier when getting flags for resource number 0x%08x", resID); + return false; + } - const PackageGroup* const grp = mPackageGroups[p]; - if (grp == NULL) { - ALOGW("Bad identifier when getting flags for resource number 0x%08x", resID); - return false; - } + const PackageGroup* const grp = mPackageGroups[p]; + if (grp == NULL) { + ALOGW("Bad identifier when getting flags for resource number 0x%08x", resID); + return false; + } - Entry entry; - status_t err = getEntry(grp, t, e, NULL, &entry); - if (err != NO_ERROR) { - return false; + Entry entry; + status_t err = getEntry(grp, t, e, NULL, &entry); + if (err != NO_ERROR) { + return false; + } + + *outFlags = entry.specFlags; + return true; +} + +bool ResTable::getResourceEntryFlags(uint32_t resID, uint32_t* outFlags) const { + if (mError != NO_ERROR) { + return false; + } + + const ssize_t p = getResourcePackageIndex(resID); + const int t = Res_GETTYPE(resID); + const int e = Res_GETENTRY(resID); + + if (p < 0) { + if (Res_GETPACKAGE(resID)+1 == 0) { + ALOGW("No package identifier when getting flags for resource number 0x%08x", resID); + } else { + ALOGW("No known package when getting flags for resource number 0x%08x", resID); } + return false; + } + if (t < 0) { + ALOGW("No type identifier when getting flags for resource number 0x%08x", resID); + return false; + } - *outFlags = entry.specFlags; - return true; + const PackageGroup* const grp = mPackageGroups[p]; + if (grp == NULL) { + ALOGW("Bad identifier when getting flags for resource number 0x%08x", resID); + return false; + } + + Entry entry; + status_t err = getEntry(grp, t, e, NULL, &entry); + if (err != NO_ERROR) { + return false; + } + + *outFlags = entry.entry->flags(); + return true; } bool ResTable::isPackageDynamic(uint8_t packageID) const { diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index 0d45149267cf..63b28da075cd 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -1593,6 +1593,8 @@ union ResTable_entry // If set, this is a compact entry with data type and value directly // encoded in the this entry, see ResTable_entry::compact FLAG_COMPACT = 0x0008, + // If set, this entry relies on read write android feature flags + FLAG_USES_FEATURE_FLAGS = 0x0010, }; struct Full { @@ -1622,6 +1624,7 @@ union ResTable_entry uint16_t flags() const { return dtohs(full.flags); }; bool is_compact() const { return flags() & FLAG_COMPACT; } bool is_complex() const { return flags() & FLAG_COMPLEX; } + bool uses_feature_flags() const { return flags() & FLAG_USES_FEATURE_FLAGS; } size_t size() const { return is_compact() ? sizeof(ResTable_entry) : dtohs(this->full.size); @@ -2039,6 +2042,8 @@ public: bool getResourceFlags(uint32_t resID, uint32_t* outFlags) const; + bool getResourceEntryFlags(uint32_t resID, uint32_t* outFlags) const; + /** * Returns whether or not the package for the given resource has been dynamically assigned. * If the resource can't be found, returns 'false'. diff --git a/location/java/android/location/GnssClock.java b/location/java/android/location/GnssClock.java index 62f50b57520c..6930f365adc1 100644 --- a/location/java/android/location/GnssClock.java +++ b/location/java/android/location/GnssClock.java @@ -349,7 +349,7 @@ public final class GnssClock implements Parcelable { * Gets the clock's Drift in nanoseconds per second. * * <p>This value is the instantaneous time-derivative of the value provided by - * {@link #getBiasNanos()}. + * the sum of {@link #getFullBiasNanos()} and {@link #getBiasNanos()}. * * <p>A positive value indicates that the frequency is higher than the nominal (e.g. GPS master * clock) frequency. The error estimate for this reported drift is diff --git a/media/java/android/media/quality/MediaQualityContract.java b/media/java/android/media/quality/MediaQualityContract.java index e4de3e4420fe..fccdba8e727f 100644 --- a/media/java/android/media/quality/MediaQualityContract.java +++ b/media/java/android/media/quality/MediaQualityContract.java @@ -82,7 +82,7 @@ public class MediaQualityContract { String PARAMETER_NAME = "_name"; String PARAMETER_PACKAGE = "_package"; String PARAMETER_INPUT_ID = "_input_id"; - + String VENDOR_PARAMETERS = "_vendor_parameters"; } /** diff --git a/media/java/android/media/tv/extension/scan/IHDPlusInfo.aidl b/media/java/android/media/tv/extension/scan/IHDPlusInfo.aidl index cdf6e23f4b47..40848fe6f875 100644 --- a/media/java/android/media/tv/extension/scan/IHDPlusInfo.aidl +++ b/media/java/android/media/tv/extension/scan/IHDPlusInfo.aidl @@ -21,5 +21,5 @@ package android.media.tv.extension.scan; */ interface IHDPlusInfo { // Specifying a HDPlusInfo and start a network scan. - int setHDPlusInfo(String isBlindScanContinue, String isHDMode); + int setHDPlusInfo(boolean isBlindScanContinue, boolean isHDMode); } diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml index 394efae9da0e..87148207575b 100644 --- a/packages/CompanionDeviceManager/res/values-fr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml @@ -26,7 +26,7 @@ <string name="profile_name_watch" msgid="576290739483672360">"montre"</string> <string name="chooser_title_non_profile" msgid="6035023914517087400">"Sélectionner l\'appareil qui sera géré par <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string> <string name="chooser_title" msgid="2235819929238267637">"Sélectionner votre <xliff:g id="PROFILE_NAME">%1$s</xliff:g> à configurer"</string> - <string name="single_device_title" msgid="4199861437545438606">"Recherche de l\'appareil suivant : <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string> + <string name="single_device_title" msgid="4199861437545438606">"Recherche de votre <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string> <string name="summary_watch" msgid="8134580124808507407">"Cette appli sera autorisée à synchroniser des infos (comme le nom de l\'appelant) et disposera de ces autorisations sur votre <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à gérer <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ?"</string> <string name="profile_name_glasses" msgid="3506504967216601277">"appareil"</string> diff --git a/packages/ExternalStorageProvider/res/values-fa/strings.xml b/packages/ExternalStorageProvider/res/values-fa/strings.xml index 9eabfd027da2..28781f123ada 100644 --- a/packages/ExternalStorageProvider/res/values-fa/strings.xml +++ b/packages/ExternalStorageProvider/res/values-fa/strings.xml @@ -18,6 +18,6 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="748293919008814871">"حافظه خارجی"</string> <string name="storage_description" msgid="9176081505553938524">"فضای ذخیرهسازی محلی"</string> - <string name="root_internal_storage" msgid="4980477711224234931">"حافظهٔ داخلی"</string> + <string name="root_internal_storage" msgid="4980477711224234931">"فضای ذخیرهسازی داخلی"</string> <string name="root_documents" msgid="5695037589229175941">"اسناد"</string> </resources> diff --git a/packages/PackageInstaller/res/values-ne/strings.xml b/packages/PackageInstaller/res/values-ne/strings.xml index 0bc4be3e53d6..f7998309f2c1 100644 --- a/packages/PackageInstaller/res/values-ne/strings.xml +++ b/packages/PackageInstaller/res/values-ne/strings.xml @@ -17,7 +17,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_name" msgid="7488448184431507488">"प्याकेज स्थापनाकर्ता"</string> - <string name="install" msgid="711829760615509273">"स्थापना गर्नु…"</string> + <string name="install" msgid="711829760615509273">"इन्स्टल"</string> <string name="update" msgid="3932142540719227615">"अपडेट गर्नुहोस्"</string> <string name="done" msgid="6632441120016885253">"सम्पन्न भयो"</string> <string name="cancel" msgid="1018267193425558088">"रद्द गर्नुहोस्"</string> diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java index d55bbb3bbdbf..bf739620bc99 100644 --- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java +++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java @@ -187,7 +187,9 @@ public class IllustrationPreference extends Preference implements GroupSectionDi if (mLottieDynamicColor) { LottieColorUtils.applyDynamicColors(getContext(), illustrationView); } - LottieColorUtils.applyMaterialColor(getContext(), illustrationView); + if (SettingsThemeHelper.isExpressiveTheme(getContext())) { + LottieColorUtils.applyMaterialColor(getContext(), illustrationView); + } if (mOnBindListener != null) { mOnBindListener.onBind(illustrationView); diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java index 4421424c0e39..e59cc81d3ba8 100644 --- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java +++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java @@ -157,10 +157,6 @@ public class LottieColorUtils { /** Applies material colors. */ public static void applyMaterialColor(@NonNull Context context, @NonNull LottieAnimationView lottieAnimationView) { - if (!SettingsThemeHelper.isExpressiveTheme(context)) { - return; - } - for (String key : MATERIAL_COLOR_MAP.keySet()) { final int color = context.getColor(MATERIAL_COLOR_MAP.get(key)); lottieAnimationView.addValueCallback( diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-af/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-af/strings.xml index b41ec957f12d..9d3092d39d03 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-af/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-af/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Geaktiveer deur administrateur"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Gedeaktiveer deur administrateur"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Geaktiveer deur Gevorderde Beskerming"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Gedeaktiveer deur Gevorderde Beskerming"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-am/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-am/strings.xml index 8e9488453032..9617acaa0c14 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-am/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-am/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"በአስተዳዳሪ ነቅቷል"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"በአስተዳዳሪ ተሰናክሏል"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"በላቀ ጥበቃ የነቃ"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"በላቀ ጥበቃ የተሰናከለ"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ar/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ar/strings.xml index 8b2ccdfbb0e8..581b91458c1c 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-ar/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ar/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"يفعِّل المشرف هذا الإعداد."</string> <string name="disabled_by_admin" msgid="4023569940620832713">"أوقف المشرف هذا الإعداد"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"تم التفعيل من خلال ميزة \"الحماية المتقدّمة\""</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"تم الإيقاف من خلال ميزة \"الحماية المتقدّمة\""</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-as/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-as/strings.xml index 03e9e828534a..5824abdf921c 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-as/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-as/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"প্ৰশাসকে সক্ষম কৰিছে"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"প্ৰশাসকে অক্ষম কৰিছে"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"সুৰক্ষা সম্পৰ্কীয় উন্নত সুবিধাটোৱে সক্ষম কৰিছে"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"সুৰক্ষা সম্পৰ্কীয় উন্নত সুবিধাটোৱে অক্ষম কৰিছে"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-az/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-az/strings.xml index 98447166a156..f07e05403afb 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-az/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-az/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Admin tərəfindən aktiv edildi"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Admin tərəfindən deaktiv edildi"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Qabaqcıl Qoruma tərəfindən aktiv edilib"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Qabaqcıl Qoruma tərəfindən deaktiv edilib"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-b+sr+Latn/strings.xml index c7b9be28fb1e..e09afbfbbd63 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-b+sr+Latn/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Administrator je omogućio"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Administrator je onemogućio"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Omogućila je Napredna zaštita"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Onemogućila je Napredna zaštita"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-be/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-be/strings.xml index 92ed11157dfc..a64734bde002 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-be/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-be/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Уключана адміністратарам"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Адключана адміністратарам"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Уключана Палепшанай абаронай"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Адключана Палепшанай абаронай"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-bg/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-bg/strings.xml index 57b50c5c580c..ccaa6563cbe9 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-bg/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-bg/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Активирано от администратора"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Деактивирано от администратора"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Активирано от „Разширена защита“"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Деактивирано от „Разширена защита“"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-bn/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-bn/strings.xml index 939ceb82ab40..0a48aa21a36b 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-bn/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-bn/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"অ্যাডমিন চালু করেছেন"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"অ্যাডমিন বন্ধ করেছেন"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"উন্নত সুরক্ষা চালু করেছে"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"উন্নত সুরক্ষা বন্ধ করেছে"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-bs/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-bs/strings.xml index 87cd3b8905c7..eebcebffe2a1 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-bs/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-bs/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Omogućio administrator"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Onemogućio administrator"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Omogućeno je Naprednom zaštitom"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Onemogućeno je Naprednom zaštitom"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ca/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ca/strings.xml index 34099b6f3f08..51e3fa9c8a41 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-ca/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ca/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Activat per l\'administrador"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Desactivat per l\'administrador"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Activat per la Protecció avançada"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Desactivat per la Protecció avançada"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-cs/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-cs/strings.xml index 82cd56f39059..a5db6099c8cb 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-cs/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-cs/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Zapnuto administrátorem"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Vypnuto administrátorem"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Aktivováno pokročilou ochranou"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Deaktivováno pokročilou ochranou"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-da/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-da/strings.xml index 7f7ae8b3d5e0..7f10edf158b6 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-da/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-da/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Aktiveret af administratoren"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Deaktiveret af administrator"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Aktiveret af Avanceret beskyttelse"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Deaktiveret af Avanceret beskyttelse"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-de/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-de/strings.xml index efaa50efacf4..604593bf0966 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-de/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-de/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Vom Administrator aktiviert"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Vom Administrator deaktiviert"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Vom erweiterten Sicherheitsprogramm aktiviert"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Vom erweiterten Sicherheitsprogramm deaktiviert"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-el/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-el/strings.xml index ddde3ece472a..79b401607a94 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-el/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-el/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Ενεργοποιήθηκε από τον διαχειριστή"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Απενεργοποιήθηκε από τον διαχειριστή"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Ενεργοποιήθηκε από την Ενισχυμένη προστασία"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Απενεργοποιήθηκε από την Ενισχυμένη προστασία"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-en-rAU/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rAU/strings.xml index 6a07741d8e4c..14b92720487e 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-en-rAU/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rAU/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Enabled by admin"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Disabled by admin"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Enabled by Advanced Protection"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Disabled by Advanced Protection"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-en-rCA/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rCA/strings.xml index 6a07741d8e4c..14b92720487e 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-en-rCA/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rCA/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Enabled by admin"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Disabled by admin"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Enabled by Advanced Protection"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Disabled by Advanced Protection"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-en-rGB/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rGB/strings.xml index 6a07741d8e4c..14b92720487e 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-en-rGB/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rGB/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Enabled by admin"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Disabled by admin"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Enabled by Advanced Protection"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Disabled by Advanced Protection"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-en-rIN/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rIN/strings.xml index 6a07741d8e4c..14b92720487e 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-en-rIN/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rIN/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Enabled by admin"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Disabled by admin"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Enabled by Advanced Protection"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Disabled by Advanced Protection"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-es-rUS/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-es-rUS/strings.xml index 8dc15f77f6e0..616b568d58fe 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-es-rUS/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"El administrador habilitó la opción"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"El administrador inhabilitó la opción"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Habilitado por la Protección avanzada"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Inhabilitado por la Protección avanzada"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-es/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-es/strings.xml index 7c9864d7e81e..351f16cb1a24 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-es/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-es/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Habilitado por el administrador"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Inhabilitado por el administrador"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Habilitado por Protección Avanzada"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Inhabilitado por Protección Avanzada"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-et/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-et/strings.xml index 5939b584a0f2..c59d6459789e 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-et/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-et/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Administraatori lubatud"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Administraatori keelatud"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Lubatud täiustatud kaitsega"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Keelatud täiustatud kaitsega"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-eu/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-eu/strings.xml index 27bef6e92073..2a881247c3af 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-eu/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-eu/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Administratzaileak gaitu egin du"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Administratzaileak desgaitu du"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Babes aurreratua programak gaitu du"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Babes aurreratua programak desgaitu du"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml index 8fb2646821dc..9c39f98aab17 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"توسط سرپرست فعال شده"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"توسط سرپرست غیرفعال شده"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"فعالشده با «محافظت پیشرفته»"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"غیرفعالشده با «محافظت پیشرفته»"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-fi/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-fi/strings.xml index cd7cbd3d83ca..41fef5af7033 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-fi/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-fi/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Järjestelmänvalvojan sallima"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Järjestelmänvalvojan estämä"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Lisäsuojaus on ottanut asetuksen käyttöön"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Lisäsuojaus on poistanut asetuksen käytöstä"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-fr-rCA/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-fr-rCA/strings.xml index da74cf6a3ab9..9ff117427555 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-fr-rCA/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-fr-rCA/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Activé par l\'administrateur"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Désactivé par l\'administrateur"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Activée par la protection avancée"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Désactivée par la protection avancée"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-fr/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-fr/strings.xml index 2215af24664c..9ff117427555 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-fr/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-fr/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Activé par l\'administrateur"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Désactivé par l\'administrateur"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Activé par la Protection Avancée"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Désactivé par la Protection Avancée"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-gl/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-gl/strings.xml index 92f33bbf2533..dbf8f7d83b6c 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-gl/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-gl/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Opción activada polo administrador"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Opción desactivada polo administrador"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Opción activada por Protección avanzada"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Opción desactivada por Protección avanzada"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-gu/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-gu/strings.xml index 026bdb1127d3..4fc4ab48059d 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-gu/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-gu/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"વ્યવસ્થાપકે ચાલુ કરેલ"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"ઍડમિને બંધ કરેલું"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"અદ્યતન સુરક્ષા દ્વારા ચાલુ કરવામાં આવી છે"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"અદ્યતન સુરક્ષા દ્વારા બંધ કરવામાં આવી છે"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-hi/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-hi/strings.xml index 8fc8fd04ad93..6de84388bbe4 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-hi/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-hi/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"एडमिन की ओर से चालू किया गया"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"एडमिन ने यह सुविधा बंद की हुई है"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"\'ऐडवांस सुरक्षा\' सेटिंग ने चालू किया है"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"\'ऐडवांस सुरक्षा\' सेटिंग ने बंद किया है"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-hr/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-hr/strings.xml index 40605a3b83fb..eebcebffe2a1 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-hr/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-hr/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Omogućio administrator"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Onemogućio administrator"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Omogućila je napredna zaštita"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Onemogućila je napredna zaštita"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-hu/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-hu/strings.xml index 59135a42fd2a..ecfa2c794e28 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-hu/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-hu/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"A rendszergazda bekapcsolta"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"A rendszergazda letiltotta"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Engedélyezte a Speciális védelem"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Letiltotta a Speciális védelem"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-hy/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-hy/strings.xml index 0221f9333249..23a2a6b125eb 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-hy/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-hy/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Միացված է ադմինիստրատորի կողմից"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Անջատվել է ադմինիստրատորի կողմից"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Միացվել է Լրացուցիչ պաշտպանության կողմից"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Անջատվել է Լրացուցիչ պաշտպանության կողմից"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-in/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-in/strings.xml index 6beb4c9b2c26..ae8ec8251b7d 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-in/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-in/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Diaktifkan oleh admin"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Dinonaktifkan oleh admin"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Diaktifkan oleh Perlindungan Lanjutan"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Dinonaktifkan oleh Perlindungan Lanjutan"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-is/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-is/strings.xml index feb325bf2210..55380b333edd 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-is/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-is/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Gert virkt af kerfisstjóra"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Gert óvirkt af kerfisstjóra"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Virkjað af ítarlegri vernd"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Gert óvirkt af ítarlegri vernd"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-it/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-it/strings.xml index 616392026b55..bddf43ce6917 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-it/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-it/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Attivata dall\'amministratore"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Opzione disattivata dall\'amministratore"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Attivata dalla protezione avanzata"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Disattivata dalla protezione avanzata"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-iw/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-iw/strings.xml index c342041f6c6e..007de061fbe9 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-iw/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-iw/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"מופעל על ידי מנהל המכשיר"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"האפשרות הושבתה על ידי האדמין"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"ההעדפה הופעלה על ידי ההגנה המתקדמת"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"ההעדפה הושבתה על ידי ההגנה המתקדמת"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ja/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ja/strings.xml index bd386f5858a9..490efd099569 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-ja/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ja/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"管理者によって有効にされています"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"管理者により無効にされています"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"高度な保護機能により有効になっています"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"高度な保護機能により無効になっています"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ka/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ka/strings.xml index a6fde9022a21..5c394b832af9 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-ka/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ka/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"ჩართულია ადმინისტრატორის მიერ"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"გათიშულია ადმინისტრატორის მიერ"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"ჩართულია დამატებითი დაცვის საშუალებით"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"გათიშულია დამატებითი დაცვის საშუალებით"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-kk/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-kk/strings.xml index ed0f95c200f6..eff7e44c6a39 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-kk/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-kk/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Әкімші қосқан"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Әкімші өшірген"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Күшейтілген қорғаныс параметрі қосып қойды."</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Күшейтілген қорғаныс параметрі өшіріп тастады."</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-km/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-km/strings.xml index f2f5ab8e1dbf..5a4f0748c796 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-km/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-km/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"បើកដោយអ្នកគ្រប់គ្រង"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"បានបិទដោយអ្នកគ្រប់គ្រង"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"បានបើកដោយការការពារកម្រិតខ្ពស់"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"បានបិទដោយការការពារកម្រិតខ្ពស់"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-kn/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-kn/strings.xml index ebc41a52b4df..9b7a0d8b97bd 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-kn/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-kn/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"ನಿರ್ವಾಹಕರು ಸಕ್ರಿಯಗೊಳಿಸಿದ್ದಾರೆ"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"ನಿರ್ವಾಹಕರು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿದ್ದಾರೆ"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"ಸುಧಾರಿತ ಸಂರಕ್ಷಣೆ ಮೂಲಕ ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"ಸುಧಾರಿತ ಸಂರಕ್ಷಣೆ ಮೂಲಕ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ko/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ko/strings.xml index 552662b4be95..d4f134cf3adb 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-ko/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ko/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"관리자가 사용 설정함"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"관리자가 사용 중지함"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"고급 보호 기능으로 사용 설정됨"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"고급 보호 기능으로 사용 중지됨"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ky/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ky/strings.xml index 375ea19ff66e..a934b51f6a98 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-ky/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ky/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Администратор иштетип койгон"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Администратор өчүрүп койгон"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Өркүндөтүлгөн коргоо тарабынан иштетилди"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Өркүндөтүлгөн коргоо тарабынан өчүрүлдү"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-lo/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-lo/strings.xml index 4b311c0ce38d..c2d80f28130e 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-lo/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-lo/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"ເປີດນຳໃຊ້ໂດຍຜູ້ເບິ່ງແຍງລະບົບ"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"ຖືກຜູ້ເບິ່ງແຍງລະບົບປິດໄວ້"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"ໄດ້ເປີດການນຳໃຊ້ໂດຍການປົກປ້ອງຂັ້ນສູງ"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"ໄດ້ປິດການນຳໃຊ້ໂດຍການປົກປ້ອງຂັ້ນສູງ"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-lt/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-lt/strings.xml index cbbe92374854..2e96a0ad7dae 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-lt/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-lt/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Įgalino administratorius"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Išjungė administratorius"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Įgalino Papildoma apsauga"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Išjungė Papildoma apsauga"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-lv/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-lv/strings.xml index a5189aa70ff8..1d2bcb0d484b 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-lv/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-lv/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Iespējoja administrators"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Atspējoja administrators"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Iespējota iestatījuma “Papildu aizsardzība” dēļ"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Atspējota iestatījuma “Papildu aizsardzība” dēļ"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-mk/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-mk/strings.xml index 993b4aea8b13..1c8f1d1a0c43 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-mk/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-mk/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Овозможено од администраторот"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Оневозможено од администраторот"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Овозможено од „Напредна заштита“"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Оневозможено од „Напредна заштита“"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ml/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ml/strings.xml index 9deeb6aa2cfd..c4ee22491659 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-ml/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ml/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"അഡ്മിൻ പ്രവർത്തനക്ഷമമാക്കി"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"അഡ്മിൻ പ്രവർത്തനരഹിതമാക്കി"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"വിപുലമായ പരിരക്ഷ പ്രവർത്തനക്ഷമമാക്കി"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"വിപുലമായ പരിരക്ഷ പ്രവർത്തനരഹിതമാക്കി"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-mn/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-mn/strings.xml index c9a91de26591..472c50ac36a3 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-mn/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-mn/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Админ идэвхжүүлсэн"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Админ цуцалсан"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Дэвшилтэт хамгаалалтаар идэвхжүүлсэн"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Дэвшилтэт хамгаалалтаар идэвхгүй болгосон"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-mr/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-mr/strings.xml index ede12424de04..d01bfc4dea81 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-mr/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-mr/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"अॅडमिनने सुरू केलेले"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"अॅडमिनने बंद केलेले"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"प्रगत संरक्षणाद्वारे सुरू केले आहे"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"प्रगत संरक्षणाद्वारे बंद केले आहे"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ms/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ms/strings.xml index e8f710a7c909..618ea8c13c37 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-ms/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ms/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Didayakan oleh pentadbir"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Dilumpuhkan oleh pentadbir"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Didayakan oleh Perlindungan Lanjutan"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Dilumpuhkan oleh Perlindungan Lanjutan"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-my/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-my/strings.xml index 97be99f43291..e4626000476e 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-my/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-my/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"စီမံခန့်ခွဲသူက ဖွင့်ထားသည်"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"စီမံခန့်ခွဲသူက ပိတ်ထားသည်"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"အဆင့်မြင့်ကာကွယ်ရေးက ဖွင့်ထားသည်"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"အဆင့်မြင့်ကာကွယ်ရေးက ပိတ်ထားသည်"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-nb/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-nb/strings.xml index 971d1ccd190a..509e70b31645 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-nb/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-nb/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Aktivert av administratoren"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Deaktivert av administratoren"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Aktivert av Avansert beskyttelse"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Deaktivert av Avansert beskyttelse"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ne/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ne/strings.xml index 3d2a74e3b270..15bb85c7b174 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-ne/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ne/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"प्रशासकद्वारा सक्षम पारिएको"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"एडमिनले अफ गरेको"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"सुरक्षासम्बन्धी उन्नत सुविधाले अन गरेको छ"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"सुरक्षासम्बन्धी उन्नत सुविधाले अफ गरेको छ"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-nl/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-nl/strings.xml index 9830363c7f65..a73deafbc70f 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-nl/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-nl/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Aangezet door beheerder"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Uitgezet door beheerder"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Aangezet door Geavanceerde beveiliging"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Uitgezet door Geavanceerde beveiliging"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml index 2dab1592c296..4ce6460f8b89 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"ଆଡମିନଙ୍କ ଦ୍ୱାରା ସକ୍ଷମ କରାଯାଇଛି"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"ଆଡମିନଙ୍କ ଦ୍ଵାରା ଅକ୍ଷମ କରାଯାଇଛି"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"ଆଡଭାନ୍ସଡ ପ୍ରୋଟେକସନ ଦ୍ୱାରା ସକ୍ଷମ କରାଯାଇଛି"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"ଆଡଭାନ୍ସଡ ପ୍ରୋଟେକସନ ଦ୍ୱାରା ଅକ୍ଷମ କରାଯାଇଛି"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-pa/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-pa/strings.xml index 12f296a46b2d..1a3a133e6c41 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-pa/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-pa/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਚਾਲੂ ਕੀਤਾ ਗਿਆ"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਬੰਦ ਕੀਤਾ ਗਿਆ"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"ਅਡਵਾਂਸ ਸੁਰੱਖਿਆ ਵੱਲੋਂ ਚਾਲੂ ਕੀਤੀ ਗਈ"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"ਅਡਵਾਂਸ ਸੁਰੱਖਿਆ ਵੱਲੋਂ ਬੰਦ ਕੀਤੀ ਗਈ"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-pl/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-pl/strings.xml index df7394766339..0523e2b23ed3 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-pl/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-pl/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Włączone przez administratora"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Wyłączone przez administratora"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Włączone przez Ochronę zaawansowaną"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Wyłączone przez Ochronę zaawansowaną"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rBR/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rBR/strings.xml index a705ba421910..908e2fbbff5b 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rBR/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Ativado pelo administrador"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Desativado pelo administrador"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Preferência ativada pela Proteção Avançada"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Preferência desativada pela Proteção Avançada"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rPT/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rPT/strings.xml index b01118381478..908e2fbbff5b 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rPT/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Ativado pelo administrador"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Desativado pelo administrador"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Ativado pela Proteção avançada"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Desativado pela Proteção avançada"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-pt/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-pt/strings.xml index a705ba421910..908e2fbbff5b 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-pt/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-pt/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Ativado pelo administrador"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Desativado pelo administrador"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Preferência ativada pela Proteção Avançada"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Preferência desativada pela Proteção Avançada"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ro/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ro/strings.xml index 3eb347abbc1b..ad41605c636f 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-ro/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ro/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Activat de administrator"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Dezactivat de administrator"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Activată de Protecția avansată"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Dezactivată de Protecția avansată"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ru/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ru/strings.xml index a004a1fe60da..59006449133d 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-ru/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ru/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Включено администратором"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Отключено администратором"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Включено Дополнительной защитой"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Отключено Дополнительной защитой"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-si/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-si/strings.xml index addc8b3ae15c..de89710d7acd 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-si/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-si/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"පරිපාලක විසින් සබල කර ඇත"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"ඔබගේ පරිපාලක විසින් අබල කර ඇත"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"උසස් ආරක්ෂණය මගින් සබල කර ඇත"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"උසස් ආරක්ෂණය මගින් අබල කර ඇත"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-sk/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-sk/strings.xml index 0277696560b9..b8bb91942799 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-sk/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-sk/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Povolené správcom"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Zakázané správcom"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Aktivované rozšírenou ochranou"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Deaktivované rozšírenou ochranou"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-sl/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-sl/strings.xml index eb886bcf1232..1d8ee573e233 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-sl/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-sl/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Omogočil skrbnik"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Onemogočil skrbnik"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Omogočila dodatna zaščita"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Onemogočila dodatna zaščita"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-sq/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-sq/strings.xml index 2de5ffe47c1c..4ee40bf39b59 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-sq/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-sq/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Aktivizuar nga administratori"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Çaktivizuar nga administratori"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Aktivizuar nga \"Mbrojtja e përparuar\""</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Çaktivizuar nga \"Mbrojtja e përparuar\""</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-sr/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-sr/strings.xml index 94f52a0b95a2..9d006a7ef4ef 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-sr/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-sr/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Администратор је омогућио"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Администратор је онемогућио"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Омогућила је Напредна заштита"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Онемогућила је Напредна заштита"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-sv/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-sv/strings.xml index b41c4d8a8275..faea0703468e 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-sv/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-sv/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Aktiverad av administratör"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Inaktiverad av administratören"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Aktiverades av Avancerat skydd"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Inaktiverades av Avancerat skydd"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-sw/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-sw/strings.xml index 4d2e0d994972..59f511aea6fc 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-sw/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-sw/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Imewashwa na msimamizi"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Imezimwa na msimamizi"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Imewashwa kwa kutumia Ulinzi wa Hali ya Juu"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Imezimwa kwa kutumia Ulinzi wa Hali ya Juu"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ta/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ta/strings.xml index 55b300657eaf..3ef5f77e96dc 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-ta/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ta/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"நிர்வாகி இயக்கியுள்ளார்"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"நிர்வாகி முடக்கியுள்ளார்"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"மேம்பட்ட பாதுகாப்பு அமைப்பால் இயக்கப்பட்டது"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"மேம்பட்ட பாதுகாப்பு அமைப்பால் முடக்கப்பட்டது"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml index fc6d00b22d34..8f17dc5ec1e8 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"అడ్మిన్ ఎనేబుల్ చేశారు"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"అడ్మిన్ డిజేబుల్ చేశారు"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"అడ్వాన్స్డ్ ప్రొటెక్షన్ ద్వారా ఎనేబుల్ చేయబడింది"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"అడ్వాన్స్డ్ ప్రొటెక్షన్ ద్వారా డిజేబుల్ చేయబడింది"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-th/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-th/strings.xml index 51da8dec6443..80fd0c04cb2f 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-th/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-th/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"เปิดใช้โดยผู้ดูแลระบบ"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"ปิดใช้โดยผู้ดูแลระบบ"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"เปิดใช้โดยการปกป้องขั้นสูง"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"ปิดใช้โดยการปกป้องขั้นสูง"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-tl/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-tl/strings.xml index 7fbf0e7ace73..a4a538dc84ba 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-tl/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-tl/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Na-enable ng admin"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Na-disable ng admin"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Na-enable ng Advanced na Proteksyon"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Na-disable ng Advanced na Proteksyon"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-tr/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-tr/strings.xml index a529ca557ba1..ac5ed6a152b7 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-tr/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-tr/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Yönetici tarafından etkinleştirildi"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Yönetici tarafından devre dışı bırakıldı"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Gelişmiş Koruma tarafından etkinleştirildi"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Gelişmiş Koruma tarafından devre dışı bırakıldı"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-uk/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-uk/strings.xml index fdf4160b1bb0..32f02a45608e 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-uk/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-uk/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Увімкнено адміністратором"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Вимкнено адміністратором"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Увімкнено Додатковим захистом"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Вимкнено Додатковим захистом"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ur/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ur/strings.xml index b40cb6827523..f3752d90497c 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-ur/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ur/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"منتظم کی طرف سے فعال کردہ"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"منتظم کی طرف سے غیر فعال کردہ"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"اعلی تحفظ نے فعال کیا ہے"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"اعلی تحفظ نے غیر فعال کیا ہے"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-uz/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-uz/strings.xml index 9a27735407e2..e2e9f423f501 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-uz/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-uz/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Administrator tomonidan yoqilgan"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Administrator tomonidan faolsizlantirilgan"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Kuchaytirilgan himoya tomonidan yoqilgan"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Kuchaytirilgan himoya tomonidan faolsizlantirilgan"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml index 3436762f8355..dd654b290977 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Do quản trị viên bật"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Quản trị viên đã vô hiệu hóa chế độ này"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Được bật bởi chế độ Bảo vệ nâng cao"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Bị tắt bởi chế độ Bảo vệ nâng cao"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rCN/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rCN/strings.xml index 5c9e302f274c..8fa969ea5112 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rCN/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rCN/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"已被管理员启用"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"已被管理员停用"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"已被“高级保护”功能启用"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"已被“高级保护”功能停用"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rHK/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rHK/strings.xml index d4b883355cf3..501f86084340 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rHK/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"已由管理員啟用"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"已由管理員停用"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"已由進階保護功能啟用"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"已由進階保護功能停用"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rTW/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rTW/strings.xml index d4b883355cf3..501f86084340 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rTW/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"已由管理員啟用"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"已由管理員停用"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"已由進階保護功能啟用"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"已由進階保護功能停用"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-zu/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-zu/strings.xml index 2a93d00d687f..86a6acb92df4 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-zu/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-zu/strings.xml @@ -19,6 +19,4 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Kunikwe amandla umlawuli"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"Kukhutshazwe umlawuli"</string> - <string name="enabled_by_advanced_protection" msgid="6236917660829422499">"Kunikwe Amandla Ukuvikela Okuthuthukile"</string> - <string name="disabled_by_advanced_protection" msgid="369596009193239632">"Kukhutshazwe Ukuvikela Okuthuthukile"</string> </resources> diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml index dcad7356508d..58ddc723b77a 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Beheer deur Beperkte Instellings"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Onbeskikbaar tydens oproepe"</string> <string name="disabled" msgid="8017887509554714950">"Gedeaktiveer"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Toegelaat"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Nie toegelaat nie"</string> <string name="install_other_apps" msgid="3232595082023199454">"Installeer onbekende apps"</string> diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml index dc6bd0fb06c8..3844a4b69d86 100644 --- a/packages/SettingsLib/res/values-am/strings.xml +++ b/packages/SettingsLib/res/values-am/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"በተገደበ ቅንብር ቁጥጥር የሚደረግበት"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"በጥሪዎች ጊዜ አይገኝም"</string> <string name="disabled" msgid="8017887509554714950">"ቦዝኗል"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"ይፈቀዳል"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"አይፈቀድም"</string> <string name="install_other_apps" msgid="3232595082023199454">"ያልታወቁ መተግበሪያዎችን ይጫኑ"</string> diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml index 5fbab96a6a01..0d31c2eb0b96 100644 --- a/packages/SettingsLib/res/values-ar/strings.xml +++ b/packages/SettingsLib/res/values-ar/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"يتحكّم فيه إعداد محظور"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"غير متاح أثناء المكالمات"</string> <string name="disabled" msgid="8017887509554714950">"غير مفعّل"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"تطبيق مسموح به"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"تطبيق غير مسموح به"</string> <string name="install_other_apps" msgid="3232595082023199454">"تثبيت التطبيقات غير المعروفة"</string> diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml index f95a66befec1..56f73df512a1 100644 --- a/packages/SettingsLib/res/values-as/strings.xml +++ b/packages/SettingsLib/res/values-as/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"প্ৰতিবন্ধিত ছেটিঙৰ দ্বাৰা নিয়ন্ত্ৰিত"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"কল চলি থকাৰ সময়ত উপলব্ধ নহয়"</string> <string name="disabled" msgid="8017887509554714950">"নিষ্ক্ৰিয়"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"অনুমতি দিয়া হৈছে"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"অনুমতি দিয়া হোৱা নাই"</string> <string name="install_other_apps" msgid="3232595082023199454">"অজ্ঞাত এপ্ ইনষ্টল কৰক"</string> diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml index 5e47ff955125..b7dcfb857902 100644 --- a/packages/SettingsLib/res/values-az/strings.xml +++ b/packages/SettingsLib/res/values-az/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Məhdudlaşdırılmış Ayar ilə nəzarət edilir"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Zənglər zamanı əlçatan deyil"</string> <string name="disabled" msgid="8017887509554714950">"Deaktiv"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"İcazə verilib"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"İcazə verilməyib"</string> <string name="install_other_apps" msgid="3232595082023199454">"Tanınmayan tətbiqlərin quraşdırılması"</string> diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml index cb623991538d..97873e5a2d2a 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrolišu ograničena podešavanja"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Nedostupno tokom poziva"</string> <string name="disabled" msgid="8017887509554714950">"Onemogućeno"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Dozvoljeno"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Nije dozvoljeno"</string> <string name="install_other_apps" msgid="3232595082023199454">"Instaliranje nepoznatih aplikacija"</string> diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml index ef66fb32d844..78a5eaf388f0 100644 --- a/packages/SettingsLib/res/values-be/strings.xml +++ b/packages/SettingsLib/res/values-be/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Пад кіраваннем Абмежаванага наладжвання"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Недаступна падчас выклікаў"</string> <string name="disabled" msgid="8017887509554714950">"Адключанае"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Дазволена"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Забаронена"</string> <string name="install_other_apps" msgid="3232595082023199454">"Усталёўка невядомых праграм"</string> diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml index 69d68662b8c5..9fc0dea9abea 100644 --- a/packages/SettingsLib/res/values-bg/strings.xml +++ b/packages/SettingsLib/res/values-bg/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Управлява се чрез ограничена настройка"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Заето по време на обаждания"</string> <string name="disabled" msgid="8017887509554714950">"Деактивирано"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Има разрешение"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Няма разрешение"</string> <string name="install_other_apps" msgid="3232595082023199454">"Инст. на неизвестни прилож."</string> diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml index 7e8e3fe3de70..79e4ed9600aa 100644 --- a/packages/SettingsLib/res/values-bn/strings.xml +++ b/packages/SettingsLib/res/values-bn/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"এটি বিধিনিষেধ সেটিং থেকে নিয়ন্ত্রণ করা হয়"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"কল চলাকালীন উপলভ্য হবে না"</string> <string name="disabled" msgid="8017887509554714950">"অক্ষম হয়েছে"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"অনুমোদিত"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"অনুমোদিত নয়"</string> <string name="install_other_apps" msgid="3232595082023199454">"অজানা অ্যাপ ইনস্টল করা"</string> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index d0b15d9e6768..d06ce341fa99 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrolira ograničena postavka"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Nije dostupno tokom poziva"</string> <string name="disabled" msgid="8017887509554714950">"Onemogućeno"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Dozvoljeno"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Nije dozvoljeno"</string> <string name="install_other_apps" msgid="3232595082023199454">"Instaliranje nepoznatih aplikacija"</string> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index 283182c7219d..776caae3b828 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -507,7 +507,7 @@ <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Hauria de durar aproximadament fins a les <xliff:g id="TIME">%1$s</xliff:g> segons l\'ús que en facis"</string> <string name="power_discharge_by" msgid="4113180890060388350">"Hauria de durar aproximadament fins a les <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="92545648425937000">"Hauria de durar aproximadament fins a les <xliff:g id="TIME">%1$s</xliff:g>"</string> - <string name="power_discharge_by_only_short" msgid="5883041507426914446">"fins a les <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="5883041507426914446">"Fins a les <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"És possible que la bateria s\'esgoti a les <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"Temps restant inferior a <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="318215464914990578">"Temps restant inferior a <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlat per l\'opció de configuració restringida"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"No està disponible durant les trucades"</string> <string name="disabled" msgid="8017887509554714950">"Desactivat"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Amb permís"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Sense permís"</string> <string name="install_other_apps" msgid="3232595082023199454">"Instal·la aplicacions desconegudes"</string> diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml index bc00d47af14f..02722fd98959 100644 --- a/packages/SettingsLib/res/values-cs/strings.xml +++ b/packages/SettingsLib/res/values-cs/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Spravováno omezeným nastavením"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Při volání nedostupné"</string> <string name="disabled" msgid="8017887509554714950">"Deaktivováno"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Povoleno"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Není povoleno"</string> <string name="install_other_apps" msgid="3232595082023199454">"Instalace neznámých aplikací"</string> diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index ef1448316f26..4d37578c68b9 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Styres af en begrænset indstilling"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Kan ikke bruges under opkald"</string> <string name="disabled" msgid="8017887509554714950">"Deaktiveret"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Tilladt"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Ikke tilladt"</string> <string name="install_other_apps" msgid="3232595082023199454">"Installer ukendte apps"</string> diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml index e7ffaa4f6048..3e57002a7a59 100644 --- a/packages/SettingsLib/res/values-de/strings.xml +++ b/packages/SettingsLib/res/values-de/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Gesteuert durch eingeschränkte Einstellung"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Während Anrufen nicht verfügbar"</string> <string name="disabled" msgid="8017887509554714950">"Deaktiviert"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Zugelassen"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Nicht zugelassen"</string> <string name="install_other_apps" msgid="3232595082023199454">"Installieren unbekannter Apps"</string> diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml index 2fc0ff2fc1db..be1135690e62 100644 --- a/packages/SettingsLib/res/values-el/strings.xml +++ b/packages/SettingsLib/res/values-el/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Ελέγχεται από τη Ρύθμιση με περιορισμό"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Μη διαθέσιμη κατά τη διάρκεια κλήσεων"</string> <string name="disabled" msgid="8017887509554714950">"Απενεργοποιημένη"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Επιτρέπεται"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Δεν επιτρέπεται"</string> <string name="install_other_apps" msgid="3232595082023199454">"Εγκατ. άγνωστων εφ."</string> diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml index 34d6bf7299f2..8c819ac742a1 100644 --- a/packages/SettingsLib/res/values-en-rAU/strings.xml +++ b/packages/SettingsLib/res/values-en-rAU/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlled by restricted setting"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Unavailable during calls"</string> <string name="disabled" msgid="8017887509554714950">"Disabled"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Allowed"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Not allowed"</string> <string name="install_other_apps" msgid="3232595082023199454">"Install unknown apps"</string> diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml index 120343727593..2faf2feed627 100644 --- a/packages/SettingsLib/res/values-en-rCA/strings.xml +++ b/packages/SettingsLib/res/values-en-rCA/strings.xml @@ -539,6 +539,7 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlled by Restricted Setting"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Unavailable during calls"</string> <string name="disabled" msgid="8017887509554714950">"Disabled"</string> + <string name="enabled" msgid="3997122818554810678">"Enabled"</string> <string name="external_source_trusted" msgid="1146522036773132905">"Allowed"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Not allowed"</string> <string name="install_other_apps" msgid="3232595082023199454">"Install unknown apps"</string> diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml index 34d6bf7299f2..8c819ac742a1 100644 --- a/packages/SettingsLib/res/values-en-rGB/strings.xml +++ b/packages/SettingsLib/res/values-en-rGB/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlled by restricted setting"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Unavailable during calls"</string> <string name="disabled" msgid="8017887509554714950">"Disabled"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Allowed"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Not allowed"</string> <string name="install_other_apps" msgid="3232595082023199454">"Install unknown apps"</string> diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml index 34d6bf7299f2..8c819ac742a1 100644 --- a/packages/SettingsLib/res/values-en-rIN/strings.xml +++ b/packages/SettingsLib/res/values-en-rIN/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlled by restricted setting"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Unavailable during calls"</string> <string name="disabled" msgid="8017887509554714950">"Disabled"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Allowed"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Not allowed"</string> <string name="install_other_apps" msgid="3232595082023199454">"Install unknown apps"</string> diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index ca17178b0db0..224ad41a5ad2 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Función controlada por configuración restringida"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"No disponible durante llamadas"</string> <string name="disabled" msgid="8017887509554714950">"Inhabilitada"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Con permiso"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"No permitida"</string> <string name="install_other_apps" msgid="3232595082023199454">"Instalar apps desconocidas"</string> diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index 22e8b114f875..66d81d27a807 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlado por ajustes restringidos"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"No disponible durante las llamadas"</string> <string name="disabled" msgid="8017887509554714950">"Inhabilitada"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Autorizadas"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"No autorizadas"</string> <string name="install_other_apps" msgid="3232595082023199454">"Instalar aplicaciones desconocidas"</string> diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml index 0de019794528..59e1e4b4bc95 100644 --- a/packages/SettingsLib/res/values-et/strings.xml +++ b/packages/SettingsLib/res/values-et/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Haldavad piiranguga seaded"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Pole kõnede ajal saadaval"</string> <string name="disabled" msgid="8017887509554714950">"Keelatud"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Lubatud"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Pole lubatud"</string> <string name="install_other_apps" msgid="3232595082023199454">"Tundmatute rakenduste installimine"</string> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 7a8bf56841b6..6fd7e24b8c8b 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Ezarpen mugatuak kontrolatzen du"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Ez dago erabilgarri deiak egin bitartean"</string> <string name="disabled" msgid="8017887509554714950">"Desgaituta"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Baimenduta"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Baimendu gabe"</string> <string name="install_other_apps" msgid="3232595082023199454">"Instalatu aplikazio ezezagunak"</string> diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index 9ba2f3510980..d42a7a0acb3c 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"با تنظیم «حالت محدود» کنترل میشود"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"درطول تماس دردسترس نیست"</string> <string name="disabled" msgid="8017887509554714950">"غیر فعال شد"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"مجاز بودن"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"مجاز نبودن"</string> <string name="install_other_apps" msgid="3232595082023199454">"نصب برنامههای ناشناس"</string> diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml index d1cc76cab9aa..a66c8cf375a5 100644 --- a/packages/SettingsLib/res/values-fi/strings.xml +++ b/packages/SettingsLib/res/values-fi/strings.xml @@ -246,7 +246,7 @@ <item msgid="6946761421234586000">"400 %"</item> </string-array> <string name="choose_profile" msgid="343803890897657450">"Valitse profiili"</string> - <string name="category_personal" msgid="6236798763159385225">"Henkilökohtainen"</string> + <string name="category_personal" msgid="6236798763159385225">"Omat"</string> <string name="category_work" msgid="4014193632325996115">"Työ"</string> <string name="category_private" msgid="4244892185452788977">"Yksityinen"</string> <string name="category_clone" msgid="1554511758987195974">"Klooni"</string> @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Rajoitettujen asetusten mukaisesti"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Ei käytettävissä puhelujen aikana"</string> <string name="disabled" msgid="8017887509554714950">"Pois päältä"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Sallittu"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Ei sallittu"</string> <string name="install_other_apps" msgid="3232595082023199454">"Tuntemattomien sovellusten asentaminen"</string> diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml index d83389261c71..f332208d742a 100644 --- a/packages/SettingsLib/res/values-fr-rCA/strings.xml +++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Contrôlé par les paramètres restreints"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Indisponible pendant les appels"</string> <string name="disabled" msgid="8017887509554714950">"Désactivée"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Autorisée"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Non autorisée"</string> <string name="install_other_apps" msgid="3232595082023199454">"Installer les applis inconnues"</string> diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index 07849e09ecc9..4cc8a9a37632 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Contrôlé par les paramètres restreints"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Indisponible pendant les appels"</string> <string name="disabled" msgid="8017887509554714950">"Désactivée"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Autorisé"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Non autorisé"</string> <string name="install_other_apps" msgid="3232595082023199454">"Installation d\'applis inconnues"</string> diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index b6eacfc33293..b7a6abc2dfcd 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Baixo o control de opcións restrinxidas"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Non dispoñible durante as chamadas"</string> <string name="disabled" msgid="8017887509554714950">"Desactivada"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Permiso concedido"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Permiso non concedido"</string> <string name="install_other_apps" msgid="3232595082023199454">"Instalar aplicacións descoñecidas"</string> diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml index 57f898210efd..aa27f2a8a09b 100644 --- a/packages/SettingsLib/res/values-gu/strings.xml +++ b/packages/SettingsLib/res/values-gu/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"પ્રતિબંધિત સેટિંગ દ્વારા નિયંત્રિત"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"કૉલ દરમિયાન અનુપલબ્ધ"</string> <string name="disabled" msgid="8017887509554714950">"બંધ કરી"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"મંજૂરી છે"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"મંજૂરી નથી"</string> <string name="install_other_apps" msgid="3232595082023199454">"અજાણી ઍપ ઇન્સ્ટૉલ કરો"</string> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index 02bc92be8899..7c4d64f32cda 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"इसे पाबंदी मोड वाली सेटिंग से कंट्रोल किया जाता है"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"कॉल के दौरान उपलब्ध नहीं है"</string> <string name="disabled" msgid="8017887509554714950">"बंद किया गया"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"अनुमति है"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"अनुमति नहीं है"</string> <string name="install_other_apps" msgid="3232595082023199454">"अनजान ऐप्लिकेशन इंस्टॉल करने की अनुमति"</string> diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml index 15eb4710cbf8..ba5650f1d7a5 100644 --- a/packages/SettingsLib/res/values-hr/strings.xml +++ b/packages/SettingsLib/res/values-hr/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrolira ograničena postavka"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Nije dostupno tijekom poziva"</string> <string name="disabled" msgid="8017887509554714950">"Onemogućeno"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Dopušteno"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Nije dopušteno"</string> <string name="install_other_apps" msgid="3232595082023199454">"Instalacija nepoznatih aplikacija"</string> diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml index 08ae0f870a9e..faeec8d6ed24 100644 --- a/packages/SettingsLib/res/values-hu/strings.xml +++ b/packages/SettingsLib/res/values-hu/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Korlátozott beállítás vezérli"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Nem áll rendelkezésre hívások közben"</string> <string name="disabled" msgid="8017887509554714950">"Letiltva"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Engedélyezett"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Nem engedélyezett"</string> <string name="install_other_apps" msgid="3232595082023199454">"Ismeretlen alkalmazások telepítése"</string> diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml index 347101354a3b..f2b22679b1bb 100644 --- a/packages/SettingsLib/res/values-hy/strings.xml +++ b/packages/SettingsLib/res/values-hy/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Կառավարվում է սահմանափակ ռեժիմի կարգավորումներով"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Զանգի ընթացքում հասանելի չէ"</string> <string name="disabled" msgid="8017887509554714950">"Կասեցված է"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Թույլատրված է"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Արգելված"</string> <string name="install_other_apps" msgid="3232595082023199454">"Անհայտ հավելվածների տեղադրում"</string> diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml index 85109fcf1677..7af3de0da4fe 100644 --- a/packages/SettingsLib/res/values-in/strings.xml +++ b/packages/SettingsLib/res/values-in/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Dikontrol oleh Setelan Terbatas"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Tidak tersedia selama panggilan berlangsung"</string> <string name="disabled" msgid="8017887509554714950">"Dinonaktifkan"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Diizinkan"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Tidak diizinkan"</string> <string name="install_other_apps" msgid="3232595082023199454">"Instal aplikasi tidak dikenal"</string> diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml index 3041151c617e..e6ef20fcd908 100644 --- a/packages/SettingsLib/res/values-is/strings.xml +++ b/packages/SettingsLib/res/values-is/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Stýrt af takmarkaði stillingu"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Ekki í boði á meðan á símtölum stendur"</string> <string name="disabled" msgid="8017887509554714950">"Óvirkt"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Heimilað"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Ekki heimilað"</string> <string name="install_other_apps" msgid="3232595082023199454">"Setja upp óþekkt forrit"</string> diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml index c42cab36f30d..24e7a4cfe45d 100644 --- a/packages/SettingsLib/res/values-it/strings.xml +++ b/packages/SettingsLib/res/values-it/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Gestita tramite impostazioni con restrizioni"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Non disponibile durante le chiamate"</string> <string name="disabled" msgid="8017887509554714950">"Disattivato"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Autorizzazione concessa"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Autorizzazione non concessa"</string> <string name="install_other_apps" msgid="3232595082023199454">"Installa app sconosciute"</string> diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml index c39521f8776f..82d90430090b 100644 --- a/packages/SettingsLib/res/values-iw/strings.xml +++ b/packages/SettingsLib/res/values-iw/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"בשליטה של הגדרה מוגבלת"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"ההעדפה הזו לא זמינה במהלך שיחות"</string> <string name="disabled" msgid="8017887509554714950">"מושבת"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"מורשה"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"לא מורשה"</string> <string name="install_other_apps" msgid="3232595082023199454">"התקנת אפליקציות לא מוכרות"</string> diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index bb997ff6294d..79438fa1fa2d 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"制限付き設定によって管理されています"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"通話中は利用できません"</string> <string name="disabled" msgid="8017887509554714950">"無効"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"許可"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"許可しない"</string> <string name="install_other_apps" msgid="3232595082023199454">"不明なアプリのインストール"</string> diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml index 91e8889acfa5..ea01938d93d9 100644 --- a/packages/SettingsLib/res/values-ka/strings.xml +++ b/packages/SettingsLib/res/values-ka/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"კონტროლდება შეზღუდული რეჟიმის პარამეტრით"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"მიუწვდომელია ზარების განხორციელებისას"</string> <string name="disabled" msgid="8017887509554714950">"გამორთული"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"დაშვებულია"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"დაუშვებელია"</string> <string name="install_other_apps" msgid="3232595082023199454">"უცნობი აპების ინსტალაცია"</string> diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml index 25c92de40657..16b7c22b6bfe 100644 --- a/packages/SettingsLib/res/values-kk/strings.xml +++ b/packages/SettingsLib/res/values-kk/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Шектелген параметрлер арқылы басқарылады."</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Қоңырау шалу кезінде қолжетімді емес."</string> <string name="disabled" msgid="8017887509554714950">"Өшірілген"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Рұқсат берілген"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Рұқсат етілмеген"</string> <string name="install_other_apps" msgid="3232595082023199454">"Белгісіз қолданбаларды орнату"</string> diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml index 9dadee1d34b3..de93ee94271f 100644 --- a/packages/SettingsLib/res/values-km/strings.xml +++ b/packages/SettingsLib/res/values-km/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"គ្រប់គ្រងដោយការកំណត់ដែលបានរឹតបន្តឹង"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"មិនអាចប្រើបានទេអំឡុងពេលហៅទូរសព្ទ"</string> <string name="disabled" msgid="8017887509554714950">"បិទ"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"បានអនុញ្ញាត"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"មិនបានអនុញ្ញាត"</string> <string name="install_other_apps" msgid="3232595082023199454">"ដំឡើងកម្មវិធីដែលមិនស្គាល់"</string> diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml index 72056bb1ed7d..4c4ea64ea52f 100644 --- a/packages/SettingsLib/res/values-kn/strings.xml +++ b/packages/SettingsLib/res/values-kn/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"ನಿರ್ಬಂಧಿಸಲಾದ ಸೆಟ್ಟಿಂಗ್ ಮೂಲಕ ನಿಯಂತ್ರಿಸಲಾಗುತ್ತದೆ"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"ಕರೆಗಳ ಸಮಯದಲ್ಲಿ ಲಭ್ಯವಿಲ್ಲ"</string> <string name="disabled" msgid="8017887509554714950">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"ಅನುಮತಿಸಲಾಗಿದೆ"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"ಅನುಮತಿ ಇಲ್ಲ"</string> <string name="install_other_apps" msgid="3232595082023199454">"ಅಪರಿಚಿತ ಆ್ಯಪ್ಗಳನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string> diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml index 3b965e54e145..0488543f7790 100644 --- a/packages/SettingsLib/res/values-ko/strings.xml +++ b/packages/SettingsLib/res/values-ko/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"제한된 설정으로 제어됨"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"통화 중에는 사용할 수 없습니다."</string> <string name="disabled" msgid="8017887509554714950">"사용 안함"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"허용됨"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"허용되지 않음"</string> <string name="install_other_apps" msgid="3232595082023199454">"알 수 없는 앱 설치"</string> diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml index 3eee360ed220..b04883747ee7 100644 --- a/packages/SettingsLib/res/values-ky/strings.xml +++ b/packages/SettingsLib/res/values-ky/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Чектелген параметр аркылуу көзөмөлдөнөт"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Сүйлөшүп жаткан учурда жеткиликсиз"</string> <string name="disabled" msgid="8017887509554714950">"Өчүрүлгөн"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Уруксат берилген"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Тыюу салынган"</string> <string name="install_other_apps" msgid="3232595082023199454">"Белгисиз колдонмолорду орнотуу"</string> diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml index 8044cce18edb..f57ed0cea03b 100644 --- a/packages/SettingsLib/res/values-lo/strings.xml +++ b/packages/SettingsLib/res/values-lo/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"ຄວບຄຸມໂດຍການຕັ້ງຄ່າທີ່ຈຳກັດໄວ້"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"ບໍ່ສາມາດໃຊ້ໄດ້ລະຫວ່າງການໂທ"</string> <string name="disabled" msgid="8017887509554714950">"ປິດການນຳໃຊ້"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"ອະນຸຍາດແລ້ວ"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"ບໍ່ອະນຸຍາດ"</string> <string name="install_other_apps" msgid="3232595082023199454">"ຕິດຕັ້ງແອັບທີ່ບໍ່ຮູ້ຈັກ"</string> diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml index aec236a55d41..25b22cae3d0e 100644 --- a/packages/SettingsLib/res/values-lt/strings.xml +++ b/packages/SettingsLib/res/values-lt/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Valdoma pagal apribotą nustatymą"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Nepasiekiama per skambučius"</string> <string name="disabled" msgid="8017887509554714950">"Neleidžiama"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Leidžiama"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Neleidžiama"</string> <string name="install_other_apps" msgid="3232595082023199454">"Nežinomų programų diegimas"</string> diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml index 5716f8f4194c..cdca19b8e0c8 100644 --- a/packages/SettingsLib/res/values-lv/strings.xml +++ b/packages/SettingsLib/res/values-lv/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrolē ierobežots iestatījums"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Ierīce nav pieejama zvanu laikā"</string> <string name="disabled" msgid="8017887509554714950">"Atspējots"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Atļauts"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Nav atļauts"</string> <string name="install_other_apps" msgid="3232595082023199454">"Nezināmu lietotņu instalēšana"</string> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index bc6409da8e12..e51ca04022a7 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Контролирано со ограничени поставки"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Недостапно при повици"</string> <string name="disabled" msgid="8017887509554714950">"Оневозможено"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Со дозвола"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Без дозвола"</string> <string name="install_other_apps" msgid="3232595082023199454">"Инсталирање непознати апликации"</string> diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml index bcadd7d88059..54b6ff8ab524 100644 --- a/packages/SettingsLib/res/values-ml/strings.xml +++ b/packages/SettingsLib/res/values-ml/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"നിയന്ത്രിത ക്രമീകരണം ഉപയോഗിച്ച് നിയന്ത്രിക്കുന്നത്"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"കോളുകൾ ചെയ്യുമ്പോൾ ലഭ്യമല്ല"</string> <string name="disabled" msgid="8017887509554714950">"പ്രവർത്തനരഹിതമാക്കി"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"അനുവദനീയം"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"അനുവദിച്ചിട്ടില്ല"</string> <string name="install_other_apps" msgid="3232595082023199454">"പരിചയമില്ലാത്ത ആപ്പുകൾ ഇൻസ്റ്റാൾ ചെയ്യുക"</string> diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml index 2b45e85a2995..ed42362e5c1e 100644 --- a/packages/SettingsLib/res/values-mn/strings.xml +++ b/packages/SettingsLib/res/values-mn/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Хязгаарлагдсан тохиргоогоор хянадаг"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Дуудлагын үер боломжгүй"</string> <string name="disabled" msgid="8017887509554714950">"Идэвхгүйжүүлсэн"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Зөвшөөрсөн"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Зөвшөөрөөгүй"</string> <string name="install_other_apps" msgid="3232595082023199454">"Тодорхойгүй апп суулгах"</string> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index 8c77b0897aed..6e7cd02b1e61 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"प्रतिबंधित केलेल्या सेटिंग द्वारे नियंत्रित"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"कॉल दरम्यान उपलब्ध नाही"</string> <string name="disabled" msgid="8017887509554714950">"अक्षम"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"अनुमती आहे"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"अनुमती नाही"</string> <string name="install_other_apps" msgid="3232595082023199454">"अज्ञात अॅप्स इंस्टॉल करा"</string> diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml index a2f95628a6a1..58d80385ff87 100644 --- a/packages/SettingsLib/res/values-ms/strings.xml +++ b/packages/SettingsLib/res/values-ms/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Dikawal oleh Tetapan Terhad"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Tidak tersedia semasa panggilan berlangsung"</string> <string name="disabled" msgid="8017887509554714950">"Dilumpuhkan"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Dibenarkan"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Tidak dibenarkan"</string> <string name="install_other_apps" msgid="3232595082023199454">"Pasang apl yang tidak diketahui"</string> diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml index b0d86afe9a6c..ddd127901e18 100644 --- a/packages/SettingsLib/res/values-my/strings.xml +++ b/packages/SettingsLib/res/values-my/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"ကန့်သတ်ဆက်တင်ဖြင့် ထိန်းချုပ်ထားသည်"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"ဖုန်းခေါ်ဆိုနေချိန်တွင် မရနိုင်ပါ"</string> <string name="disabled" msgid="8017887509554714950">"ပိတ်ထားပြီး"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"ခွင့်ပြုထားသည်"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"ခွင့်မပြုပါ"</string> <string name="install_other_apps" msgid="3232595082023199454">"အမည်မသိအက်ပ် ထည့်သွင်းခြင်း"</string> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index 755df5100e5a..c8fc415528b4 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrollert av en begrenset innstilling"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Utilgjengelig under samtaler"</string> <string name="disabled" msgid="8017887509554714950">"Deaktivert"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Tillatt"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Ikke tillatt"</string> <string name="install_other_apps" msgid="3232595082023199454">"Installer ukjente apper"</string> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index 0a9ac1770896..5f09635e19c7 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"प्रतिबन्धित सेटिङले नियन्त्रण गरेको"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"कल चलिरहेका बेला उपलब्ध छैन"</string> <string name="disabled" msgid="8017887509554714950">"असक्षम पारियो"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"अनुमति छ"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"अनुमति छैन"</string> <string name="install_other_apps" msgid="3232595082023199454">"अज्ञात एप इन्स्टल गर्ने अनुमति"</string> diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml index f71f3abfaf2b..78dfdcead634 100644 --- a/packages/SettingsLib/res/values-nl/strings.xml +++ b/packages/SettingsLib/res/values-nl/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Beheerd door beperkte instelling"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Niet beschikbaar tijdens gesprekken"</string> <string name="disabled" msgid="8017887509554714950">"Uitgezet"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Toegestaan"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Niet toegestaan"</string> <string name="install_other_apps" msgid="3232595082023199454">"Onbekende apps installeren"</string> diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml index f30ae3d94d42..d6e26314a0f9 100644 --- a/packages/SettingsLib/res/values-or/strings.xml +++ b/packages/SettingsLib/res/values-or/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"ପ୍ରତିବନ୍ଧିତ ସେଟିଂ ଦ୍ୱାରା ନିୟନ୍ତ୍ରଣ କରାଯାଇଛି"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"କଲ କରିବାବେଳେ ଉପଲବ୍ଧ ନଥାଏ"</string> <string name="disabled" msgid="8017887509554714950">"ଅକ୍ଷମ ହୋଇଛି"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"ଅନୁମତି ଦିଆଯାଇଛି"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"ଅନୁମତି ନାହିଁ"</string> <string name="install_other_apps" msgid="3232595082023199454">"ଅଜଣା ଆପ ଇନଷ୍ଟଲ କରନ୍ତୁ"</string> diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml index 2c2eab2fa871..ab5f4afd07f3 100644 --- a/packages/SettingsLib/res/values-pa/strings.xml +++ b/packages/SettingsLib/res/values-pa/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"ਪ੍ਰਤਿਬੰਧਿਤ ਸੈਟਿੰਗ ਰਾਹੀਂ ਕੰਟਰੋਲ ਕੀਤੀ ਜਾਂਦੀ ਹੈ"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"ਕਾਲਾਂ ਦੌਰਾਨ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string> <string name="disabled" msgid="8017887509554714950">"ਅਯੋਗ ਬਣਾਇਆ"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"ਮਨਜ਼ੂਰਸ਼ੁਦਾ"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"ਗੈਰ-ਮਨਜ਼ੂਰਸ਼ੁਦਾ"</string> <string name="install_other_apps" msgid="3232595082023199454">"ਅਗਿਆਤ ਐਪਾਂ ਦੀ ਸਥਾਪਨਾ"</string> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index aed9b06d5037..462142468e26 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Obowiązują ustawienia z ograniczonym dostępem"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Niedostępne w trakcie połączeń"</string> <string name="disabled" msgid="8017887509554714950">"Wyłączona"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Dozwolone"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Niedozwolone"</string> <string name="install_other_apps" msgid="3232595082023199454">"Instalowanie nieznanych aplikacji"</string> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index e16e3557dc38..482f47931f4a 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlada pelas configurações restritas"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Indisponível durante ligações"</string> <string name="disabled" msgid="8017887509554714950">"Desativado"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Permitido"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Não permitido"</string> <string name="install_other_apps" msgid="3232595082023199454">"Instalar apps desconhecidos"</string> diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml index 11f410f90497..1a9975732513 100644 --- a/packages/SettingsLib/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlado por uma definição restrita"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Indisponível durante as chamadas"</string> <string name="disabled" msgid="8017887509554714950">"Desativada"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Autorizada"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Não autorizada"</string> <string name="install_other_apps" msgid="3232595082023199454">"Instalar apps desconhecidas"</string> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index e16e3557dc38..482f47931f4a 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlada pelas configurações restritas"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Indisponível durante ligações"</string> <string name="disabled" msgid="8017887509554714950">"Desativado"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Permitido"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Não permitido"</string> <string name="install_other_apps" msgid="3232595082023199454">"Instalar apps desconhecidos"</string> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index 83a6e68b36b4..757fee9e110e 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlată de setarea restricționată"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Indisponibil în timpul apelurilor"</string> <string name="disabled" msgid="8017887509554714950">"Dezactivată"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Permise"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Nepermise"</string> <string name="install_other_apps" msgid="3232595082023199454">"Instalarea aplicațiilor necunoscute"</string> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index 1ed7c3623acc..9e922a0b85b3 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Контролируется настройками с ограниченным доступом"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Недоступно во время вызовов"</string> <string name="disabled" msgid="8017887509554714950">"Отключено"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Разрешено"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Запрещено"</string> <string name="install_other_apps" msgid="3232595082023199454">"Установка неизвестных приложений"</string> diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml index dffa392c7947..517b00c61efb 100644 --- a/packages/SettingsLib/res/values-si/strings.xml +++ b/packages/SettingsLib/res/values-si/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"සීමා කළ සැකසීම මගින් පාලනය වේ"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"ඇමතුම් අතරතුර නොපවතී"</string> <string name="disabled" msgid="8017887509554714950">"අබල කර ඇත"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"ඉඩ දුන්"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"ඉඩ නොදෙන"</string> <string name="install_other_apps" msgid="3232595082023199454">"නොදන්නා යෙදුම් ස්ථාපනය"</string> diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml index 0f4297aec6ad..e8fb53fdcef6 100644 --- a/packages/SettingsLib/res/values-sk/strings.xml +++ b/packages/SettingsLib/res/values-sk/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Ovládané obmedzeným nastavením"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Počas hovorov nie je k dispozícii"</string> <string name="disabled" msgid="8017887509554714950">"Deaktivované"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Povolené"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Nie je povolené"</string> <string name="install_other_apps" msgid="3232595082023199454">"Inštalácia neznámych aplikácií"</string> diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml index 744b4da576ed..7d508862bef1 100644 --- a/packages/SettingsLib/res/values-sl/strings.xml +++ b/packages/SettingsLib/res/values-sl/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Pod nadzorom omejene nastavitve"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Ni na voljo med klici"</string> <string name="disabled" msgid="8017887509554714950">"Onemogočeno"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Dovoljene"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Ni dovoljeno"</string> <string name="install_other_apps" msgid="3232595082023199454">"Nameščanje neznanih aplikacij"</string> diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml index 3d9622e063de..8a711d5ebcee 100644 --- a/packages/SettingsLib/res/values-sq/strings.xml +++ b/packages/SettingsLib/res/values-sq/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrollohet nga \"Cilësimet e kufizuara\""</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Nuk ofrohet gjatë telefonatave"</string> <string name="disabled" msgid="8017887509554714950">"Çaktivizuar"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Lejohet"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Nuk lejohet"</string> <string name="install_other_apps" msgid="3232595082023199454">"Instalo aplikacione të panjohura"</string> diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml index 32ec5000bfd0..d57eb5c4c830 100644 --- a/packages/SettingsLib/res/values-sr/strings.xml +++ b/packages/SettingsLib/res/values-sr/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Контролишу ограничена подешавања"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Недоступно током позива"</string> <string name="disabled" msgid="8017887509554714950">"Онемогућено"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Дозвољено"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Није дозвољено"</string> <string name="install_other_apps" msgid="3232595082023199454">"Инсталирање непознатих апликација"</string> diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml index cf223f5b7bdb..5d27839daa6a 100644 --- a/packages/SettingsLib/res/values-sv/strings.xml +++ b/packages/SettingsLib/res/values-sv/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Styrs av spärrad inställning"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Ej tillgänglig under samtal"</string> <string name="disabled" msgid="8017887509554714950">"Inaktiverad"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Tillåts"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Tillåts inte"</string> <string name="install_other_apps" msgid="3232595082023199454">"Installera okända appar"</string> diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml index 26e0412b2893..9ddb7ff129ad 100644 --- a/packages/SettingsLib/res/values-sw/strings.xml +++ b/packages/SettingsLib/res/values-sw/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Imedhibitiwa na Mpangilio wenye Mipaka"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Haipatikani wakati unaongea kwa simu"</string> <string name="disabled" msgid="8017887509554714950">"Imezimwa"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Imeruhusiwa"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Hairuhusiwi"</string> <string name="install_other_apps" msgid="3232595082023199454">"Kuweka programu zisizojulikana"</string> diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml index c2e762f417e7..68a60cf85a90 100644 --- a/packages/SettingsLib/res/values-ta/strings.xml +++ b/packages/SettingsLib/res/values-ta/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"வரையறுக்கப்பட்ட அமைப்பால் கட்டுப்படுத்தப்படுகிறது"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"அழைப்புகளின்போது பயன்படுத்த முடியாது"</string> <string name="disabled" msgid="8017887509554714950">"முடக்கப்பட்டது"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"அனுமதிக்கப்பட்டது"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"அனுமதிக்கப்படவில்லை"</string> <string name="install_other_apps" msgid="3232595082023199454">"தெரியாத ஆப்ஸ்களை நிறுவுதல்"</string> diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml index f4678f3d0dd5..db4f66b955b6 100644 --- a/packages/SettingsLib/res/values-te/strings.xml +++ b/packages/SettingsLib/res/values-te/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"పరిమితం చేసిన సెట్టింగ్ ద్వారా నియంత్రించబడుతుంది"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"కాల్స్ సమయంలో అందుబాటులో ఉండదు"</string> <string name="disabled" msgid="8017887509554714950">"డిజేబుల్ చేయబడింది"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"అనుమతించినవి"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"అనుమతించబడలేదు"</string> <string name="install_other_apps" msgid="3232595082023199454">"తెలియని యాప్ల ఇన్స్టలేషన్"</string> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index e360ae6d5278..035644f845f1 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"ควบคุมโดยการตั้งค่าที่จำกัด"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"ใช้งานไม่ได้ขณะสนทนาโทรศัพท์"</string> <string name="disabled" msgid="8017887509554714950">"ปิดอยู่"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"อนุญาต"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"ไม่อนุญาต"</string> <string name="install_other_apps" msgid="3232595082023199454">"ติดตั้งแอปที่ไม่รู้จัก"</string> diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml index 09f40c761fda..4ef2f436898a 100644 --- a/packages/SettingsLib/res/values-tl/strings.xml +++ b/packages/SettingsLib/res/values-tl/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kinokontrol ng Pinaghihigpitang Setting"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Hindi available habang may tawag"</string> <string name="disabled" msgid="8017887509554714950">"Naka-disable"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Pinapayagan"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Hindi pinapayagan"</string> <string name="install_other_apps" msgid="3232595082023199454">"Mag-install ng di-kilalang app"</string> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index 19b3baf6c82d..19295aa169ef 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kısıtlanmış ayar tarafından kontrol ediliyor"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Telefon aramaları sırasında kullanılamaz"</string> <string name="disabled" msgid="8017887509554714950">"Devre dışı"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"İzin verildi"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"İzin verilmiyor"</string> <string name="install_other_apps" msgid="3232595082023199454">"Bilinmeyen uygulamaları yükleme"</string> diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml index ff18f5cf10a4..e46137fd237e 100644 --- a/packages/SettingsLib/res/values-uk/strings.xml +++ b/packages/SettingsLib/res/values-uk/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Керується налаштуваннями з обмеженнями"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Недоступно під час викликів"</string> <string name="disabled" msgid="8017887509554714950">"Вимкнено"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Дозволено"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Заборонено"</string> <string name="install_other_apps" msgid="3232595082023199454">"Встановлювати невідомі додатки"</string> diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml index a07a341fd956..72da3784aa4d 100644 --- a/packages/SettingsLib/res/values-ur/strings.xml +++ b/packages/SettingsLib/res/values-ur/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"محدود کردہ ترتیب کے زیر انتظام ہے"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"کالز کے دوران غیر دستیاب"</string> <string name="disabled" msgid="8017887509554714950">"غیر فعال"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"اجازت ہے"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"اجازت نہیں ہے"</string> <string name="install_other_apps" msgid="3232595082023199454">"نامعلوم ایپس انسٹال کریں"</string> diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml index 3a10aa801797..795eae45ab92 100644 --- a/packages/SettingsLib/res/values-uz/strings.xml +++ b/packages/SettingsLib/res/values-uz/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Cheklangan sozlama tomonidan boshqariladi"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Chaqiruv vaqtida ishlamaydi"</string> <string name="disabled" msgid="8017887509554714950">"Oʻchiq"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Ruxsat berilgan"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Ruxsat berilmagan"</string> <string name="install_other_apps" msgid="3232595082023199454">"Notanish ilovalarni o‘rnatish"</string> diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml index c2c035c15ce0..8f5c0c2675e4 100644 --- a/packages/SettingsLib/res/values-vi/strings.xml +++ b/packages/SettingsLib/res/values-vi/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Do chế độ Cài đặt hạn chế kiểm soát"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Không dùng được khi có cuộc gọi"</string> <string name="disabled" msgid="8017887509554714950">"Đã tắt"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Được phép"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Không được phép"</string> <string name="install_other_apps" msgid="3232595082023199454">"Cài ứng dụng không rõ nguồn"</string> diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml index 06379e1c254f..85d3c179a623 100644 --- a/packages/SettingsLib/res/values-zh-rCN/strings.xml +++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"由受限设置控制"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"通话期间无法使用"</string> <string name="disabled" msgid="8017887509554714950">"已停用"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"允许"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"不允许"</string> <string name="install_other_apps" msgid="3232595082023199454">"安装未知应用"</string> diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml index a3ae971b07c4..3ff554000a6c 100644 --- a/packages/SettingsLib/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"由「受限設定」控制"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"通話時無法使用"</string> <string name="disabled" msgid="8017887509554714950">"已停用"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"允許"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"不允許"</string> <string name="install_other_apps" msgid="3232595082023199454">"安裝不明的應用程式"</string> diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml index f670088de16b..5362d380564f 100644 --- a/packages/SettingsLib/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"由受限制的設定控管"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"通話時無法使用"</string> <string name="disabled" msgid="8017887509554714950">"已停用"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"允許"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"不允許"</string> <string name="install_other_apps" msgid="3232595082023199454">"安裝不明應用程式"</string> @@ -670,7 +672,7 @@ <string name="add_user_failed" msgid="4809887794313944872">"無法建立新的使用者"</string> <string name="add_guest_failed" msgid="8074548434469843443">"無法建立新訪客"</string> <string name="user_nickname" msgid="262624187455825083">"暱稱"</string> - <string name="edit_user_info_message" msgid="6677556031419002895">"這部裝置的所有使用者都能看到你選擇的名稱和相片。"</string> + <string name="edit_user_info_message" msgid="6677556031419002895">"這部裝置的所有使用者,都能看到你選擇的名稱和相片。"</string> <string name="user_add_user" msgid="7876449291500212468">"新增使用者"</string> <string name="guest_new_guest" msgid="3482026122932643557">"新增訪客"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"移除訪客"</string> diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml index 1d792a0a2864..79ce6d7b25d0 100644 --- a/packages/SettingsLib/res/values-zu/strings.xml +++ b/packages/SettingsLib/res/values-zu/strings.xml @@ -539,6 +539,8 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kulawulwe Isethingi Elikhawulelwe"</string> <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Akutholakali ngesikhathi samakholi"</string> <string name="disabled" msgid="8017887509554714950">"Akusebenzi"</string> + <!-- no translation found for enabled (3997122818554810678) --> + <skip /> <string name="external_source_trusted" msgid="1146522036773132905">"Kuvumelekile"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"Akuvumelekile"</string> <string name="install_other_apps" msgid="3232595082023199454">"Faka ama-app angaziwa"</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/supervision/SupervisionLog.kt b/packages/SettingsLib/src/com/android/settingslib/supervision/SupervisionLog.kt new file mode 100644 index 000000000000..92455c05e3d7 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/supervision/SupervisionLog.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.supervision + +/** Constants used in supervision logs. */ +object SupervisionLog { + const val TAG = "SupervisionSettings" +} diff --git a/packages/SettingsLib/src/com/android/settingslib/supervision/SupervisionRestrictionsHelper.kt b/packages/SettingsLib/src/com/android/settingslib/supervision/SupervisionRestrictionsHelper.kt new file mode 100644 index 000000000000..1be8a17915a1 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/supervision/SupervisionRestrictionsHelper.kt @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.supervision + +import android.app.admin.DeviceAdminReceiver +import android.app.supervision.SupervisionManager +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.os.UserHandle +import android.util.Log +import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin + +/** Helper class for supervision-enforced restrictions. */ +object SupervisionRestrictionsHelper { + + /** + * Creates an instance of [EnforcedAdmin] that uses the correct supervision component or returns + * null if supervision is not enabled. + */ + @JvmStatic + fun createEnforcedAdmin( + context: Context, + restriction: String, + user: UserHandle, + ): EnforcedAdmin? { + val supervisionManager = context.getSystemService(SupervisionManager::class.java) + val supervisionAppPackage = supervisionManager?.activeSupervisionAppPackage ?: return null + var supervisionComponent: ComponentName? = null + + // Try to find the service whose package matches the active supervision app. + val resolveSupervisionApps = + context.packageManager.queryIntentServicesAsUser( + Intent("android.app.action.BIND_SUPERVISION_APP_SERVICE"), + PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, + user.identifier, + ) + resolveSupervisionApps + .mapNotNull { it.serviceInfo?.componentName } + .find { it.packageName == supervisionAppPackage } + ?.let { supervisionComponent = it } + + if (supervisionComponent == null) { + // Try to find the PO receiver whose package matches the active supervision app, for + // backwards compatibility. + val resolveDeviceAdmins = + context.packageManager.queryBroadcastReceiversAsUser( + Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED), + PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, + user.identifier, + ) + resolveDeviceAdmins + .mapNotNull { it.activityInfo?.componentName } + .find { it.packageName == supervisionAppPackage } + ?.let { supervisionComponent = it } + } + + if (supervisionComponent == null) { + Log.d(SupervisionLog.TAG, "Could not find the supervision component.") + } + return EnforcedAdmin(supervisionComponent, restriction, user) + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/users/CreateUserActivity.java b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserActivity.java index c5e6f60e3fa6..2b95fd1cdd9d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/users/CreateUserActivity.java +++ b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserActivity.java @@ -93,18 +93,10 @@ public class CreateUserActivity extends Activity { @Override public boolean onTouchEvent(@Nullable MotionEvent event) { - onBackInvoked(); + cancel(); return super.onTouchEvent(event); } - private void onBackInvoked() { - if (mSetupUserDialog != null) { - mSetupUserDialog.dismiss(); - } - setResult(RESULT_CANCELED); - finish(); - } - @VisibleForTesting void setSuccessResult(String userName, Drawable userIcon, String path, Boolean isAdmin) { Intent intent = new Intent(this, CreateUserActivity.class); @@ -112,14 +104,12 @@ public class CreateUserActivity extends Activity { intent.putExtra(EXTRA_IS_ADMIN, isAdmin); intent.putExtra(EXTRA_USER_ICON_PATH, path); - mSetupUserDialog.dismiss(); setResult(RESULT_OK, intent); finish(); } @VisibleForTesting void cancel() { - mSetupUserDialog.dismiss(); setResult(RESULT_CANCELED); finish(); } diff --git a/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java index d9f1b632323c..bce229f5a13d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java +++ b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java @@ -282,7 +282,7 @@ public class CreateUserDialogController { mCustomDialogHelper.getDialog().dismiss(); break; case EXIT_DIALOG: - finish(); + mUserCreationDialog.dismiss(); break; default: if (mCurrentState < EXIT_DIALOG) { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/supervision/OWNERS b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/supervision/OWNERS new file mode 100644 index 000000000000..04e7058b4384 --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/supervision/OWNERS @@ -0,0 +1 @@ +file:platform/frameworks/base:/core/java/android/app/supervision/OWNERS diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/supervision/SupervisionIntentProviderTest.kt b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/supervision/SupervisionIntentProviderTest.kt index 2ceed2875cb4..83ffa9399dc0 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/supervision/SupervisionIntentProviderTest.kt +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/supervision/SupervisionIntentProviderTest.kt @@ -19,6 +19,7 @@ package com.android.settingslib.supervision import android.app.supervision.SupervisionManager import android.content.Context import android.content.ContextWrapper +import android.content.Intent import android.content.pm.PackageManager import android.content.pm.ResolveInfo import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -77,8 +78,8 @@ class SupervisionIntentProviderTest { fun getSettingsIntent_unresolvedIntent() { `when`(mockSupervisionManager.activeSupervisionAppPackage) .thenReturn(SUPERVISION_APP_PACKAGE) - `when`(mockPackageManager.queryIntentActivitiesAsUser(any(), anyInt(), anyInt())) - .thenReturn(emptyList()) + `when`(mockPackageManager.queryIntentActivitiesAsUser(any<Intent>(), anyInt(), anyInt())) + .thenReturn(emptyList<ResolveInfo>()) val intent = SupervisionIntentProvider.getSettingsIntent(context) @@ -89,7 +90,7 @@ class SupervisionIntentProviderTest { fun getSettingsIntent_resolvedIntent() { `when`(mockSupervisionManager.activeSupervisionAppPackage) .thenReturn(SUPERVISION_APP_PACKAGE) - `when`(mockPackageManager.queryIntentActivitiesAsUser(any(), anyInt(), anyInt())) + `when`(mockPackageManager.queryIntentActivitiesAsUser(any<Intent>(), anyInt(), anyInt())) .thenReturn(listOf(ResolveInfo())) val intent = SupervisionIntentProvider.getSettingsIntent(context) diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/supervision/SupervisionRestrictionsHelperTest.kt b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/supervision/SupervisionRestrictionsHelperTest.kt new file mode 100644 index 000000000000..872fc2a44b3d --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/supervision/SupervisionRestrictionsHelperTest.kt @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.settingslib.supervision + +import android.app.admin.DeviceAdminReceiver +import android.app.supervision.SupervisionManager +import android.content.Context +import android.content.ContextWrapper +import android.content.Intent +import android.content.pm.ActivityInfo +import android.content.pm.PackageManager +import android.content.pm.ResolveInfo +import android.content.pm.ServiceInfo +import android.os.UserHandle +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatcher +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.argThat +import org.mockito.ArgumentMatchers.eq +import org.mockito.Mock +import org.mockito.Mockito.`when` +import org.mockito.junit.MockitoJUnit +import org.mockito.junit.MockitoRule + +/** + * Unit tests for [SupervisionRestrictionsHelper]. + * + * Run with `atest SupervisionRestrictionsHelperTest`. + */ +@RunWith(AndroidJUnit4::class) +class SupervisionRestrictionsHelperTest { + @get:Rule val mocks: MockitoRule = MockitoJUnit.rule() + + @Mock private lateinit var mockPackageManager: PackageManager + + @Mock private lateinit var mockSupervisionManager: SupervisionManager + + private lateinit var context: Context + + @Before + fun setUp() { + context = + object : ContextWrapper(InstrumentationRegistry.getInstrumentation().context) { + override fun getPackageManager() = mockPackageManager + + override fun getSystemService(name: String) = + when (name) { + Context.SUPERVISION_SERVICE -> mockSupervisionManager + else -> super.getSystemService(name) + } + } + } + + @Test + fun createEnforcedAdmin_nullSupervisionPackage() { + `when`(mockSupervisionManager.activeSupervisionAppPackage).thenReturn(null) + + val enforcedAdmin = + SupervisionRestrictionsHelper.createEnforcedAdmin(context, RESTRICTION, USER_HANDLE) + + assertThat(enforcedAdmin).isNull() + } + + @Test + fun createEnforcedAdmin_supervisionAppService() { + val resolveInfo = + ResolveInfo().apply { + serviceInfo = + ServiceInfo().apply { + packageName = SUPERVISION_APP_PACKAGE + name = "service.class" + } + } + + `when`(mockSupervisionManager.activeSupervisionAppPackage) + .thenReturn(SUPERVISION_APP_PACKAGE) + `when`( + mockPackageManager.queryIntentServicesAsUser( + argThat(hasAction("android.app.action.BIND_SUPERVISION_APP_SERVICE")), + anyInt(), + eq(USER_ID), + ) + ) + .thenReturn(listOf(resolveInfo)) + + val enforcedAdmin = + SupervisionRestrictionsHelper.createEnforcedAdmin(context, RESTRICTION, USER_HANDLE) + + assertThat(enforcedAdmin).isNotNull() + assertThat(enforcedAdmin!!.component).isEqualTo(resolveInfo.serviceInfo.componentName) + assertThat(enforcedAdmin.enforcedRestriction).isEqualTo(RESTRICTION) + assertThat(enforcedAdmin.user).isEqualTo(USER_HANDLE) + } + + @Test + fun createEnforcedAdmin_profileOwnerReceiver() { + val resolveInfo = + ResolveInfo().apply { + activityInfo = + ActivityInfo().apply { + packageName = SUPERVISION_APP_PACKAGE + name = "service.class" + } + } + + `when`(mockSupervisionManager.activeSupervisionAppPackage) + .thenReturn(SUPERVISION_APP_PACKAGE) + `when`(mockPackageManager.queryIntentServicesAsUser(any<Intent>(), anyInt(), eq(USER_ID))) + .thenReturn(emptyList<ResolveInfo>()) + `when`( + mockPackageManager.queryBroadcastReceiversAsUser( + argThat(hasAction(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED)), + anyInt(), + eq(USER_ID), + ) + ) + .thenReturn(listOf(resolveInfo)) + + val enforcedAdmin = + SupervisionRestrictionsHelper.createEnforcedAdmin(context, RESTRICTION, USER_HANDLE) + + assertThat(enforcedAdmin).isNotNull() + assertThat(enforcedAdmin!!.component).isEqualTo(resolveInfo.activityInfo.componentName) + assertThat(enforcedAdmin.enforcedRestriction).isEqualTo(RESTRICTION) + assertThat(enforcedAdmin.user).isEqualTo(USER_HANDLE) + } + + @Test + fun createEnforcedAdmin_noSupervisionComponent() { + `when`(mockSupervisionManager.activeSupervisionAppPackage) + .thenReturn(SUPERVISION_APP_PACKAGE) + `when`(mockPackageManager.queryIntentServicesAsUser(any<Intent>(), anyInt(), anyInt())) + .thenReturn(emptyList<ResolveInfo>()) + `when`(mockPackageManager.queryBroadcastReceiversAsUser(any<Intent>(), anyInt(), anyInt())) + .thenReturn(emptyList<ResolveInfo>()) + + val enforcedAdmin = + SupervisionRestrictionsHelper.createEnforcedAdmin(context, RESTRICTION, USER_HANDLE) + + assertThat(enforcedAdmin).isNotNull() + assertThat(enforcedAdmin!!.component).isNull() + assertThat(enforcedAdmin.enforcedRestriction).isEqualTo(RESTRICTION) + assertThat(enforcedAdmin.user).isEqualTo(USER_HANDLE) + } + + private fun hasAction(action: String) = + object : ArgumentMatcher<Intent> { + override fun matches(intent: Intent?) = intent?.action == action + } + + private companion object { + const val SUPERVISION_APP_PACKAGE = "app.supervision" + const val RESTRICTION = "restriction" + val USER_HANDLE = UserHandle.CURRENT + val USER_ID = USER_HANDLE.identifier + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserActivityTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserActivityTest.java index f58eb7cc2e31..220c03e53be2 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserActivityTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserActivityTest.java @@ -65,23 +65,23 @@ public class CreateUserActivityTest { } @Test - public void onTouchEvent_dismissesDialogAndCancelsResult() { + public void onTouchEvent_finishesActivityAndCancelsResult() { mCreateUserActivity.onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0)); - assertThat(mCreateUserActivity.mSetupUserDialog.isShowing()).isFalse(); + assertThat(mCreateUserActivity.isFinishing()).isTrue(); assertThat(shadowOf(mCreateUserActivity).getResultCode()) .isEqualTo(Activity.RESULT_CANCELED); } @Test - public void setSuccessResult_dismissesDialogAndSetsSuccessResult() { + public void setSuccessResult_finishesActivityAndSetsSuccessResult() { Drawable mockDrawable = mock(Drawable.class); mCreateUserActivity.setSuccessResult(TEST_USER_NAME, mockDrawable, TEST_USER_ICON_PATH, TEST_IS_ADMIN); - assertThat(mCreateUserActivity.mSetupUserDialog.isShowing()).isFalse(); + assertThat(mCreateUserActivity.isFinishing()).isTrue(); assertThat(shadowOf(mCreateUserActivity).getResultCode()).isEqualTo(Activity.RESULT_OK); Intent resultIntent = shadowOf(mCreateUserActivity).getResultIntent(); @@ -92,10 +92,10 @@ public class CreateUserActivityTest { } @Test - public void cancel_dismissesDialogAndSetsCancelResult() { + public void cancel_finishesActivityAndSetsCancelResult() { mCreateUserActivity.cancel(); - assertThat(mCreateUserActivity.mSetupUserDialog.isShowing()).isFalse(); + assertThat(mCreateUserActivity.isFinishing()).isTrue(); assertThat(shadowOf(mCreateUserActivity).getResultCode()) .isEqualTo(Activity.RESULT_CANCELED); } diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 72ae76a45cac..f628a420d8fa 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -312,6 +312,9 @@ <!-- Permission necessary to change car audio volume through CarAudioManager --> <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME" /> + <!-- To detect when projecting to Android Auto --> + <uses-permission android:name="android.permission.READ_PROJECTION_STATE" /> + <!-- Permission to control Android Debug Bridge (ADB) --> <uses-permission android:name="android.permission.MANAGE_DEBUGGING" /> diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index 3c86f28cccb3..ab18612355f0 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -1401,6 +1401,16 @@ flag { } flag { + name: "media_controls_device_manager_background_execution" + namespace: "systemui" + description: "Sends some instances creation to background thread" + bug: "400200474" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "output_switcher_redesign" namespace: "systemui" description: "Enables visual update for Media Output Switcher" @@ -1836,6 +1846,16 @@ flag { } flag { + name: "disable_blurred_shade_visible" + namespace: "systemui" + description: "Removes the check for a blur radius when determining shade window visibility" + bug: "394977231" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "notification_shade_blur" namespace: "systemui" description: "Enables the new blur effect on the Notification Shade." diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt index e43b8a0b9297..7ee6a6e5ebf4 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt @@ -107,6 +107,16 @@ constructor( */ // TODO(b/301385865): Remove this flag. private val disableWmTimeout: Boolean = false, + + /** + * Whether we should disable the reparent transaction that puts the opening/closing window above + * the view's window. This should be set to true in tests only, where we can't currently use a + * valid leash. + * + * TODO(b/397180418): Remove this flag when we don't have the RemoteAnimation wrapper anymore + * and we can just inject a fake transaction. + */ + private val skipReparentTransaction: Boolean = false, ) { @JvmOverloads constructor( @@ -1140,6 +1150,7 @@ constructor( DelegatingAnimationCompletionListener(listener, this::dispose), transitionAnimator, disableWmTimeout, + skipReparentTransaction, ) } @@ -1173,6 +1184,16 @@ constructor( */ // TODO(b/301385865): Remove this flag. disableWmTimeout: Boolean = false, + + /** + * Whether we should disable the reparent transaction that puts the opening/closing window + * above the view's window. This should be set to true in tests only, where we can't + * currently use a valid leash. + * + * TODO(b/397180418): Remove this flag when we don't have the RemoteAnimation wrapper + * anymore and we can just inject a fake transaction. + */ + private val skipReparentTransaction: Boolean = false, ) : RemoteAnimationDelegate<IRemoteAnimationFinishedCallback> { private val transitionContainer = controller.transitionContainer private val context = transitionContainer.context @@ -1515,7 +1536,7 @@ constructor( ) } - if (moveTransitionAnimationLayer()) { + if (moveTransitionAnimationLayer() && !skipReparentTransaction) { // Ensure that the launching window is rendered above the view's window, // so it is not obstructed. // TODO(b/397180418): re-use the start transaction once the diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/FontVariationUtils.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/FontVariationUtils.kt index 9a746870c6ff..e07d7b337ba2 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/FontVariationUtils.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/FontVariationUtils.kt @@ -16,17 +16,18 @@ package com.android.systemui.animation +import kotlin.text.buildString + class FontVariationUtils { private var mWeight = -1 private var mWidth = -1 private var mOpticalSize = -1 private var mRoundness = -1 - private var isUpdated = false + private var mCurrentFVar = "" /* * generate fontVariationSettings string, used for key in typefaceCache in TextAnimator * the order of axes should align to the order of parameters - * if every axis remains unchanged, return "" */ fun updateFontVariation( weight: Int = -1, @@ -34,15 +35,17 @@ class FontVariationUtils { opticalSize: Int = -1, roundness: Int = -1, ): String { - isUpdated = false + var isUpdated = false if (weight >= 0 && mWeight != weight) { isUpdated = true mWeight = weight } + if (width >= 0 && mWidth != width) { isUpdated = true mWidth = width } + if (opticalSize >= 0 && mOpticalSize != opticalSize) { isUpdated = true mOpticalSize = opticalSize @@ -52,23 +55,32 @@ class FontVariationUtils { isUpdated = true mRoundness = roundness } - var resultString = "" - if (mWeight >= 0) { - resultString += "'${GSFAxes.WEIGHT.tag}' $mWeight" - } - if (mWidth >= 0) { - resultString += - (if (resultString.isBlank()) "" else ", ") + "'${GSFAxes.WIDTH.tag}' $mWidth" - } - if (mOpticalSize >= 0) { - resultString += - (if (resultString.isBlank()) "" else ", ") + - "'${GSFAxes.OPTICAL_SIZE.tag}' $mOpticalSize" - } - if (mRoundness >= 0) { - resultString += - (if (resultString.isBlank()) "" else ", ") + "'${GSFAxes.ROUND.tag}' $mRoundness" + + if (!isUpdated) { + return mCurrentFVar } - return if (isUpdated) resultString else "" + + return buildString { + if (mWeight >= 0) { + if (!isBlank()) append(", ") + append("'${GSFAxes.WEIGHT.tag}' $mWeight") + } + + if (mWidth >= 0) { + if (!isBlank()) append(", ") + append("'${GSFAxes.WIDTH.tag}' $mWidth") + } + + if (mOpticalSize >= 0) { + if (!isBlank()) append(", ") + append("'${GSFAxes.OPTICAL_SIZE.tag}' $mOpticalSize") + } + + if (mRoundness >= 0) { + if (!isBlank()) append(", ") + append("'${GSFAxes.ROUND.tag}' $mRoundness") + } + } + .also { mCurrentFVar = it } } } diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt index 5d9c441db003..a4a96d19e8bb 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt @@ -1006,13 +1006,32 @@ class TransitionAnimator( Log.d(TAG, "Animation ended") } - // TODO(b/330672236): Post this to the main thread instead so that it does not - // flicker with Flexiglass enabled. - controller.onTransitionAnimationEnd(isExpandingFullyAbove) - transitionContainerOverlay.remove(windowBackgroundLayer) + val onEnd = { + controller.onTransitionAnimationEnd(isExpandingFullyAbove) + transitionContainerOverlay.remove(windowBackgroundLayer) - if (moveBackgroundLayerWhenAppVisibilityChanges && controller.isLaunching) { - openingWindowSyncViewOverlay?.remove(windowBackgroundLayer) + if (moveBackgroundLayerWhenAppVisibilityChanges && controller.isLaunching) { + openingWindowSyncViewOverlay?.remove(windowBackgroundLayer) + } + } + // TODO(b/330672236): Post this to the main thread for launches as well, so that they do not + // flicker with Flexiglass enabled. + if (controller.isLaunching) { + onEnd() + } else { + // onAnimationEnd is called at the end of the animation, on a Choreographer animation + // tick. During dialog launches, the following calls will move the animated content from + // the dialog overlay back to its original position, and this change must be reflected + // in the next frame given that we then sync the next frame of both the content and + // dialog ViewRoots. During SysUI activity launches, we will instantly collapse the + // shade at the end of the transition. However, if those are rendered by Compose, whose + // compositions are also scheduled on a Choreographer frame, any state change made + // *right now* won't be reflected in the next frame given that a Choreographer frame + // can't schedule another and have it happen in the same frame. So we post the forwarded + // calls to [Controller.onLaunchAnimationEnd] in the main executor, leaving this + // Choreographer frame, ensuring that any state change applied by + // onTransitionAnimationEnd() will be reflected in the same frame. + mainExecutor.execute { onEnd() } } } diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/RunBlockingDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/RunBlockingDetector.kt new file mode 100644 index 000000000000..fce536a60b84 --- /dev/null +++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/RunBlockingDetector.kt @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2025 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.systemui.lint + +import com.android.tools.lint.client.api.UElementHandler +import com.android.tools.lint.detector.api.Category +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Implementation +import com.android.tools.lint.detector.api.Issue +import com.android.tools.lint.detector.api.JavaContext +import com.android.tools.lint.detector.api.Scope +import com.android.tools.lint.detector.api.Severity +import com.android.tools.lint.detector.api.SourceCodeScanner +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UFile +import org.jetbrains.uast.UImportStatement + +/** Detects whether [runBlocking] is being imported. */ +class RunBlockingDetector : Detector(), SourceCodeScanner { + + override fun getApplicableUastTypes(): List<Class<out UElement>> { + return listOf(UFile::class.java) + } + + override fun createUastHandler(context: JavaContext): UElementHandler { + return object : UElementHandler() { + override fun visitFile(node: UFile) { + for (importStatement in node.imports) { + visitImportStatement(context, importStatement) + } + } + } + } + + private fun visitImportStatement(context: JavaContext, importStatement: UImportStatement) { + val importName = importStatement.importReference?.asSourceString() + if (FORBIDDEN_IMPORTS.contains(importName)) { + context.report( + ISSUE, + importStatement as UElement, + context.getLocation(importStatement), + "Importing $importName is not allowed.", + ) + } + } + + companion object { + @JvmField + val ISSUE = + Issue.create( + id = "RunBlockingUsage", + briefDescription = "Discouraged runBlocking call", + explanation = + """ + Using `runBlocking` is generally discouraged in Android + development as it can lead to UI freezes and ANRs. + Consider using `launch` or `async` with coroutine scope + instead. If needed from java, consider introducing a method + with a callback instead from kotlin. + """, + category = Category.PERFORMANCE, + priority = 8, + severity = Severity.WARNING, + implementation = + Implementation(RunBlockingDetector::class.java, Scope.JAVA_FILE_SCOPE), + ) + + val FORBIDDEN_IMPORTS = listOf("kotlinx.coroutines.runBlocking") + } +} diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt index adb311610587..b455c0021517 100644 --- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt +++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt @@ -50,6 +50,7 @@ class SystemUIIssueRegistry : IssueRegistry() { ShadeDisplayAwareDialogDetector.ISSUE, RegisterContentObserverSyncViaSettingsProxyDetector.SYNC_WARNING, RegisterContentObserverViaContentResolverDetector.CONTENT_RESOLVER_ERROR, + RunBlockingDetector.ISSUE, ) override val api: Int diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/RunBlockingDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/RunBlockingDetectorTest.kt new file mode 100644 index 000000000000..4ae429d204aa --- /dev/null +++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/RunBlockingDetectorTest.kt @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2025 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.systemui.lint + +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Issue +import org.junit.Test + +class RunBlockingDetectorTest : SystemUILintDetectorTest() { + + override fun getDetector(): Detector = RunBlockingDetector() + + override fun getIssues(): List<Issue> = listOf(RunBlockingDetector.ISSUE) + + @Test + fun testViolation() { + lint() + .files( + kotlin( + """ + package com.example + + import kotlinx.coroutines.runBlocking + + class MyClass { + fun myMethod() { + runBlocking { + // Some code here + } + } + } + """ + ), + RUN_BLOCKING_DEFINITION, + ) + .issues(RunBlockingDetector.ISSUE) + .run() + .expect( + """ +src/com/example/MyClass.kt:4: Warning: Importing kotlinx.coroutines.runBlocking is not allowed. [RunBlockingUsage] + import kotlinx.coroutines.runBlocking + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +0 errors, 1 warnings +""" + .trimIndent() + ) + } + + // Verifies that the lint check does *not* flag calls to other methods. + @Test + fun testNotViolation() { + lint() + .detector(RunBlockingDetector()) + .issues(RunBlockingDetector.ISSUE) + .files( + kotlin( + """ + package com.example + + class MyClass { + fun myMethod() { + myOtherMethod { + } + } + + fun myOtherMethod(block: () -> Unit) { + block() + } + } + """ + ) + ) + .run() + .expectClean() + } + + private companion object { + val RUN_BLOCKING_DEFINITION = + kotlin( + """ + package kotlinx.coroutines + + fun runBlocking(block: suspend () -> Unit) { + // Implementation details don't matter for this test. + } + """ + ) + } +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt index 8ad96a5bcb37..62b134279267 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt @@ -77,6 +77,16 @@ internal constructor( list.apply { add(toIndex, removeAt(fromIndex)) } } + /** Swap the two items in the list with the given indices. */ + fun swapItems(index1: Int, index2: Int) { + list.apply { + val item1 = get(index1) + val item2 = get(index2) + set(index2, item1) + set(index1, item2) + } + } + /** Remove widget from the list and the database. */ fun onRemove(indexToRemove: Int) { if (list[indexToRemove].isWidgetContent()) { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/DragAndDropTargetState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/DragAndDropTargetState.kt index 0aef7f2c7063..dda388aeeac6 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/DragAndDropTargetState.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/DragAndDropTargetState.kt @@ -18,8 +18,10 @@ package com.android.systemui.communal.ui.compose import android.content.ClipDescription import android.view.DragEvent +import androidx.compose.animation.core.tween import androidx.compose.foundation.draganddrop.dragAndDropTarget import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.animateScrollBy import androidx.compose.foundation.gestures.scrollBy import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.runtime.Composable @@ -37,6 +39,7 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.dp import com.android.systemui.Flags.communalWidgetResizing +import com.android.systemui.Flags.glanceableHubV2 import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.ui.compose.extensions.firstItemAtOffset import com.android.systemui.communal.util.WidgetPickerIntentUtils @@ -51,13 +54,14 @@ import kotlinx.coroutines.launch * @see dragAndDropTarget */ @Composable -internal fun rememberDragAndDropTargetState( +fun rememberDragAndDropTargetState( gridState: LazyGridState, contentOffset: Offset, contentListState: ContentListState, ): DragAndDropTargetState { val scope = rememberCoroutineScope() val autoScrollThreshold = with(LocalDensity.current) { 60.dp.toPx() } + val state = remember(gridState, contentOffset, contentListState, autoScrollThreshold, scope) { DragAndDropTargetState( @@ -68,11 +72,9 @@ internal fun rememberDragAndDropTargetState( scope = scope, ) } - LaunchedEffect(state) { - for (diff in state.scrollChannel) { - gridState.scrollBy(diff) - } - } + + LaunchedEffect(state) { state.processScrollRequests(scope) } + return state } @@ -83,7 +85,7 @@ internal fun rememberDragAndDropTargetState( * @see DragEvent */ @Composable -internal fun Modifier.dragAndDropTarget(dragDropTargetState: DragAndDropTargetState): Modifier { +fun Modifier.dragAndDropTarget(dragDropTargetState: DragAndDropTargetState): Modifier { val state by rememberUpdatedState(dragDropTargetState) return this then @@ -132,13 +134,79 @@ internal fun Modifier.dragAndDropTarget(dragDropTargetState: DragAndDropTargetSt * other activities. [GridDragDropState] on the other hand, handles dragging of existing items in * the communal hub grid. */ -internal class DragAndDropTargetState( +class DragAndDropTargetState( + state: LazyGridState, + contentOffset: Offset, + contentListState: ContentListState, + autoScrollThreshold: Float, + scope: CoroutineScope, +) { + private val dragDropState: DragAndDropTargetStateInternal = + if (glanceableHubV2()) { + DragAndDropTargetStateV2( + state = state, + contentListState = contentListState, + scope = scope, + autoScrollThreshold = autoScrollThreshold, + contentOffset = contentOffset, + ) + } else { + DragAndDropTargetStateV1( + state = state, + contentListState = contentListState, + scope = scope, + autoScrollThreshold = autoScrollThreshold, + contentOffset = contentOffset, + ) + } + + fun onStarted() = dragDropState.onStarted() + + fun onMoved(event: DragAndDropEvent) = dragDropState.onMoved(event) + + fun onDrop(event: DragAndDropEvent) = dragDropState.onDrop(event) + + fun onEnded() = dragDropState.onEnded() + + fun onExited() = dragDropState.onExited() + + suspend fun processScrollRequests(coroutineScope: CoroutineScope) = + dragDropState.processScrollRequests(coroutineScope) +} + +/** + * A private interface defining the API for handling drag-and-drop operations. There will be two + * implementations of this interface: V1 for devices that do not have the glanceable_hub_v2 flag + * enabled, and V2 for devices that do have that flag enabled. + * + * TODO(b/400789179): Remove this interface and the V1 implementation once glanceable_hub_v2 has + * shipped. + */ +private interface DragAndDropTargetStateInternal { + fun onStarted() = Unit + + fun onMoved(event: DragAndDropEvent) = Unit + + fun onDrop(event: DragAndDropEvent): Boolean = false + + fun onEnded() = Unit + + fun onExited() = Unit + + suspend fun processScrollRequests(coroutineScope: CoroutineScope) = Unit +} + +/** + * The V1 implementation of DragAndDropTargetStateInternal to be used when the glanceable_hub_v2 + * flag is disabled. + */ +private class DragAndDropTargetStateV1( private val state: LazyGridState, private val contentOffset: Offset, private val contentListState: ContentListState, private val autoScrollThreshold: Float, private val scope: CoroutineScope, -) { +) : DragAndDropTargetStateInternal { /** * The placeholder item that is treated as if it is being dragged across the grid. It is added * to grid once drag and drop event is started and removed when event ends. @@ -147,15 +215,21 @@ internal class DragAndDropTargetState( private var placeHolderIndex: Int? = null private var previousTargetItemKey: Any? = null - internal val scrollChannel = Channel<Float>() + private val scrollChannel = Channel<Float>() - fun onStarted() { + override suspend fun processScrollRequests(coroutineScope: CoroutineScope) { + for (diff in scrollChannel) { + state.scrollBy(diff) + } + } + + override fun onStarted() { // assume item will be added to the end. contentListState.list.add(placeHolder) placeHolderIndex = contentListState.list.size - 1 } - fun onMoved(event: DragAndDropEvent) { + override fun onMoved(event: DragAndDropEvent) { val dragOffset = event.toOffset() val targetItem = @@ -201,7 +275,7 @@ internal class DragAndDropTargetState( } } - fun onDrop(event: DragAndDropEvent): Boolean { + override fun onDrop(event: DragAndDropEvent): Boolean { return placeHolderIndex?.let { dropIndex -> val widgetExtra = event.maybeWidgetExtra() ?: return false val (componentName, user) = widgetExtra @@ -219,13 +293,13 @@ internal class DragAndDropTargetState( } ?: false } - fun onEnded() { + override fun onEnded() { placeHolderIndex = null previousTargetItemKey = null contentListState.list.remove(placeHolder) } - fun onExited() { + override fun onExited() { onEnded() } @@ -257,16 +331,186 @@ internal class DragAndDropTargetState( contentListState.onMove(currentIndex, index) } } +} +/** + * The V2 implementation of DragAndDropTargetStateInternal to be used when the glanceable_hub_v2 + * flag is enabled. + */ +private class DragAndDropTargetStateV2( + private val state: LazyGridState, + private val contentOffset: Offset, + private val contentListState: ContentListState, + private val autoScrollThreshold: Float, + private val scope: CoroutineScope, +) : DragAndDropTargetStateInternal { /** - * Parses and returns the intent extra associated with the widget that is dropped into the grid. - * - * Returns null if the drop event didn't include intent information. + * The placeholder item that is treated as if it is being dragged across the grid. It is added + * to grid once drag and drop event is started and removed when event ends. */ - private fun DragAndDropEvent.maybeWidgetExtra(): WidgetPickerIntentUtils.WidgetExtra? { - val clipData = this.toAndroidDragEvent().clipData.takeIf { it.itemCount != 0 } - return clipData?.getItemAt(0)?.intent?.let { intent -> getWidgetExtraFromIntent(intent) } + private var placeHolder = CommunalContentModel.WidgetPlaceholder() + private var placeHolderIndex: Int? = null + private var previousTargetItemKey: Any? = null + private var dragOffset = Offset.Zero + private var columnWidth = 0 + + private val scrollChannel = Channel<Float>() + + override suspend fun processScrollRequests(coroutineScope: CoroutineScope) { + while (true) { + val amount = scrollChannel.receive() + + if (state.isScrollInProgress) { + // Ignore overscrolling if a scroll is already in progress (but we still want to + // consume the scroll event so that we don't end up processing a bunch of old + // events after scrolling has finished). + continue + } + + // Perform the rest of the drag operation after scrolling has finished (or immediately + // if there will be no scrolling). + if (amount != 0f) { + scope.launch { + state.animateScrollBy(amount, tween(delayMillis = 250, durationMillis = 1000)) + performDragAction() + } + } else { + performDragAction() + } + } + } + + override fun onStarted() { + // assume item will be added to the end. + contentListState.list.add(placeHolder) + placeHolderIndex = contentListState.list.size - 1 + + // Use the width of the first item as the column width. + columnWidth = + state.layoutInfo.visibleItemsInfo.first().size.width + + state.layoutInfo.beforeContentPadding + + state.layoutInfo.afterContentPadding } - private fun DragAndDropEvent.toOffset() = this.toAndroidDragEvent().run { Offset(x, y) } + override fun onMoved(event: DragAndDropEvent) { + dragOffset = event.toOffset() + scrollChannel.trySend(computeAutoscroll(dragOffset)) + } + + override fun onDrop(event: DragAndDropEvent): Boolean { + return placeHolderIndex?.let { dropIndex -> + val widgetExtra = event.maybeWidgetExtra() ?: return false + val (componentName, user) = widgetExtra + if (componentName != null && user != null) { + // Placeholder isn't removed yet to allow the setting the right rank for items + // before adding in the new item. + contentListState.onSaveList( + newItemComponentName = componentName, + newItemUser = user, + newItemIndex = dropIndex, + ) + return@let true + } + return false + } ?: false + } + + override fun onEnded() { + placeHolderIndex = null + previousTargetItemKey = null + contentListState.list.remove(placeHolder) + } + + override fun onExited() { + onEnded() + } + + private fun performDragAction() { + val targetItem = + state.layoutInfo.visibleItemsInfo + .asSequence() + .filter { item -> contentListState.isItemEditable(item.index) } + .firstItemAtOffset(dragOffset - contentOffset) + + if ( + targetItem != null && + (!communalWidgetResizing() || targetItem.key != previousTargetItemKey) + ) { + if (communalWidgetResizing()) { + // Keep track of the previous target item, to avoid rapidly oscillating between + // items if the target item doesn't visually move as a result of the index change. + // In this case, even after the index changes, we'd still be colliding with the + // element, so it would be selected as the target item the next time this function + // runs again, which would trigger us to revert the index change we recently made. + previousTargetItemKey = targetItem.key + } + + val scrollToIndex = + if (targetItem.index == state.firstVisibleItemIndex) { + placeHolderIndex + } else if (placeHolderIndex == state.firstVisibleItemIndex) { + targetItem.index + } else { + null + } + + if (scrollToIndex != null) { + scope.launch { + state.scrollToItem(scrollToIndex, state.firstVisibleItemScrollOffset) + movePlaceholderTo(targetItem.index) + } + } else { + movePlaceholderTo(targetItem.index) + } + + placeHolderIndex = targetItem.index + } else if (targetItem == null) { + previousTargetItemKey = null + } + } + + private fun computeAutoscroll(dragOffset: Offset): Float { + val orientation = state.layoutInfo.orientation + val distanceFromStart = + if (orientation == Orientation.Horizontal) { + dragOffset.x + } else { + dragOffset.y + } + val distanceFromEnd = + if (orientation == Orientation.Horizontal) { + state.layoutInfo.viewportEndOffset - dragOffset.x + } else { + state.layoutInfo.viewportEndOffset - dragOffset.y + } + + return when { + distanceFromEnd < autoScrollThreshold -> { + (columnWidth - state.layoutInfo.beforeContentPadding).toFloat() + } + distanceFromStart < autoScrollThreshold -> { + -(columnWidth - state.layoutInfo.afterContentPadding).toFloat() + } + else -> 0f + } + } + + private fun movePlaceholderTo(index: Int) { + val currentIndex = contentListState.list.indexOf(placeHolder) + if (currentIndex != index) { + contentListState.swapItems(currentIndex, index) + } + } } + +/** + * Parses and returns the intent extra associated with the widget that is dropped into the grid. + * + * Returns null if the drop event didn't include intent information. + */ +private fun DragAndDropEvent.maybeWidgetExtra(): WidgetPickerIntentUtils.WidgetExtra? { + val clipData = this.toAndroidDragEvent().clipData.takeIf { it.itemCount != 0 } + return clipData?.getItemAt(0)?.intent?.let { intent -> getWidgetExtraFromIntent(intent) } +} + +private fun DragAndDropEvent.toOffset() = this.toAndroidDragEvent().run { Offset(x, y) } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt index c972d3e3cf15..2a5addeb4951 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt @@ -19,7 +19,10 @@ package com.android.systemui.communal.ui.compose import androidx.compose.animation.core.Spring import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.spring +import androidx.compose.animation.core.tween import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.animateScrollBy import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress import androidx.compose.foundation.gestures.scrollBy import androidx.compose.foundation.layout.Box @@ -37,13 +40,16 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.IntRect import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.round import androidx.compose.ui.unit.toOffset import androidx.compose.ui.unit.toSize import com.android.systemui.Flags.communalWidgetResizing +import com.android.systemui.Flags.glanceableHubV2 import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.ui.compose.extensions.firstItemAtOffset @@ -62,22 +68,22 @@ fun rememberGridDragDropState( contentListState: ContentListState, updateDragPositionForRemove: (boundingBox: IntRect) -> Boolean, ): GridDragDropState { - val scope = rememberCoroutineScope() + val coroutineScope = rememberCoroutineScope() + val autoScrollThreshold = with(LocalDensity.current) { 60.dp.toPx() } + val state = remember(gridState, contentListState, updateDragPositionForRemove) { GridDragDropState( - state = gridState, + gridState = gridState, contentListState = contentListState, - scope = scope, + coroutineScope = coroutineScope, + autoScrollThreshold = autoScrollThreshold, updateDragPositionForRemove = updateDragPositionForRemove, ) } - LaunchedEffect(state) { - while (true) { - val diff = state.scrollChannel.receive() - gridState.scrollBy(diff) - } - } + + LaunchedEffect(state) { state.processScrollRequests(coroutineScope) } + return state } @@ -89,36 +95,86 @@ fun rememberGridDragDropState( * to remove the dragged item if condition met and call [ContentListState.onSaveList] to persist any * change in ordering. */ -class GridDragDropState -internal constructor( - private val state: LazyGridState, - private val contentListState: ContentListState, - private val scope: CoroutineScope, +class GridDragDropState( + val gridState: LazyGridState, + contentListState: ContentListState, + coroutineScope: CoroutineScope, + autoScrollThreshold: Float, private val updateDragPositionForRemove: (draggingBoundingBox: IntRect) -> Boolean, ) { - var draggingItemKey by mutableStateOf<String?>(null) - private set + private val dragDropState: GridDragDropStateInternal = + if (glanceableHubV2()) { + GridDragDropStateV2( + gridState = gridState, + contentListState = contentListState, + scope = coroutineScope, + autoScrollThreshold = autoScrollThreshold, + updateDragPositionForRemove = updateDragPositionForRemove, + ) + } else { + GridDragDropStateV1( + gridState = gridState, + contentListState = contentListState, + scope = coroutineScope, + updateDragPositionForRemove = updateDragPositionForRemove, + ) + } - var isDraggingToRemove by mutableStateOf(false) - private set + val draggingItemKey: String? + get() = dragDropState.draggingItemKey - internal val scrollChannel = Channel<Float>() + val isDraggingToRemove: Boolean + get() = dragDropState.isDraggingToRemove - private var draggingItemDraggedDelta by mutableStateOf(Offset.Zero) - private var draggingItemInitialOffset by mutableStateOf(Offset.Zero) + val draggingItemOffset: Offset + get() = dragDropState.draggingItemOffset - private val spacer = CommunalContentModel.Spacer(CommunalContentSize.Responsive(1)) - private var spacerIndex: Int? = null + /** + * Called when dragging is initiated. + * + * @return {@code True} if dragging a grid item, {@code False} otherwise. + */ + fun onDragStart( + offset: Offset, + screenWidth: Int, + layoutDirection: LayoutDirection, + contentOffset: Offset, + ): Boolean = dragDropState.onDragStart(offset, screenWidth, layoutDirection, contentOffset) - private var previousTargetItemKey: Any? = null + fun onDragInterrupted() = dragDropState.onDragInterrupted() + + fun onDrag(offset: Offset, layoutDirection: LayoutDirection) = + dragDropState.onDrag(offset, layoutDirection) + + suspend fun processScrollRequests(coroutineScope: CoroutineScope) = + dragDropState.processScrollRequests(coroutineScope) +} + +/** + * A private base class defining the API for handling drag-and-drop operations. There will be two + * implementations of this class: V1 for devices that do not have the glanceable_hub_v2 flag + * enabled, and V2 for devices that do have that flag enabled. + * + * TODO(b/400789179): Remove this class and the V1 implementation once glanceable_hub_v2 has + * shipped. + */ +private open class GridDragDropStateInternal(protected val state: LazyGridState) { + var draggingItemKey by mutableStateOf<String?>(null) + protected set - internal val draggingItemOffset: Offset + var isDraggingToRemove by mutableStateOf(false) + protected set + + var draggingItemDraggedDelta by mutableStateOf(Offset.Zero) + var draggingItemInitialOffset by mutableStateOf(Offset.Zero) + + val draggingItemOffset: Offset get() = draggingItemLayoutInfo?.let { item -> draggingItemInitialOffset + draggingItemDraggedDelta - item.offset.toOffset() } ?: Offset.Zero - private val draggingItemLayoutInfo: LazyGridItemInfo? + val draggingItemLayoutInfo: LazyGridItemInfo? get() = state.layoutInfo.visibleItemsInfo.firstOrNull { it.key == draggingItemKey } /** @@ -126,7 +182,45 @@ internal constructor( * * @return {@code True} if dragging a grid item, {@code False} otherwise. */ - internal fun onDragStart( + open fun onDragStart( + offset: Offset, + screenWidth: Int, + layoutDirection: LayoutDirection, + contentOffset: Offset, + ): Boolean = false + + open fun onDragInterrupted() = Unit + + open fun onDrag(offset: Offset, layoutDirection: LayoutDirection) = Unit + + open suspend fun processScrollRequests(coroutineScope: CoroutineScope) = Unit +} + +/** + * The V1 implementation of GridDragDropStateInternal to be used when the glanceable_hub_v2 flag is + * disabled. + */ +private class GridDragDropStateV1( + val gridState: LazyGridState, + private val contentListState: ContentListState, + private val scope: CoroutineScope, + private val updateDragPositionForRemove: (draggingBoundingBox: IntRect) -> Boolean, +) : GridDragDropStateInternal(gridState) { + private val scrollChannel = Channel<Float>() + + private val spacer = CommunalContentModel.Spacer(CommunalContentSize.Responsive(1)) + private var spacerIndex: Int? = null + + private var previousTargetItemKey: Any? = null + + override suspend fun processScrollRequests(coroutineScope: CoroutineScope) { + while (true) { + val diff = scrollChannel.receive() + state.scrollBy(diff) + } + } + + override fun onDragStart( offset: Offset, screenWidth: Int, layoutDirection: LayoutDirection, @@ -162,7 +256,7 @@ internal constructor( return false } - internal fun onDragInterrupted() { + override fun onDragInterrupted() { draggingItemKey?.let { if (isDraggingToRemove) { contentListState.onRemove( @@ -185,7 +279,7 @@ internal constructor( } } - internal fun onDrag(offset: Offset, layoutDirection: LayoutDirection) { + override fun onDrag(offset: Offset, layoutDirection: LayoutDirection) { // Adjust offset to match the layout direction draggingItemDraggedDelta += Offset(offset.x.directional(LayoutDirection.Ltr, layoutDirection), offset.y) @@ -282,6 +376,249 @@ internal constructor( } } +/** + * The V2 implementation of GridDragDropStateInternal to be used when the glanceable_hub_v2 flag is + * enabled. + */ +private class GridDragDropStateV2( + val gridState: LazyGridState, + private val contentListState: ContentListState, + private val scope: CoroutineScope, + private val autoScrollThreshold: Float, + private val updateDragPositionForRemove: (draggingBoundingBox: IntRect) -> Boolean, +) : GridDragDropStateInternal(gridState) { + + private val scrollChannel = Channel<Float>(Channel.UNLIMITED) + + // Used to keep track of the dragging item during scrolling (because it might be off screen + // and no longer in the list of visible items). + private var draggingItemWhileScrolling: LazyGridItemInfo? by mutableStateOf(null) + + private val spacer = CommunalContentModel.Spacer(CommunalContentSize.Responsive(1)) + private var spacerIndex: Int? = null + + private var previousTargetItemKey: Any? = null + + // Basically, the location of the user's finger on the screen. + private var currentDragPositionOnScreen by mutableStateOf(Offset.Zero) + // The offset of the grid from the top of the screen. + private var contentOffset = Offset.Zero + + // The width of one column in the grid (needed in order to auto-scroll one column at a time). + private var columnWidth = 0 + + override suspend fun processScrollRequests(coroutineScope: CoroutineScope) { + while (true) { + val amount = scrollChannel.receive() + + if (state.isScrollInProgress) { + // Ignore overscrolling if a scroll is already in progress (but we still want to + // consume the scroll event so that we don't end up processing a bunch of old + // events after scrolling has finished). + continue + } + + // We perform the rest of the drag action after scrolling has finished (or immediately + // if there will be no scrolling). + if (amount != 0f) { + coroutineScope.launch { + state.animateScrollBy(amount, tween(delayMillis = 250, durationMillis = 1000)) + performDragAction() + } + } else { + performDragAction() + } + } + } + + override fun onDragStart( + offset: Offset, + screenWidth: Int, + layoutDirection: LayoutDirection, + contentOffset: Offset, + ): Boolean { + val normalizedOffset = + Offset( + if (layoutDirection == LayoutDirection.Ltr) offset.x else screenWidth - offset.x, + offset.y, + ) + + currentDragPositionOnScreen = normalizedOffset + this.contentOffset = contentOffset + + state.layoutInfo.visibleItemsInfo + .filter { item -> contentListState.isItemEditable(item.index) } + // grid item offset is based off grid content container so we need to deduct + // before content padding from the initial pointer position + .firstItemAtOffset(normalizedOffset - contentOffset) + ?.apply { + draggingItemKey = key as String + draggingItemWhileScrolling = this + draggingItemInitialOffset = this.offset.toOffset() + columnWidth = + this.size.width + + state.layoutInfo.beforeContentPadding + + state.layoutInfo.afterContentPadding + // Add a spacer after the last widget if it is larger than the dragging widget. + // This allows overscrolling, enabling the dragging widget to be placed beyond it. + val lastWidget = contentListState.list.lastOrNull { it.isWidgetContent() } + if ( + lastWidget != null && + draggingItemLayoutInfo != null && + lastWidget.size.span > draggingItemLayoutInfo!!.span + ) { + contentListState.list.add(spacer) + spacerIndex = contentListState.list.size - 1 + } + return true + } + + return false + } + + override fun onDragInterrupted() { + draggingItemKey?.let { + if (isDraggingToRemove) { + contentListState.onRemove( + contentListState.list.indexOfFirst { it.key == draggingItemKey } + ) + isDraggingToRemove = false + updateDragPositionForRemove(IntRect.Zero) + } + // persist list editing changes on dragging ends + contentListState.onSaveList() + draggingItemKey = null + } + previousTargetItemKey = null + draggingItemDraggedDelta = Offset.Zero + draggingItemInitialOffset = Offset.Zero + currentDragPositionOnScreen = Offset.Zero + draggingItemWhileScrolling = null + // Remove spacer, if any, when a drag gesture finishes. + spacerIndex?.let { + contentListState.list.removeAt(it) + spacerIndex = null + } + } + + override fun onDrag(offset: Offset, layoutDirection: LayoutDirection) { + // Adjust offset to match the layout direction + val delta = Offset(offset.x.directional(LayoutDirection.Ltr, layoutDirection), offset.y) + draggingItemDraggedDelta += delta + currentDragPositionOnScreen += delta + + scrollChannel.trySend(computeAutoscroll(currentDragPositionOnScreen)) + } + + fun performDragAction() { + val draggingItem = draggingItemLayoutInfo ?: draggingItemWhileScrolling + if (draggingItem == null) { + return + } + + val draggingBoundingBox = + IntRect(draggingItem.offset + draggingItemOffset.round(), draggingItem.size) + val curDragPositionInGrid = (currentDragPositionOnScreen - contentOffset) + + val targetItem = + if (communalWidgetResizing()) { + val lastVisibleItemIndex = state.layoutInfo.visibleItemsInfo.last().index + state.layoutInfo.visibleItemsInfo.findLast( + fun(item): Boolean { + val itemBoundingBox = IntRect(item.offset, item.size) + return draggingItemKey != item.key && + contentListState.isItemEditable(item.index) && + itemBoundingBox.contains(curDragPositionInGrid.round()) && + // If we swap with the last visible item, and that item doesn't fit + // in the gap created by moving the current item, then the current item + // will get placed after the last visible item. In this case, it gets + // placed outside of the viewport. We avoid this here, so the user + // has to scroll first before the swap can happen. + (item.index != lastVisibleItemIndex || item.span <= draggingItem.span) + } + ) + } else { + state.layoutInfo.visibleItemsInfo + .asSequence() + .filter { item -> contentListState.isItemEditable(item.index) } + .filter { item -> draggingItem.index != item.index } + .firstItemAtOffset(curDragPositionInGrid) + } + + if ( + targetItem != null && + (!communalWidgetResizing() || targetItem.key != previousTargetItemKey) + ) { + val scrollToIndex = + if (targetItem.index == state.firstVisibleItemIndex) { + draggingItem.index + } else if (draggingItem.index == state.firstVisibleItemIndex) { + targetItem.index + } else { + null + } + if (communalWidgetResizing()) { + // Keep track of the previous target item, to avoid rapidly oscillating between + // items if the target item doesn't visually move as a result of the index change. + // In this case, even after the index changes, we'd still be colliding with the + // element, so it would be selected as the target item the next time this function + // runs again, which would trigger us to revert the index change we recently made. + previousTargetItemKey = targetItem.key + } + if (scrollToIndex != null) { + scope.launch { + // this is needed to neutralize automatic keeping the first item first. + state.scrollToItem(scrollToIndex, state.firstVisibleItemScrollOffset) + contentListState.swapItems(draggingItem.index, targetItem.index) + } + } else { + contentListState.swapItems(draggingItem.index, targetItem.index) + } + draggingItemWhileScrolling = targetItem + isDraggingToRemove = false + } else if (targetItem == null) { + isDraggingToRemove = checkForRemove(draggingBoundingBox) + previousTargetItemKey = null + } + } + + /** Calculate the amount dragged out of bound on both sides. Returns 0f if not overscrolled. */ + private fun computeAutoscroll(dragOffset: Offset): Float { + val orientation = state.layoutInfo.orientation + val distanceFromStart = + if (orientation == Orientation.Horizontal) { + dragOffset.x + } else { + dragOffset.y + } + val distanceFromEnd = + if (orientation == Orientation.Horizontal) { + state.layoutInfo.viewportEndOffset - dragOffset.x + } else { + state.layoutInfo.viewportEndOffset - dragOffset.y + } + + return when { + distanceFromEnd < autoScrollThreshold -> { + (columnWidth - state.layoutInfo.beforeContentPadding).toFloat() + } + distanceFromStart < autoScrollThreshold -> { + -(columnWidth - state.layoutInfo.afterContentPadding).toFloat() + } + else -> 0f + } + } + + /** Calls the callback with the updated drag position and returns whether to remove the item. */ + private fun checkForRemove(draggingItemBoundingBox: IntRect): Boolean { + return if (draggingItemDraggedDelta.y < 0) { + updateDragPositionForRemove(draggingItemBoundingBox) + } else { + false + } + } +} + fun Modifier.dragContainer( dragDropState: GridDragDropState, layoutDirection: LayoutDirection, diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt index 4bf0ceb51784..6e29e6932629 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt @@ -38,8 +38,9 @@ import com.android.systemui.animation.TypefaceVariantCacheImpl import com.android.systemui.customization.R import com.android.systemui.log.core.LogLevel import com.android.systemui.log.core.LogcatOnlyMessageBuffer -import com.android.systemui.log.core.Logger import com.android.systemui.log.core.MessageBuffer +import com.android.systemui.plugins.clocks.ClockLogger +import com.android.systemui.plugins.clocks.ClockLogger.Companion.escapeTime import java.io.PrintWriter import java.util.Calendar import java.util.Locale @@ -67,7 +68,7 @@ constructor( var messageBuffer: MessageBuffer get() = logger.buffer set(value) { - logger = Logger(value, TAG) + logger = ClockLogger(this, value, TAG) } var hasCustomPositionUpdatedAnimation: Boolean = false @@ -185,7 +186,9 @@ constructor( time.timeInMillis = timeOverrideInMillis ?: System.currentTimeMillis() contentDescription = DateFormat.format(descFormat, time) val formattedText = DateFormat.format(format, time) - logger.d({ "refreshTime: new formattedText=$str1" }) { str1 = formattedText?.toString() } + logger.d({ "refreshTime: new formattedText=${escapeTime(str1)}" }) { + str1 = formattedText?.toString() + } // Setting text actually triggers a layout pass in TextView (because the text view is set to // wrap_content width and TextView always relayouts for this). This avoids needless relayout @@ -195,7 +198,7 @@ constructor( } text = formattedText - logger.d({ "refreshTime: done setting new time text to: $str1" }) { + logger.d({ "refreshTime: done setting new time text to: ${escapeTime(str1)}" }) { str1 = formattedText?.toString() } @@ -225,7 +228,7 @@ constructor( @SuppressLint("DrawAllocation") override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { - logger.d("onMeasure") + logger.onMeasure(widthMeasureSpec, heightMeasureSpec) if (!isSingleLineInternal && MeasureSpec.getMode(heightMeasureSpec) == EXACTLY) { // Call straight into TextView.setTextSize to avoid setting lastUnconstrainedTextSize @@ -263,14 +266,14 @@ constructor( canvas.translate(parentWidth / 4f, 0f) } - logger.d({ "onDraw($str1)" }) { str1 = text.toString() } + logger.onDraw("$text") // intentionally doesn't call super.onDraw here or else the text will be rendered twice textAnimator?.draw(canvas) canvas.restore() } override fun invalidate() { - logger.d("invalidate") + logger.invalidate() super.invalidate() } @@ -280,7 +283,7 @@ constructor( lengthBefore: Int, lengthAfter: Int, ) { - logger.d({ "onTextChanged($str1)" }) { str1 = text.toString() } + logger.d({ "onTextChanged(${escapeTime(str1)})" }) { str1 = "$text" } super.onTextChanged(text, start, lengthBefore, lengthAfter) } @@ -370,7 +373,7 @@ constructor( return } - logger.d("animateCharge") + logger.animateCharge() val startAnimPhase2 = Runnable { setTextStyle( weight = if (isDozing()) dozingWeight else lockScreenWeight, @@ -394,7 +397,7 @@ constructor( } fun animateDoze(isDozing: Boolean, animate: Boolean) { - logger.d("animateDoze") + logger.animateDoze(isDozing, animate) setTextStyle( weight = if (isDozing) dozingWeight else lockScreenWeight, color = if (isDozing) dozingColor else lockScreenColor, @@ -484,7 +487,7 @@ constructor( isSingleLineInternal && !use24HourFormat -> Patterns.sClockView12 else -> DOUBLE_LINE_FORMAT_12_HOUR } - logger.d({ "refreshFormat($str1)" }) { str1 = format?.toString() } + logger.d({ "refreshFormat(${escapeTime(str1)})" }) { str1 = format?.toString() } descFormat = if (use24HourFormat) Patterns.sClockView24 else Patterns.sClockView12 refreshTime() @@ -634,7 +637,7 @@ constructor( companion object { private val TAG = AnimatableClockView::class.simpleName!! - private val DEFAULT_LOGGER = Logger(LogcatOnlyMessageBuffer(LogLevel.WARNING), TAG) + private val DEFAULT_LOGGER = ClockLogger(null, LogcatOnlyMessageBuffer(LogLevel.DEBUG), TAG) const val ANIMATION_DURATION_FOLD_TO_AOD: Int = 600 private const val DOUBLE_LINE_FORMAT_12_HOUR = "hh\nmm" diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/CanvasUtil.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/CanvasUtil.kt index dd1599e5259d..9857d7f3d69d 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/CanvasUtil.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/CanvasUtil.kt @@ -17,6 +17,8 @@ package com.android.systemui.shared.clocks import android.graphics.Canvas +import com.android.systemui.plugins.clocks.VPoint +import com.android.systemui.plugins.clocks.VPointF object CanvasUtil { fun Canvas.translate(pt: VPointF) = this.translate(pt.x, pt.y) diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DigitTranslateAnimator.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DigitTranslateAnimator.kt index f5ccc52c8c6b..941cebfb4014 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DigitTranslateAnimator.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DigitTranslateAnimator.kt @@ -20,7 +20,8 @@ import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.animation.TimeInterpolator import android.animation.ValueAnimator -import com.android.systemui.shared.clocks.VPointF.Companion.times +import com.android.systemui.plugins.clocks.VPointF +import com.android.systemui.plugins.clocks.VPointF.Companion.times class DigitTranslateAnimator(private val updateCallback: (VPointF) -> Unit) { var currentTranslation = VPointF.ZERO diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt index 336c66eed889..9ac9e60f05fd 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt @@ -16,13 +16,13 @@ package com.android.systemui.shared.clocks -import android.graphics.RectF import android.view.View import androidx.annotation.VisibleForTesting import com.android.systemui.plugins.clocks.ClockAnimations import com.android.systemui.plugins.clocks.ClockEvents import com.android.systemui.plugins.clocks.ClockFaceConfig import com.android.systemui.plugins.clocks.ClockFaceEvents +import com.android.systemui.plugins.clocks.VRectF interface SimpleClockLayerController { val view: View @@ -32,5 +32,5 @@ interface SimpleClockLayerController { val config: ClockFaceConfig @VisibleForTesting var fakeTimeMills: Long? - var onViewBoundsChanged: ((RectF) -> Unit)? + var onViewBoundsChanged: ((VRectF) -> Unit)? } diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ViewUtils.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ViewUtils.kt index 1e90a2370786..0740b0e504cb 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ViewUtils.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ViewUtils.kt @@ -18,8 +18,9 @@ package com.android.systemui.shared.clocks import android.graphics.Rect import android.view.View -import com.android.systemui.shared.clocks.VPoint.Companion.center -import com.android.systemui.shared.clocks.VPointF.Companion.center +import com.android.systemui.plugins.clocks.VPoint.Companion.center +import com.android.systemui.plugins.clocks.VPointF +import com.android.systemui.plugins.clocks.VPointF.Companion.center object ViewUtils { fun View.computeLayoutDiff(targetRegion: Rect, isLargeClock: Boolean): VPointF { diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt index 2dc3e2b7af73..ba32ab083063 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt @@ -17,7 +17,6 @@ package com.android.systemui.shared.clocks.view import android.graphics.Canvas -import android.graphics.RectF import android.icu.text.NumberFormat import android.util.MathUtils.constrainedMap import android.view.View @@ -29,14 +28,15 @@ import com.android.app.animation.Interpolators import com.android.systemui.customization.R import com.android.systemui.plugins.clocks.ClockFontAxisSetting import com.android.systemui.plugins.clocks.ClockLogger +import com.android.systemui.plugins.clocks.VPoint +import com.android.systemui.plugins.clocks.VPointF +import com.android.systemui.plugins.clocks.VPointF.Companion.max +import com.android.systemui.plugins.clocks.VPointF.Companion.times +import com.android.systemui.plugins.clocks.VRectF import com.android.systemui.shared.clocks.CanvasUtil.translate import com.android.systemui.shared.clocks.CanvasUtil.use import com.android.systemui.shared.clocks.ClockContext import com.android.systemui.shared.clocks.DigitTranslateAnimator -import com.android.systemui.shared.clocks.VPoint -import com.android.systemui.shared.clocks.VPointF -import com.android.systemui.shared.clocks.VPointF.Companion.max -import com.android.systemui.shared.clocks.VPointF.Companion.times import com.android.systemui.shared.clocks.ViewUtils.measuredSize import java.util.Locale import kotlin.collections.filterNotNull @@ -101,7 +101,7 @@ class FlexClockView(clockCtx: ClockContext) : ViewGroup(clockCtx.context) { updateLocale(Locale.getDefault()) } - var onViewBoundsChanged: ((RectF) -> Unit)? = null + var onViewBoundsChanged: ((VRectF) -> Unit)? = null private val digitOffsets = mutableMapOf<Int, Float>() protected fun calculateSize( @@ -189,13 +189,7 @@ class FlexClockView(clockCtx: ClockContext) : ViewGroup(clockCtx.context) { fun updateLocation() { val layoutBounds = this.layoutBounds ?: return - val bounds = - RectF( - layoutBounds.centerX() - measuredWidth / 2f, - layoutBounds.centerY() - measuredHeight / 2f, - layoutBounds.centerX() + measuredWidth / 2f, - layoutBounds.centerY() + measuredHeight / 2f, - ) + val bounds = VRectF.fromCenter(layoutBounds.center, this.measuredSize) setFrame( bounds.left.roundToInt(), bounds.top.roundToInt(), @@ -215,16 +209,11 @@ class FlexClockView(clockCtx: ClockContext) : ViewGroup(clockCtx.context) { onAnimateDoze = null } - private val layoutBounds = RectF() + private var layoutBounds = VRectF.ZERO override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { logger.onLayout(changed, left, top, right, bottom) - - layoutBounds.left = left.toFloat() - layoutBounds.top = top.toFloat() - layoutBounds.right = right.toFloat() - layoutBounds.bottom = bottom.toFloat() - + layoutBounds = VRectF(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat()) updateChildFrames(isLayout = true) } diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt index 0ec2d188833a..2af25fe339a2 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt @@ -23,7 +23,6 @@ import android.graphics.Paint import android.graphics.PorterDuff import android.graphics.PorterDuffXfermode import android.graphics.Rect -import android.graphics.RectF import android.os.VibrationEffect import android.text.Layout import android.text.TextPaint @@ -45,6 +44,10 @@ import com.android.systemui.plugins.clocks.ClockFontAxisSetting import com.android.systemui.plugins.clocks.ClockFontAxisSetting.Companion.replace import com.android.systemui.plugins.clocks.ClockFontAxisSetting.Companion.toFVar import com.android.systemui.plugins.clocks.ClockLogger +import com.android.systemui.plugins.clocks.VPoint +import com.android.systemui.plugins.clocks.VPointF +import com.android.systemui.plugins.clocks.VPointF.Companion.size +import com.android.systemui.plugins.clocks.VRectF import com.android.systemui.shared.Flags.ambientAod import com.android.systemui.shared.clocks.CanvasUtil.translate import com.android.systemui.shared.clocks.CanvasUtil.use @@ -53,9 +56,6 @@ import com.android.systemui.shared.clocks.DigitTranslateAnimator import com.android.systemui.shared.clocks.DimensionParser import com.android.systemui.shared.clocks.FLEX_CLOCK_ID import com.android.systemui.shared.clocks.FontTextStyle -import com.android.systemui.shared.clocks.VPoint -import com.android.systemui.shared.clocks.VPointF -import com.android.systemui.shared.clocks.VPointF.Companion.size import com.android.systemui.shared.clocks.ViewUtils.measuredSize import com.android.systemui.shared.clocks.ViewUtils.size import com.android.systemui.shared.clocks.toClockAxisSetting @@ -66,11 +66,11 @@ import kotlin.math.roundToInt private val TAG = SimpleDigitalClockTextView::class.simpleName!! -private fun Paint.getTextBounds(text: CharSequence, result: RectF = RectF()): RectF { - val rect = Rect() - this.getTextBounds(text, 0, text.length, rect) - result.set(rect) - return result +private val tempRect = Rect() + +private fun Paint.getTextBounds(text: CharSequence): VRectF { + this.getTextBounds(text, 0, text.length, tempRect) + return VRectF(tempRect) } enum class VerticalAlignment { @@ -143,7 +143,7 @@ open class SimpleDigitalClockTextView( fidgetFontVariation = buildFidgetVariation(lsFontAxes).toFVar() } - var onViewBoundsChanged: ((RectF) -> Unit)? = null + var onViewBoundsChanged: ((VRectF) -> Unit)? = null private val parser = DimensionParser(clockCtx.context) var maxSingleDigitHeight = -1f var maxSingleDigitWidth = -1f @@ -159,13 +159,13 @@ open class SimpleDigitalClockTextView( private val initThread = Thread.currentThread() // textBounds is the size of text in LS, which only measures current text in lockscreen style - var textBounds = RectF() + var textBounds = VRectF.ZERO // prevTextBounds and targetTextBounds are to deal with dozing animation between LS and AOD // especially for the textView which has different bounds during the animation // prevTextBounds holds the state we are transitioning from - private val prevTextBounds = RectF() + private var prevTextBounds = VRectF.ZERO // targetTextBounds holds the state we are interpolating to - private val targetTextBounds = RectF() + private var targetTextBounds = VRectF.ZERO protected val logger = ClockLogger(this, clockCtx.messageBuffer, this::class.simpleName!!) get() = field ?: ClockLogger.INIT_LOGGER @@ -215,8 +215,8 @@ open class SimpleDigitalClockTextView( lockScreenPaint.typeface = typefaceCache.getTypefaceForVariant(lsFontVariation) typeface = lockScreenPaint.typeface - lockScreenPaint.getTextBounds(text, textBounds) - targetTextBounds.set(textBounds) + textBounds = lockScreenPaint.getTextBounds(text) + targetTextBounds = textBounds textAnimator.setTextStyle(TextAnimator.Style(fVar = lsFontVariation)) measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED) @@ -287,7 +287,7 @@ open class SimpleDigitalClockTextView( canvas.use { digitTranslateAnimator?.apply { canvas.translate(currentTranslation) } canvas.translate(getDrawTranslation(interpBounds)) - if (isLayoutRtl()) canvas.translate(interpBounds.width() - textBounds.width(), 0f) + if (isLayoutRtl()) canvas.translate(interpBounds.width - textBounds.width, 0f) textAnimator.draw(canvas) } } @@ -302,16 +302,12 @@ open class SimpleDigitalClockTextView( super.setAlpha(alpha) } - private val layoutBounds = RectF() + private var layoutBounds = VRectF.ZERO override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { super.onLayout(changed, left, top, right, bottom) logger.onLayout(changed, left, top, right, bottom) - - layoutBounds.left = left.toFloat() - layoutBounds.top = top.toFloat() - layoutBounds.right = right.toFloat() - layoutBounds.bottom = bottom.toFloat() + layoutBounds = VRectF(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat()) } override fun invalidate() { @@ -327,7 +323,7 @@ open class SimpleDigitalClockTextView( fun animateDoze(isDozing: Boolean, isAnimated: Boolean) { if (!this::textAnimator.isInitialized) return - logger.animateDoze() + logger.animateDoze(isDozing, isAnimated) textAnimator.setTextStyle( TextAnimator.Style( fVar = if (isDozing) aodFontVariation else lsFontVariation, @@ -341,6 +337,11 @@ open class SimpleDigitalClockTextView( ), ) updateTextBoundsForTextAnimator() + + if (!isAnimated) { + requestLayout() + (parent as? FlexClockView)?.requestLayout() + } } fun animateCharge() { @@ -408,10 +409,10 @@ open class SimpleDigitalClockTextView( } fun refreshText() { - lockScreenPaint.getTextBounds(text, textBounds) - if (this::textAnimator.isInitialized) { - textAnimator.textInterpolator.targetPaint.getTextBounds(text, targetTextBounds) - } + textBounds = lockScreenPaint.getTextBounds(text) + targetTextBounds = + if (!this::textAnimator.isInitialized) textBounds + else textAnimator.textInterpolator.targetPaint.getTextBounds(text) if (layout == null) { requestLayout() @@ -432,23 +433,23 @@ open class SimpleDigitalClockTextView( } /** Returns the interpolated text bounding rect based on interpolation progress */ - private fun getInterpolatedTextBounds(progress: Float = getInterpolatedProgress()): RectF { + private fun getInterpolatedTextBounds(progress: Float = getInterpolatedProgress()): VRectF { if (progress <= 0f) { return prevTextBounds } else if (!textAnimator.isRunning || progress >= 1f) { return targetTextBounds } - return RectF().apply { - left = lerp(prevTextBounds.left, targetTextBounds.left, progress) - right = lerp(prevTextBounds.right, targetTextBounds.right, progress) - top = lerp(prevTextBounds.top, targetTextBounds.top, progress) - bottom = lerp(prevTextBounds.bottom, targetTextBounds.bottom, progress) - } + return VRectF( + left = lerp(prevTextBounds.left, targetTextBounds.left, progress), + right = lerp(prevTextBounds.right, targetTextBounds.right, progress), + top = lerp(prevTextBounds.top, targetTextBounds.top, progress), + bottom = lerp(prevTextBounds.bottom, targetTextBounds.bottom, progress), + ) } private fun computeMeasuredSize( - interpBounds: RectF, + interpBounds: VRectF, widthMeasureSpec: Int = measuredWidthAndState, heightMeasureSpec: Int = measuredHeightAndState, ): VPointF { @@ -461,11 +462,11 @@ open class SimpleDigitalClockTextView( return VPointF( when { mode.x == EXACTLY -> MeasureSpec.getSize(widthMeasureSpec).toFloat() - else -> interpBounds.width() + 2 * lockScreenPaint.strokeWidth + else -> interpBounds.width + 2 * lockScreenPaint.strokeWidth }, when { mode.y == EXACTLY -> MeasureSpec.getSize(heightMeasureSpec).toFloat() - else -> interpBounds.height() + 2 * lockScreenPaint.strokeWidth + else -> interpBounds.height + 2 * lockScreenPaint.strokeWidth }, ) } @@ -489,44 +490,23 @@ open class SimpleDigitalClockTextView( } /** Set the location of the view to match the interpolated text bounds */ - private fun setInterpolatedLocation(measureSize: VPointF): RectF { - val targetRect = RectF() - targetRect.apply { - when (xAlignment) { - XAlignment.LEFT -> { - left = layoutBounds.left - right = layoutBounds.left + measureSize.x - } - XAlignment.CENTER -> { - left = layoutBounds.centerX() - measureSize.x / 2f - right = layoutBounds.centerX() + measureSize.x / 2f - } - XAlignment.RIGHT -> { - left = layoutBounds.right - measureSize.x - right = layoutBounds.right - } - } - - when (verticalAlignment) { - VerticalAlignment.TOP -> { - top = layoutBounds.top - bottom = layoutBounds.top + measureSize.y - } - VerticalAlignment.CENTER -> { - top = layoutBounds.centerY() - measureSize.y / 2f - bottom = layoutBounds.centerY() + measureSize.y / 2f - } - VerticalAlignment.BOTTOM -> { - top = layoutBounds.bottom - measureSize.y - bottom = layoutBounds.bottom - } - VerticalAlignment.BASELINE -> { - top = layoutBounds.centerY() - measureSize.y / 2f - bottom = layoutBounds.centerY() + measureSize.y / 2f - } - } - } + private fun setInterpolatedLocation(measureSize: VPointF): VRectF { + val pos = + VPointF( + when (xAlignment) { + XAlignment.LEFT -> layoutBounds.left + XAlignment.CENTER -> layoutBounds.center.x - measureSize.x / 2f + XAlignment.RIGHT -> layoutBounds.right - measureSize.x + }, + when (verticalAlignment) { + VerticalAlignment.TOP -> layoutBounds.top + VerticalAlignment.CENTER -> layoutBounds.center.y - measureSize.y / 2f + VerticalAlignment.BOTTOM -> layoutBounds.bottom - measureSize.y + VerticalAlignment.BASELINE -> layoutBounds.center.y - measureSize.y / 2f + }, + ) + val targetRect = VRectF.fromTopLeft(pos, measureSize) setFrame( targetRect.left.roundToInt(), targetRect.top.roundToInt(), @@ -537,7 +517,7 @@ open class SimpleDigitalClockTextView( return targetRect } - private fun getDrawTranslation(interpBounds: RectF): VPointF { + private fun getDrawTranslation(interpBounds: VRectF): VPointF { val sizeDiff = this.measuredSize - interpBounds.size val alignment = VPointF( @@ -586,11 +566,11 @@ open class SimpleDigitalClockTextView( if (fontSizePx > 0) { setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSizePx) lockScreenPaint.textSize = textSize - lockScreenPaint.getTextBounds(text, textBounds) - targetTextBounds.set(textBounds) + textBounds = lockScreenPaint.getTextBounds(text) + targetTextBounds = textBounds } if (!constrainedByHeight) { - val lastUnconstrainedHeight = textBounds.height() + lockScreenPaint.strokeWidth * 2 + val lastUnconstrainedHeight = textBounds.height + lockScreenPaint.strokeWidth * 2 fontSizeAdjustFactor = lastUnconstrainedHeight / lastUnconstrainedTextSize } @@ -608,8 +588,8 @@ open class SimpleDigitalClockTextView( for (i in 0..9) { val rectForCalculate = lockScreenPaint.getTextBounds("$i") - maxSingleDigitHeight = max(maxSingleDigitHeight, rectForCalculate.height()) - maxSingleDigitWidth = max(maxSingleDigitWidth, rectForCalculate.width()) + maxSingleDigitHeight = max(maxSingleDigitHeight, rectForCalculate.height) + maxSingleDigitWidth = max(maxSingleDigitWidth, rectForCalculate.width) } maxSingleDigitWidth += 2 * lockScreenPaint.strokeWidth maxSingleDigitHeight += 2 * lockScreenPaint.strokeWidth @@ -637,8 +617,8 @@ open class SimpleDigitalClockTextView( * and targetPaint will store the state we transition to */ private fun updateTextBoundsForTextAnimator() { - textAnimator.textInterpolator.basePaint.getTextBounds(text, prevTextBounds) - textAnimator.textInterpolator.targetPaint.getTextBounds(text, targetTextBounds) + prevTextBounds = textAnimator.textInterpolator.basePaint.getTextBounds(text) + targetTextBounds = textAnimator.textInterpolator.targetPaint.getTextBounds(text) } /** diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/FontVariationUtilsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/FontVariationUtilsTest.kt index 8d3640d8d809..53b364c13063 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/FontVariationUtilsTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/FontVariationUtilsTest.kt @@ -41,21 +41,9 @@ class FontVariationUtilsTest : SysuiTestCase() { @Test fun testStyleValueUnchange_getBlankStr() { val fontVariationUtils = FontVariationUtils() - fontVariationUtils.updateFontVariation( - weight = 100, - width = 100, - opticalSize = 0, - roundness = 100, - ) - val updatedFvar1 = - fontVariationUtils.updateFontVariation( - weight = 100, - width = 100, - opticalSize = 0, - roundness = 100, - ) - Assert.assertEquals("", updatedFvar1) - val updatedFvar2 = fontVariationUtils.updateFontVariation() - Assert.assertEquals("", updatedFvar2) + Assert.assertEquals("", fontVariationUtils.updateFontVariation()) + val fVar = fontVariationUtils.updateFontVariation(weight = 100) + Assert.assertEquals(fVar, fontVariationUtils.updateFontVariation()) + Assert.assertEquals(fVar, fontVariationUtils.updateFontVariation(weight = 100)) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt index 5249bbe2a861..e8c30bafbba0 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt @@ -58,7 +58,6 @@ import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule -import org.mockito.kotlin.firstValue @SmallTest @RunWith(AndroidJUnit4::class) @@ -116,12 +115,7 @@ class SideFpsOverlayViewBinderTest : SysuiTestCase() { runCurrent() verify(kosmos.windowManager).addView(any(), any()) - verify(kosmos.windowManager).addView(viewCaptor.capture(), any()) - verify(viewCaptor.firstValue) - .announceForAccessibility( - mContext.getText(R.string.accessibility_side_fingerprint_indicator_label) - ) updateSfpsIndicatorRequests(kosmos, mContext, alternateBouncerRequest = false) runCurrent() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModelTest.kt index 25a287c4cfff..15a6de896e92 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModelTest.kt @@ -247,20 +247,20 @@ class PinInputViewModelTest : SysuiTestCase() { } private class PinInputSubject -private constructor(metadata: FailureMetadata, private val actual: PinInputViewModel) : +private constructor(metadata: FailureMetadata, private val actual: PinInputViewModel?) : Subject(metadata, actual) { fun matches(mnemonics: String) { val actualMnemonics = - actual.input - .map { entry -> + actual?.input + ?.map { entry -> when (entry) { is Digit -> entry.input.digitToChar() is ClearAll -> 'C' else -> throw IllegalArgumentException() } } - .joinToString(separator = "") + ?.joinToString(separator = "") if (mnemonics != actualMnemonics) { failWithActual( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/TouchHandlingViewInteractionHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/TouchHandlingViewInteractionHandlerTest.kt index 0f400892f988..56b06de0a9ba 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/TouchHandlingViewInteractionHandlerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/TouchHandlingViewInteractionHandlerTest.kt @@ -17,14 +17,12 @@ package com.android.systemui.common.ui.view +import android.testing.TestableLooper +import android.view.MotionEvent import android.view.ViewConfiguration import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.common.ui.view.TouchHandlingViewInteractionHandler.MotionEventModel -import com.android.systemui.common.ui.view.TouchHandlingViewInteractionHandler.MotionEventModel.Down -import com.android.systemui.common.ui.view.TouchHandlingViewInteractionHandler.MotionEventModel.Move -import com.android.systemui.common.ui.view.TouchHandlingViewInteractionHandler.MotionEventModel.Up import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat @@ -33,18 +31,22 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock import org.mockito.Mockito.never +import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidJUnit4::class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) class TouchHandlingViewInteractionHandlerTest : SysuiTestCase() { @Mock private lateinit var postDelayed: (Runnable, Long) -> DisposableHandle @Mock private lateinit var onLongPressDetected: (Int, Int) -> Unit @Mock private lateinit var onSingleTapDetected: (Int, Int) -> Unit + @Mock private lateinit var onDoubleTapDetected: () -> Unit private lateinit var underTest: TouchHandlingViewInteractionHandler @@ -61,14 +63,17 @@ class TouchHandlingViewInteractionHandlerTest : SysuiTestCase() { underTest = TouchHandlingViewInteractionHandler( + context = context, postDelayed = postDelayed, isAttachedToWindow = { isAttachedToWindow }, onLongPressDetected = onLongPressDetected, onSingleTapDetected = onSingleTapDetected, + onDoubleTapDetected = onDoubleTapDetected, longPressDuration = { ViewConfiguration.getLongPressTimeout().toLong() }, allowedTouchSlop = ViewConfiguration.getTouchSlop(), ) underTest.isLongPressHandlingEnabled = true + underTest.isDoubleTapHandlingEnabled = true } @Test @@ -76,63 +81,250 @@ class TouchHandlingViewInteractionHandlerTest : SysuiTestCase() { val downX = 123 val downY = 456 dispatchTouchEvents( - Down(x = downX, y = downY), - Move(distanceMoved = ViewConfiguration.getTouchSlop() - 0.1f), + MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 123f, 456f, 0), + MotionEvent.obtain( + 0L, + 0L, + MotionEvent.ACTION_MOVE, + 123f + ViewConfiguration.getTouchSlop() - 0.1f, + 456f, + 0, + ), ) delayedRunnable?.run() verify(onLongPressDetected).invoke(downX, downY) - verify(onSingleTapDetected, never()).invoke(any(), any()) + verify(onSingleTapDetected, never()).invoke(anyInt(), anyInt()) } @Test fun longPressButFeatureNotEnabled() = runTest { underTest.isLongPressHandlingEnabled = false - dispatchTouchEvents(Down(x = 123, y = 456)) + dispatchTouchEvents(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 123f, 456f, 0)) assertThat(delayedRunnable).isNull() - verify(onLongPressDetected, never()).invoke(any(), any()) - verify(onSingleTapDetected, never()).invoke(any(), any()) + verify(onLongPressDetected, never()).invoke(anyInt(), anyInt()) + verify(onSingleTapDetected, never()).invoke(anyInt(), anyInt()) } @Test fun longPressButViewNotAttached() = runTest { isAttachedToWindow = false - dispatchTouchEvents(Down(x = 123, y = 456)) + dispatchTouchEvents(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 123f, 456f, 0)) delayedRunnable?.run() - verify(onLongPressDetected, never()).invoke(any(), any()) - verify(onSingleTapDetected, never()).invoke(any(), any()) + verify(onLongPressDetected, never()).invoke(anyInt(), anyInt()) + verify(onSingleTapDetected, never()).invoke(anyInt(), anyInt()) } @Test fun draggedTooFarToBeConsideredAlongPress() = runTest { dispatchTouchEvents( - Down(x = 123, y = 456), - Move(distanceMoved = ViewConfiguration.getTouchSlop() + 0.1f), + MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 123F, 456F, 0), + // Drag action within touch slop + MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 123f, 456f, 0).apply { + addBatch(0L, 123f + ViewConfiguration.getTouchSlop() + 0.1f, 456f, 0f, 0f, 0) + }, ) assertThat(delayedRunnable).isNull() - verify(onLongPressDetected, never()).invoke(any(), any()) - verify(onSingleTapDetected, never()).invoke(any(), any()) + verify(onLongPressDetected, never()).invoke(anyInt(), anyInt()) + verify(onSingleTapDetected, never()).invoke(anyInt(), anyInt()) } @Test fun heldDownTooBrieflyToBeConsideredAlongPress() = runTest { dispatchTouchEvents( - Down(x = 123, y = 456), - Up( - distanceMoved = ViewConfiguration.getTouchSlop().toFloat(), - gestureDuration = ViewConfiguration.getLongPressTimeout() - 1L, + MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 123f, 456f, 0), + MotionEvent.obtain( + 0L, + ViewConfiguration.getLongPressTimeout() - 1L, + MotionEvent.ACTION_UP, + 123f, + 456F, + 0, ), ) assertThat(delayedRunnable).isNull() - verify(onLongPressDetected, never()).invoke(any(), any()) + verify(onLongPressDetected, never()).invoke(anyInt(), anyInt()) verify(onSingleTapDetected).invoke(123, 456) } - private fun dispatchTouchEvents(vararg models: MotionEventModel) { - models.forEach { model -> underTest.onTouchEvent(model) } + @Test + fun doubleTap() = runTest { + val secondTapTime = ViewConfiguration.getDoubleTapTimeout() - 1L + dispatchTouchEvents( + MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 123f, 456f, 0), + MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 123f, 456f, 0), + MotionEvent.obtain( + secondTapTime, + secondTapTime, + MotionEvent.ACTION_DOWN, + 123f, + 456f, + 0, + ), + MotionEvent.obtain(secondTapTime, secondTapTime, MotionEvent.ACTION_UP, 123f, 456f, 0), + ) + + verify(onDoubleTapDetected).invoke() + assertThat(delayedRunnable).isNull() + verify(onLongPressDetected, never()).invoke(anyInt(), anyInt()) + verify(onSingleTapDetected, times(2)).invoke(anyInt(), anyInt()) + } + + @Test + fun doubleTapButFeatureNotEnabled() = runTest { + underTest.isDoubleTapHandlingEnabled = false + + val secondTapTime = ViewConfiguration.getDoubleTapTimeout() - 1L + dispatchTouchEvents( + MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 123f, 456f, 0), + MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 123f, 456f, 0), + MotionEvent.obtain( + secondTapTime, + secondTapTime, + MotionEvent.ACTION_DOWN, + 123f, + 456f, + 0, + ), + MotionEvent.obtain(secondTapTime, secondTapTime, MotionEvent.ACTION_UP, 123f, 456f, 0), + ) + + verify(onDoubleTapDetected, never()).invoke() + assertThat(delayedRunnable).isNull() + verify(onLongPressDetected, never()).invoke(anyInt(), anyInt()) + verify(onSingleTapDetected, times(2)).invoke(anyInt(), anyInt()) + } + + @Test + fun tapIntoLongPress() = runTest { + val secondTapTime = ViewConfiguration.getDoubleTapTimeout() - 1L + dispatchTouchEvents( + MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 123f, 456f, 0), + MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 123f, 456f, 0), + MotionEvent.obtain( + secondTapTime, + secondTapTime, + MotionEvent.ACTION_DOWN, + 123f, + 456f, + 0, + ), + MotionEvent.obtain( + secondTapTime + ViewConfiguration.getLongPressTimeout() + 1L, + secondTapTime + ViewConfiguration.getLongPressTimeout() + 1L, + MotionEvent.ACTION_MOVE, + 123f + ViewConfiguration.getTouchSlop() - 0.1f, + 456f, + 0, + ), + ) + delayedRunnable?.run() + + verify(onDoubleTapDetected, never()).invoke() + verify(onSingleTapDetected).invoke(anyInt(), anyInt()) + verify(onLongPressDetected).invoke(anyInt(), anyInt()) + } + + @Test + fun tapIntoDownHoldTooBrieflyToBeConsideredLongPress() = runTest { + val secondTapTime = ViewConfiguration.getDoubleTapTimeout() - 1L + dispatchTouchEvents( + MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 123f, 456f, 0), + MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 123f, 456f, 0), + MotionEvent.obtain( + secondTapTime, + secondTapTime, + MotionEvent.ACTION_DOWN, + 123f, + 456f, + 0, + ), + MotionEvent.obtain( + secondTapTime + ViewConfiguration.getLongPressTimeout() + 1L, + secondTapTime + ViewConfiguration.getLongPressTimeout() + 1L, + MotionEvent.ACTION_UP, + 123f, + 456f, + 0, + ), + ) + delayedRunnable?.run() + + verify(onDoubleTapDetected, never()).invoke() + verify(onLongPressDetected, never()).invoke(anyInt(), anyInt()) + verify(onSingleTapDetected, times(2)).invoke(anyInt(), anyInt()) + } + + @Test + fun tapIntoDrag() = runTest { + val secondTapTime = ViewConfiguration.getDoubleTapTimeout() - 1L + dispatchTouchEvents( + MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 123f, 456f, 0), + MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 123f, 456f, 0), + MotionEvent.obtain( + secondTapTime, + secondTapTime, + MotionEvent.ACTION_DOWN, + 123f, + 456f, + 0, + ), + // Drag event within touch slop + MotionEvent.obtain(secondTapTime, secondTapTime, MotionEvent.ACTION_MOVE, 123f, 456f, 0) + .apply { + addBatch( + secondTapTime, + 123f + ViewConfiguration.getTouchSlop() + 0.1f, + 456f, + 0f, + 0f, + 0, + ) + }, + ) + delayedRunnable?.run() + + verify(onDoubleTapDetected, never()).invoke() + verify(onLongPressDetected, never()).invoke(anyInt(), anyInt()) + verify(onSingleTapDetected).invoke(anyInt(), anyInt()) + } + + @Test + fun doubleTapOutOfAllowableSlop() = runTest { + val secondTapTime = ViewConfiguration.getDoubleTapTimeout() - 1L + val scaledDoubleTapSlop = ViewConfiguration.get(context).scaledDoubleTapSlop + dispatchTouchEvents( + MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 123f, 456f, 0), + MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 123f, 456f, 0), + MotionEvent.obtain( + secondTapTime, + secondTapTime, + MotionEvent.ACTION_DOWN, + 123f + scaledDoubleTapSlop + 0.1f, + 456f + scaledDoubleTapSlop + 0.1f, + 0, + ), + MotionEvent.obtain( + secondTapTime, + secondTapTime, + MotionEvent.ACTION_UP, + 123f + scaledDoubleTapSlop + 0.1f, + 456f + scaledDoubleTapSlop + 0.1f, + 0, + ), + ) + + verify(onDoubleTapDetected, never()).invoke() + assertThat(delayedRunnable).isNull() + verify(onLongPressDetected, never()).invoke(anyInt(), anyInt()) + verify(onSingleTapDetected, times(2)).invoke(anyInt(), anyInt()) + } + + private fun dispatchTouchEvents(vararg events: MotionEvent) { + events.forEach { event -> underTest.onTouchEvent(event) } } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalOngoingContentStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalOngoingContentStartableTest.kt index ed73d89db2c7..6a25069a4e5e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalOngoingContentStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalOngoingContentStartableTest.kt @@ -73,12 +73,12 @@ class CommunalOngoingContentStartableTest : SysuiTestCase() { assertThat(fakeCommunalMediaRepository.isListening()).isFalse() assertThat(fakeCommunalSmartspaceRepository.isListening()).isFalse() - kosmos.setCommunalEnabled(true) + setCommunalEnabled(true) assertThat(fakeCommunalMediaRepository.isListening()).isTrue() assertThat(fakeCommunalSmartspaceRepository.isListening()).isTrue() - kosmos.setCommunalEnabled(false) + setCommunalEnabled(false) assertThat(fakeCommunalMediaRepository.isListening()).isFalse() assertThat(fakeCommunalSmartspaceRepository.isListening()).isFalse() @@ -93,13 +93,13 @@ class CommunalOngoingContentStartableTest : SysuiTestCase() { assertThat(fakeCommunalMediaRepository.isListening()).isFalse() assertThat(fakeCommunalSmartspaceRepository.isListening()).isFalse() - kosmos.setCommunalEnabled(true) + setCommunalEnabled(true) // Media listening does not start when UMO is disabled. assertThat(fakeCommunalMediaRepository.isListening()).isFalse() assertThat(fakeCommunalSmartspaceRepository.isListening()).isTrue() - kosmos.setCommunalEnabled(false) + setCommunalEnabled(false) assertThat(fakeCommunalMediaRepository.isListening()).isFalse() assertThat(fakeCommunalSmartspaceRepository.isListening()).isFalse() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CarProjectionRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CarProjectionRepositoryImplTest.kt new file mode 100644 index 000000000000..f9b29e9bc5b5 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CarProjectionRepositoryImplTest.kt @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2025 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.communal.data.repository + +import android.app.UiModeManager +import android.app.UiModeManager.OnProjectionStateChangedListener +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.backgroundScope +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.flow.launchIn +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.stub + +@SmallTest +@RunWith(AndroidJUnit4::class) +class CarProjectionRepositoryImplTest : SysuiTestCase() { + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + + private val capturedListeners = mutableListOf<OnProjectionStateChangedListener>() + + private val Kosmos.uiModeManager by + Kosmos.Fixture<UiModeManager> { + mock { + on { + addOnProjectionStateChangedListener( + eq(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE), + any(), + any(), + ) + } doAnswer + { + val listener = it.getArgument<OnProjectionStateChangedListener>(2) + capturedListeners.add(listener) + Unit + } + + on { removeOnProjectionStateChangedListener(any()) } doAnswer + { + val listener = it.getArgument<OnProjectionStateChangedListener>(0) + capturedListeners.remove(listener) + Unit + } + + on { activeProjectionTypes } doReturn UiModeManager.PROJECTION_TYPE_NONE + } + } + + private val Kosmos.underTest by + Kosmos.Fixture { + CarProjectionRepositoryImpl( + uiModeManager = uiModeManager, + bgDispatcher = testDispatcher, + ) + } + + @Test + fun testProjectionActiveUpdatesAfterCallback() = + kosmos.runTest { + val projectionActive by collectLastValue(underTest.projectionActive) + assertThat(projectionActive).isFalse() + + setActiveProjectionType(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE) + assertThat(projectionActive).isTrue() + + setActiveProjectionType(UiModeManager.PROJECTION_TYPE_NONE) + assertThat(projectionActive).isFalse() + } + + @Test + fun testProjectionInitialValueTrue() = + kosmos.runTest { + setActiveProjectionType(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE) + + val projectionActive by collectLastValue(underTest.projectionActive) + assertThat(projectionActive).isTrue() + } + + @Test + fun testUnsubscribeWhenCancelled() = + kosmos.runTest { + val job = underTest.projectionActive.launchIn(backgroundScope) + assertThat(capturedListeners).hasSize(1) + + job.cancel() + assertThat(capturedListeners).isEmpty() + } + + private fun Kosmos.setActiveProjectionType(@UiModeManager.ProjectionType projectionType: Int) { + uiModeManager.stub { on { activeProjectionTypes } doReturn projectionType } + capturedListeners.forEach { it.onProjectionStateChanged(projectionType, emptySet()) } + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt index 5c983656225e..09d44a5e18d9 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt @@ -34,9 +34,7 @@ import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.broadcastDispatcher -import com.android.systemui.communal.data.model.DisabledReason import com.android.systemui.communal.data.repository.CommunalSettingsRepositoryImpl.Companion.GLANCEABLE_HUB_BACKGROUND_SETTING -import com.android.systemui.communal.domain.interactor.setCommunalV2Enabled import com.android.systemui.communal.shared.model.CommunalBackgroundType import com.android.systemui.communal.shared.model.WhenToDream import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED @@ -202,63 +200,6 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT @EnableFlags(FLAG_COMMUNAL_HUB) @Test - fun secondaryUserIsInvalid() = - kosmos.runTest { - val enabledState by collectLastValue(underTest.getEnabledState(SECONDARY_USER)) - - assertThat(enabledState?.enabled).isFalse() - assertThat(enabledState).containsExactly(DisabledReason.DISABLED_REASON_INVALID_USER) - } - - @EnableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2) - @Test - fun classicFlagIsDisabled() = - kosmos.runTest { - setCommunalV2Enabled(false) - val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER)) - assertThat(enabledState?.enabled).isFalse() - assertThat(enabledState).containsExactly(DisabledReason.DISABLED_REASON_FLAG) - } - - @DisableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2) - @Test - fun communalHubFlagIsDisabled() = - kosmos.runTest { - val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER)) - assertThat(enabledState?.enabled).isFalse() - assertThat(enabledState).containsExactly(DisabledReason.DISABLED_REASON_FLAG) - } - - @EnableFlags(FLAG_COMMUNAL_HUB) - @Test - fun hubIsDisabledByUser() = - kosmos.runTest { - fakeSettings.putIntForUser(Settings.Secure.GLANCEABLE_HUB_ENABLED, 0, PRIMARY_USER.id) - val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER)) - assertThat(enabledState?.enabled).isFalse() - assertThat(enabledState).containsExactly(DisabledReason.DISABLED_REASON_USER_SETTING) - - fakeSettings.putIntForUser(Settings.Secure.GLANCEABLE_HUB_ENABLED, 1, SECONDARY_USER.id) - assertThat(enabledState?.enabled).isFalse() - - fakeSettings.putIntForUser(Settings.Secure.GLANCEABLE_HUB_ENABLED, 1, PRIMARY_USER.id) - assertThat(enabledState?.enabled).isTrue() - } - - @EnableFlags(FLAG_COMMUNAL_HUB) - @Test - fun hubIsDisabledByDevicePolicy() = - kosmos.runTest { - val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER)) - assertThat(enabledState?.enabled).isTrue() - - setKeyguardFeaturesDisabled(PRIMARY_USER, KEYGUARD_DISABLE_WIDGETS_ALL) - assertThat(enabledState?.enabled).isFalse() - assertThat(enabledState).containsExactly(DisabledReason.DISABLED_REASON_DEVICE_POLICY) - } - - @EnableFlags(FLAG_COMMUNAL_HUB) - @Test fun widgetsAllowedForWorkProfile_isFalse_whenDisallowedByDevicePolicy() = kosmos.runTest { val widgetsAllowedForWorkProfile by @@ -269,36 +210,6 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT assertThat(widgetsAllowedForWorkProfile).isFalse() } - @EnableFlags(FLAG_COMMUNAL_HUB) - @Test - fun hubIsEnabled_whenDisallowedByDevicePolicyForWorkProfile() = - kosmos.runTest { - val enabledStateForPrimaryUser by - collectLastValue(underTest.getEnabledState(PRIMARY_USER)) - assertThat(enabledStateForPrimaryUser?.enabled).isTrue() - - setKeyguardFeaturesDisabled(WORK_PROFILE, KEYGUARD_DISABLE_WIDGETS_ALL) - assertThat(enabledStateForPrimaryUser?.enabled).isTrue() - } - - @EnableFlags(FLAG_COMMUNAL_HUB) - @Test - fun hubIsDisabledByUserAndDevicePolicy() = - kosmos.runTest { - val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER)) - assertThat(enabledState?.enabled).isTrue() - - fakeSettings.putIntForUser(Settings.Secure.GLANCEABLE_HUB_ENABLED, 0, PRIMARY_USER.id) - setKeyguardFeaturesDisabled(PRIMARY_USER, KEYGUARD_DISABLE_WIDGETS_ALL) - - assertThat(enabledState?.enabled).isFalse() - assertThat(enabledState) - .containsExactly( - DisabledReason.DISABLED_REASON_DEVICE_POLICY, - DisabledReason.DISABLED_REASON_USER_SETTING, - ) - } - @Test @DisableFlags(FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND) fun backgroundType_defaultValue() = @@ -327,26 +238,6 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT } @Test - fun screensaverDisabledByUser() = - kosmos.runTest { - val enabledState by collectLastValue(underTest.getScreensaverEnabledState(PRIMARY_USER)) - - fakeSettings.putIntForUser(Settings.Secure.SCREENSAVER_ENABLED, 0, PRIMARY_USER.id) - - assertThat(enabledState).isFalse() - } - - @Test - fun screensaverEnabledByUser() = - kosmos.runTest { - val enabledState by collectLastValue(underTest.getScreensaverEnabledState(PRIMARY_USER)) - - fakeSettings.putIntForUser(Settings.Secure.SCREENSAVER_ENABLED, 1, PRIMARY_USER.id) - - assertThat(enabledState).isTrue() - } - - @Test fun whenToDream_charging() = kosmos.runTest { val whenToDreamState by collectLastValue(underTest.getWhenToDreamState(PRIMARY_USER)) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CarProjectionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CarProjectionInteractorTest.kt new file mode 100644 index 000000000000..fc4cd43577b1 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CarProjectionInteractorTest.kt @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2025 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.communal.domain.interactor + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.data.repository.carProjectionRepository +import com.android.systemui.communal.data.repository.fake +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class CarProjectionInteractorTest : SysuiTestCase() { + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + + private val Kosmos.underTest by Kosmos.Fixture { carProjectionInteractor } + + @Test + fun testProjectionActive() = + kosmos.runTest { + val projectionActive by collectLastValue(underTest.projectionActive) + assertThat(projectionActive).isFalse() + + carProjectionRepository.fake.setProjectionActive(true) + assertThat(projectionActive).isTrue() + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractorTest.kt new file mode 100644 index 000000000000..f4a1c90a5471 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractorTest.kt @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2025 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.communal.domain.interactor + +import android.provider.Settings +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.common.data.repository.batteryRepository +import com.android.systemui.common.data.repository.fake +import com.android.systemui.communal.data.model.FEATURE_AUTO_OPEN +import com.android.systemui.communal.data.model.FEATURE_MANUAL_OPEN +import com.android.systemui.communal.data.model.SuppressionReason +import com.android.systemui.communal.posturing.data.repository.fake +import com.android.systemui.communal.posturing.data.repository.posturingRepository +import com.android.systemui.communal.posturing.shared.model.PosturedState +import com.android.systemui.dock.DockManager +import com.android.systemui.dock.fakeDockManager +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.testKosmos +import com.android.systemui.user.data.repository.FakeUserRepository.Companion.MAIN_USER_ID +import com.android.systemui.user.data.repository.fakeUserRepository +import com.android.systemui.util.settings.fakeSettings +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.runBlocking +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class CommunalAutoOpenInteractorTest : SysuiTestCase() { + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + + private val Kosmos.underTest by Kosmos.Fixture { communalAutoOpenInteractor } + + @Before + fun setUp() { + runBlocking { kosmos.fakeUserRepository.asMainUser() } + with(kosmos.fakeSettings) { + putBoolForUser(Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, false, MAIN_USER_ID) + putBoolForUser(Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, false, MAIN_USER_ID) + putBoolForUser(Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED, false, MAIN_USER_ID) + } + } + + @Test + fun testStartWhileCharging() = + kosmos.runTest { + val shouldAutoOpen by collectLastValue(underTest.shouldAutoOpen) + val suppressionReason by collectLastValue(underTest.suppressionReason) + + fakeSettings.putBoolForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, + true, + MAIN_USER_ID, + ) + + batteryRepository.fake.setDevicePluggedIn(false) + assertThat(shouldAutoOpen).isFalse() + assertThat(suppressionReason) + .isEqualTo( + SuppressionReason.ReasonWhenToAutoShow(FEATURE_AUTO_OPEN or FEATURE_MANUAL_OPEN) + ) + + batteryRepository.fake.setDevicePluggedIn(true) + assertThat(shouldAutoOpen).isTrue() + assertThat(suppressionReason).isNull() + } + + @Test + fun testStartWhileDocked() = + kosmos.runTest { + val shouldAutoOpen by collectLastValue(underTest.shouldAutoOpen) + val suppressionReason by collectLastValue(underTest.suppressionReason) + + fakeSettings.putBoolForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, + true, + MAIN_USER_ID, + ) + + batteryRepository.fake.setDevicePluggedIn(true) + fakeDockManager.setIsDocked(false) + + assertThat(shouldAutoOpen).isFalse() + assertThat(suppressionReason) + .isEqualTo( + SuppressionReason.ReasonWhenToAutoShow(FEATURE_AUTO_OPEN or FEATURE_MANUAL_OPEN) + ) + + fakeDockManager.setIsDocked(true) + fakeDockManager.setDockEvent(DockManager.STATE_DOCKED) + assertThat(shouldAutoOpen).isTrue() + assertThat(suppressionReason).isNull() + } + + @Test + fun testStartWhilePostured() = + kosmos.runTest { + val shouldAutoOpen by collectLastValue(underTest.shouldAutoOpen) + val suppressionReason by collectLastValue(underTest.suppressionReason) + + fakeSettings.putBoolForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED, + true, + MAIN_USER_ID, + ) + + batteryRepository.fake.setDevicePluggedIn(true) + posturingRepository.fake.setPosturedState(PosturedState.NotPostured) + + assertThat(shouldAutoOpen).isFalse() + assertThat(suppressionReason) + .isEqualTo( + SuppressionReason.ReasonWhenToAutoShow(FEATURE_AUTO_OPEN or FEATURE_MANUAL_OPEN) + ) + + posturingRepository.fake.setPosturedState(PosturedState.Postured(1f)) + assertThat(shouldAutoOpen).isTrue() + assertThat(suppressionReason).isNull() + } + + @Test + fun testStartNever() = + kosmos.runTest { + val shouldAutoOpen by collectLastValue(underTest.shouldAutoOpen) + val suppressionReason by collectLastValue(underTest.suppressionReason) + + fakeSettings.putBoolForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, + false, + MAIN_USER_ID, + ) + fakeSettings.putBoolForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, + false, + MAIN_USER_ID, + ) + fakeSettings.putBoolForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED, + false, + MAIN_USER_ID, + ) + + batteryRepository.fake.setDevicePluggedIn(true) + posturingRepository.fake.setPosturedState(PosturedState.Postured(1f)) + fakeDockManager.setIsDocked(true) + + assertThat(shouldAutoOpen).isFalse() + assertThat(suppressionReason) + .isEqualTo( + SuppressionReason.ReasonWhenToAutoShow(FEATURE_AUTO_OPEN or FEATURE_MANUAL_OPEN) + ) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorCommunalDisabledTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorCommunalDisabledTest.kt deleted file mode 100644 index beec184b80e7..000000000000 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorCommunalDisabledTest.kt +++ /dev/null @@ -1,82 +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.communal.domain.interactor - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.android.systemui.Flags.FLAG_COMMUNAL_HUB -import com.android.systemui.SysuiTestCase -import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository -import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository -import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository -import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository -import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository -import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository -import com.android.systemui.kosmos.testScope -import com.android.systemui.testKosmos -import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.test.runCurrent -import kotlinx.coroutines.test.runTest -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith - -/** - * This class is a variation of the [CommunalInteractorTest] for cases where communal is disabled. - */ -@SmallTest -@RunWith(AndroidJUnit4::class) -class CommunalInteractorCommunalDisabledTest : SysuiTestCase() { - private val kosmos = testKosmos() - private val testScope = kosmos.testScope - - private lateinit var communalRepository: FakeCommunalSceneRepository - private lateinit var widgetRepository: FakeCommunalWidgetRepository - private lateinit var keyguardRepository: FakeKeyguardRepository - - private lateinit var underTest: CommunalInteractor - - @Before - fun setUp() { - communalRepository = kosmos.fakeCommunalSceneRepository - widgetRepository = kosmos.fakeCommunalWidgetRepository - keyguardRepository = kosmos.fakeKeyguardRepository - - mSetFlagsRule.disableFlags(FLAG_COMMUNAL_HUB) - - underTest = kosmos.communalInteractor - } - - @Test - fun isCommunalEnabled_false() = - testScope.runTest { assertThat(underTest.isCommunalEnabled.value).isFalse() } - - @Test - fun isCommunalAvailable_whenStorageUnlock_false() = - testScope.runTest { - val isCommunalAvailable by collectLastValue(underTest.isCommunalAvailable) - - assertThat(isCommunalAvailable).isFalse() - - keyguardRepository.setIsEncryptedOrLockdown(false) - runCurrent() - - assertThat(isCommunalAvailable).isFalse() - } -} 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 8424746f3db5..b65ecf46dcca 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 @@ -21,7 +21,6 @@ import android.app.admin.DevicePolicyManager import android.app.admin.devicePolicyManager import android.content.Intent import android.content.pm.UserInfo -import android.content.res.mainResources import android.os.UserHandle import android.os.UserManager import android.os.userManager @@ -39,9 +38,8 @@ import com.android.systemui.Flags.FLAG_COMMUNAL_WIDGET_RESIZING import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.broadcastDispatcher -import com.android.systemui.common.data.repository.batteryRepository -import com.android.systemui.common.data.repository.fake import com.android.systemui.communal.data.model.CommunalSmartspaceTimer +import com.android.systemui.communal.data.model.SuppressionReason import com.android.systemui.communal.data.repository.fakeCommunalMediaRepository import com.android.systemui.communal.data.repository.fakeCommunalPrefsRepository import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository @@ -50,14 +48,9 @@ import com.android.systemui.communal.data.repository.fakeCommunalTutorialReposit import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.domain.model.CommunalTransitionProgressModel -import com.android.systemui.communal.posturing.data.repository.fake -import com.android.systemui.communal.posturing.data.repository.posturingRepository -import com.android.systemui.communal.posturing.shared.model.PosturedState import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.communal.shared.model.EditModeState -import com.android.systemui.dock.DockManager -import com.android.systemui.dock.fakeDockManager import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.flags.Flags import com.android.systemui.flags.fakeFeatureFlagsClassic @@ -75,19 +68,16 @@ import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.settings.fakeUserTracker import com.android.systemui.statusbar.phone.fakeManagedProfileController import com.android.systemui.testKosmos -import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.whenever -import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.advanceTimeBy -import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -98,10 +88,6 @@ import org.mockito.Mockito.verify import platform.test.runner.parameterized.ParameterizedAndroidJunit4 import platform.test.runner.parameterized.Parameters -/** - * This class of test cases assume that communal is enabled. For disabled cases, see - * [CommunalInteractorCommunalDisabledTest]. - */ @SmallTest @RunWith(ParameterizedAndroidJunit4::class) class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @@ -109,10 +95,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { UserInfo(/* id= */ 0, /* name= */ "primary user", /* flags= */ UserInfo.FLAG_MAIN) private val secondaryUser = UserInfo(/* id= */ 1, /* name= */ "secondary user", /* flags= */ 0) - private val kosmos = - testKosmos() - .apply { mainResources = mContext.orCreateTestableResources.resources } - .useUnconfinedTestDispatcher() + private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val Kosmos.underTest by Kosmos.Fixture { communalInteractor } @@ -128,104 +111,40 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { kosmos.fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, true) mSetFlagsRule.enableFlags(FLAG_COMMUNAL_HUB) - - mContext.orCreateTestableResources.addOverride( - com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault, - false, - ) - mContext.orCreateTestableResources.addOverride( - com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault, - false, - ) - mContext.orCreateTestableResources.addOverride( - com.android.internal.R.bool.config_dreamsActivatedOnPosturedByDefault, - false, - ) - } - - @After - fun tearDown() { - mContext.orCreateTestableResources.removeOverride( - com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault - ) - mContext.orCreateTestableResources.removeOverride( - com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault - ) - mContext.orCreateTestableResources.removeOverride( - com.android.internal.R.bool.config_dreamsActivatedOnPosturedByDefault - ) } @Test fun communalEnabled_true() = kosmos.runTest { - fakeUserRepository.setSelectedUserInfo(mainUser) + communalSettingsInteractor.setSuppressionReasons(emptyList()) assertThat(underTest.isCommunalEnabled.value).isTrue() } @Test - fun isCommunalAvailable_mainUserUnlockedAndMainUser_true() = + fun isCommunalAvailable_whenKeyguardShowing_true() = kosmos.runTest { - val isAvailable by collectLastValue(underTest.isCommunalAvailable) - assertThat(isAvailable).isFalse() - - fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, true) - fakeUserRepository.setSelectedUserInfo(mainUser) - fakeKeyguardRepository.setKeyguardShowing(true) - - assertThat(isAvailable).isTrue() - } + communalSettingsInteractor.setSuppressionReasons(emptyList()) + fakeKeyguardRepository.setKeyguardShowing(false) - @Test - fun isCommunalAvailable_mainUserLockedAndMainUser_false() = - kosmos.runTest { val isAvailable by collectLastValue(underTest.isCommunalAvailable) assertThat(isAvailable).isFalse() - fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, false) - fakeUserRepository.setSelectedUserInfo(mainUser) fakeKeyguardRepository.setKeyguardShowing(true) - - assertThat(isAvailable).isFalse() + assertThat(isAvailable).isTrue() } @Test - fun isCommunalAvailable_mainUserUnlockedAndSecondaryUser_false() = + fun isCommunalAvailable_suppressed() = kosmos.runTest { - val isAvailable by collectLastValue(underTest.isCommunalAvailable) - assertThat(isAvailable).isFalse() - - fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, true) - fakeUserRepository.setSelectedUserInfo(secondaryUser) + communalSettingsInteractor.setSuppressionReasons(emptyList()) fakeKeyguardRepository.setKeyguardShowing(true) - assertThat(isAvailable).isFalse() - } - - @Test - fun isCommunalAvailable_whenKeyguardShowing_true() = - kosmos.runTest { val isAvailable by collectLastValue(underTest.isCommunalAvailable) - assertThat(isAvailable).isFalse() - - fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, true) - fakeUserRepository.setSelectedUserInfo(mainUser) - fakeKeyguardRepository.setKeyguardShowing(true) - assertThat(isAvailable).isTrue() - } - - @Test - fun isCommunalAvailable_communalDisabled_false() = - kosmos.runTest { - mSetFlagsRule.disableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2) - val isAvailable by collectLastValue(underTest.isCommunalAvailable) - assertThat(isAvailable).isFalse() - - fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, false) - fakeUserRepository.setSelectedUserInfo(mainUser) - fakeKeyguardRepository.setKeyguardShowing(true) + communalSettingsInteractor.setSuppressionReasons( + listOf(SuppressionReason.ReasonUnknown()) + ) assertThat(isAvailable).isFalse() } @@ -1280,66 +1199,6 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { .inOrder() } - @Test - fun showCommunalWhileCharging() = - kosmos.runTest { - fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, true) - fakeUserRepository.setSelectedUserInfo(mainUser) - fakeKeyguardRepository.setKeyguardShowing(true) - fakeSettings.putIntForUser( - Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, - 1, - mainUser.id, - ) - - val shouldShowCommunal by collectLastValue(underTest.shouldShowCommunal) - batteryRepository.fake.setDevicePluggedIn(false) - assertThat(shouldShowCommunal).isFalse() - - batteryRepository.fake.setDevicePluggedIn(true) - assertThat(shouldShowCommunal).isTrue() - } - - @Test - fun showCommunalWhilePosturedAndCharging() = - kosmos.runTest { - fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, true) - fakeUserRepository.setSelectedUserInfo(mainUser) - fakeKeyguardRepository.setKeyguardShowing(true) - fakeSettings.putIntForUser( - Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED, - 1, - mainUser.id, - ) - - val shouldShowCommunal by collectLastValue(underTest.shouldShowCommunal) - batteryRepository.fake.setDevicePluggedIn(true) - posturingRepository.fake.setPosturedState(PosturedState.NotPostured) - assertThat(shouldShowCommunal).isFalse() - - posturingRepository.fake.setPosturedState(PosturedState.Postured(1f)) - assertThat(shouldShowCommunal).isTrue() - } - - @Test - fun showCommunalWhileDocked() = - kosmos.runTest { - fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, true) - fakeUserRepository.setSelectedUserInfo(mainUser) - fakeKeyguardRepository.setKeyguardShowing(true) - fakeSettings.putIntForUser(Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, 1, mainUser.id) - - batteryRepository.fake.setDevicePluggedIn(true) - fakeDockManager.setIsDocked(false) - - val shouldShowCommunal by collectLastValue(underTest.shouldShowCommunal) - assertThat(shouldShowCommunal).isFalse() - - fakeDockManager.setIsDocked(true) - fakeDockManager.setDockEvent(DockManager.STATE_DOCKED) - assertThat(shouldShowCommunal).isTrue() - } - private fun setKeyguardFeaturesDisabled(user: UserInfo, disabledFlags: Int) { whenever(kosmos.devicePolicyManager.getKeyguardDisabledFeatures(nullable(), eq(user.id))) .thenReturn(disabledFlags) 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 8dc7a331dc2d..b8dbc9f77076 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 @@ -32,9 +32,9 @@ import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_DIRECT_EDIT_MODE import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 import com.android.systemui.SysuiTestCase import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository -import com.android.systemui.common.data.repository.batteryRepository -import com.android.systemui.common.data.repository.fake import com.android.systemui.communal.data.model.CommunalSmartspaceTimer +import com.android.systemui.communal.data.model.FEATURE_MANUAL_OPEN +import com.android.systemui.communal.data.model.SuppressionReason import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository import com.android.systemui.communal.data.repository.FakeCommunalSmartspaceRepository @@ -50,6 +50,7 @@ import com.android.systemui.communal.domain.interactor.communalInteractor import com.android.systemui.communal.domain.interactor.communalSceneInteractor import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.communal.domain.interactor.communalTutorialInteractor +import com.android.systemui.communal.domain.interactor.setCommunalEnabled import com.android.systemui.communal.domain.interactor.setCommunalV2ConfigEnabled import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.shared.log.CommunalMetricsLogger @@ -101,7 +102,6 @@ import com.android.systemui.statusbar.KeyguardIndicationController import com.android.systemui.testKosmos import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.data.repository.fakeUserRepository -import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.advanceTimeBy @@ -128,7 +128,9 @@ import platform.test.runner.parameterized.Parameters @RunWith(ParameterizedAndroidJunit4::class) class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { @Mock private lateinit var mediaHost: MediaHost + @Mock private lateinit var mediaCarouselScrollHandler: MediaCarouselScrollHandler + @Mock private lateinit var metricsLogger: CommunalMetricsLogger private val kosmos = testKosmos() @@ -212,11 +214,8 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun tutorial_tutorialNotCompletedAndKeyguardVisible_showTutorialContent() = testScope.runTest { - // Keyguard showing, storage unlocked, main user, and tutorial not started. keyguardRepository.setKeyguardShowing(true) - keyguardRepository.setKeyguardOccluded(false) - userRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, true) - setIsMainUser(true) + kosmos.setCommunalEnabled(true) tutorialRepository.setTutorialSettingState( Settings.Secure.HUB_MODE_TUTORIAL_NOT_STARTED ) @@ -951,21 +950,16 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { fun swipeToCommunal() = kosmos.runTest { setCommunalV2ConfigEnabled(true) - val mainUser = fakeUserRepository.asMainUser() - fakeKeyguardRepository.setKeyguardShowing(true) - fakeUserRepository.setUserUnlocked(mainUser.id, true) - fakeUserTracker.set(userInfos = listOf(mainUser), selectedUserIndex = 0) - fakeSettings.putIntForUser( - Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, - 1, - mainUser.id, + // Suppress manual opening + communalSettingsInteractor.setSuppressionReasons( + listOf(SuppressionReason.ReasonUnknown(FEATURE_MANUAL_OPEN)) ) val viewModel = createViewModel() val swipeToHubEnabled by collectLastValue(viewModel.swipeToHubEnabled) assertThat(swipeToHubEnabled).isFalse() - batteryRepository.fake.setDevicePluggedIn(true) + communalSettingsInteractor.setSuppressionReasons(emptyList()) assertThat(swipeToHubEnabled).isTrue() keyguardTransitionRepository.sendTransitionStep( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt index c15f797aad5d..df10d058c5d1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt @@ -17,7 +17,6 @@ package com.android.systemui.communal.widgets import android.content.pm.UserInfo -import android.provider.Settings import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags.FLAG_COMMUNAL_HUB @@ -25,6 +24,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository import com.android.systemui.communal.domain.interactor.communalInteractor import com.android.systemui.communal.domain.interactor.communalSettingsInteractor +import com.android.systemui.communal.domain.interactor.setCommunalEnabled import com.android.systemui.communal.shared.model.FakeGlanceableHubMultiUserHelper import com.android.systemui.communal.shared.model.fakeGlanceableHubMultiUserHelper import com.android.systemui.coroutines.collectLastValue @@ -37,11 +37,9 @@ import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.settings.fakeUserTracker import com.android.systemui.testKosmos -import com.android.systemui.user.data.repository.FakeUserRepository.Companion.MAIN_USER_ID import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.user.domain.interactor.userLockedInteractor import com.android.systemui.util.mockito.whenever -import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.test.runCurrent @@ -282,22 +280,12 @@ class CommunalAppWidgetHostStartableTest : SysuiTestCase() { } } - private suspend fun setCommunalAvailable( - available: Boolean, - setKeyguardShowing: Boolean = true, - ) = + private fun setCommunalAvailable(available: Boolean, setKeyguardShowing: Boolean = true) = with(kosmos) { - fakeUserRepository.setUserUnlocked(MAIN_USER_ID, true) - fakeUserRepository.setSelectedUserInfo(MAIN_USER_INFO) + setCommunalEnabled(available) if (setKeyguardShowing) { fakeKeyguardRepository.setKeyguardShowing(true) } - val settingsValue = if (available) 1 else 0 - fakeSettings.putIntForUser( - Settings.Secure.GLANCEABLE_HUB_ENABLED, - settingsValue, - MAIN_USER_INFO.id, - ) } private companion object { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt index 6c4325adced4..2ab36501d87d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt @@ -35,7 +35,6 @@ package com.android.systemui.keyguard.domain.interactor import android.os.PowerManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags -import android.provider.Settings import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags @@ -43,8 +42,6 @@ import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 import com.android.systemui.SysuiTestCase import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository -import com.android.systemui.common.data.repository.batteryRepository -import com.android.systemui.common.data.repository.fake import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository import com.android.systemui.communal.domain.interactor.communalSceneInteractor import com.android.systemui.communal.domain.interactor.setCommunalV2Available @@ -72,7 +69,6 @@ import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor import com.android.systemui.testKosmos -import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth import junit.framework.Assert.assertEquals import kotlinx.coroutines.runBlocking @@ -433,9 +429,7 @@ class FromAodTransitionInteractorTest : SysuiTestCase() { @EnableFlags(FLAG_GLANCEABLE_HUB_V2) fun testTransitionToGlanceableHub_onWakeUpFromAod() = kosmos.runTest { - val user = setCommunalV2Available(true) - fakeSettings.putIntForUser(Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1, user.id) - batteryRepository.fake.setDevicePluggedIn(true) + setCommunalV2Available(true) val currentScene by collectLastValue(communalSceneInteractor.currentScene) fakeCommunalSceneRepository.changeScene(CommunalScenes.Blank) @@ -449,4 +443,24 @@ class FromAodTransitionInteractorTest : SysuiTestCase() { Truth.assertThat(currentScene).isEqualTo(CommunalScenes.Communal) assertThat(transitionRepository).noTransitionsStarted() } + + @Test + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) + fun testDoNotTransitionToGlanceableHub_onWakeUpFromAodDueToMotion() = + kosmos.runTest { + setCommunalV2Available(true) + + val currentScene by collectLastValue(communalSceneInteractor.currentScene) + fakeCommunalSceneRepository.changeScene(CommunalScenes.Blank) + + // Communal is not showing + Truth.assertThat(currentScene).isEqualTo(CommunalScenes.Blank) + + powerInteractor.setAwakeForTest(reason = PowerManager.WAKE_REASON_LIFT) + testScope.advanceTimeBy(100) // account for debouncing + + Truth.assertThat(currentScene).isEqualTo(CommunalScenes.Blank) + assertThat(transitionRepository) + .startedTransition(from = KeyguardState.AOD, to = KeyguardState.LOCKSCREEN) + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt index 9be786fab34d..c3d18a3d893c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt @@ -20,7 +20,6 @@ import android.os.PowerManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization -import android.provider.Settings import android.service.dream.dreamManager import androidx.test.filters.SmallTest import com.android.compose.animation.scene.ObservableTransitionState @@ -30,8 +29,6 @@ import com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR import com.android.systemui.Flags.FLAG_SCENE_CONTAINER import com.android.systemui.Flags.glanceableHubV2 import com.android.systemui.SysuiTestCase -import com.android.systemui.common.data.repository.batteryRepository -import com.android.systemui.common.data.repository.fake import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository import com.android.systemui.communal.data.repository.communalSceneRepository import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository @@ -61,8 +58,6 @@ import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.se import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.testKosmos -import com.android.systemui.user.data.repository.fakeUserRepository -import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth import junit.framework.Assert.assertEquals import kotlinx.coroutines.flow.flowOf @@ -171,15 +166,7 @@ class FromDozingTransitionInteractorTest(flags: FlagsParameterization?) : SysuiT fun testTransitionToLockscreen_onWake_canDream_ktfRefactor() = kosmos.runTest { setCommunalAvailable(true) - if (glanceableHubV2()) { - val user = fakeUserRepository.asMainUser() - fakeSettings.putIntForUser( - Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, - 1, - user.id, - ) - batteryRepository.fake.setDevicePluggedIn(true) - } else { + if (!glanceableHubV2()) { whenever(dreamManager.canStartDreaming(anyBoolean())).thenReturn(true) } @@ -193,6 +180,7 @@ class FromDozingTransitionInteractorTest(flags: FlagsParameterization?) : SysuiT @Test @EnableFlags(FLAG_KEYGUARD_WM_STATE_REFACTOR) + @DisableFlags(FLAG_GLANCEABLE_HUB_V2) fun testTransitionToLockscreen_onWake_canNotDream_glanceableHubAvailable() = kosmos.runTest { whenever(dreamManager.canStartDreaming(anyBoolean())).thenReturn(false) @@ -225,15 +213,7 @@ class FromDozingTransitionInteractorTest(flags: FlagsParameterization?) : SysuiT fun testTransitionToGlanceableHub_onWakeup_ifAvailable() = kosmos.runTest { setCommunalAvailable(true) - if (glanceableHubV2()) { - val user = fakeUserRepository.asMainUser() - fakeSettings.putIntForUser( - Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, - 1, - user.id, - ) - batteryRepository.fake.setDevicePluggedIn(true) - } else { + if (!glanceableHubV2()) { whenever(dreamManager.canStartDreaming(anyBoolean())).thenReturn(true) } @@ -249,6 +229,25 @@ class FromDozingTransitionInteractorTest(flags: FlagsParameterization?) : SysuiT } @Test + @DisableFlags(FLAG_KEYGUARD_WM_STATE_REFACTOR, FLAG_SCENE_CONTAINER) + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) + fun testTransitionToLockscreen_onWakeupFromLift() = + kosmos.runTest { + setCommunalAvailable(true) + if (!glanceableHubV2()) { + whenever(dreamManager.canStartDreaming(anyBoolean())).thenReturn(true) + } + + // Device turns on. + powerInteractor.setAwakeForTest(reason = PowerManager.WAKE_REASON_LIFT) + testScope.advanceTimeBy(51L) + + // We transition to the lockscreen instead of the hub. + assertThat(transitionRepository) + .startedTransition(from = KeyguardState.DOZING, to = KeyguardState.LOCKSCREEN) + } + + @Test @EnableFlags(FLAG_KEYGUARD_WM_STATE_REFACTOR) fun testTransitionToOccluded_onWakeup_whenOccludingActivityOnTop() = kosmos.runTest { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractorTest.kt index e203a276a2f2..1dddfc1bba9c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractorTest.kt @@ -18,11 +18,17 @@ package com.android.systemui.keyguard.domain.interactor import android.content.Intent +import android.os.PowerManager +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.SetFlagsRule +import android.provider.Settings import android.view.accessibility.accessibilityManagerWrapper import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.logging.testing.UiEventLoggerFake import com.android.internal.logging.uiEventLogger +import com.android.systemui.Flags.FLAG_DOUBLE_TAP_TO_SLEEP import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInteractor @@ -39,6 +45,8 @@ import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper import com.android.systemui.testKosmos import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.settings.data.repository.userAwareSecureSettingsRepository +import com.android.systemui.util.time.fakeSystemClock import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.advanceTimeBy @@ -46,14 +54,19 @@ import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.After import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Mock import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyLong +import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidJUnit4::class) +@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) class KeyguardTouchHandlingInteractorTest : SysuiTestCase() { private val kosmos = testKosmos().apply { @@ -61,17 +74,23 @@ class KeyguardTouchHandlingInteractorTest : SysuiTestCase() { this.uiEventLogger = mock<UiEventLoggerFake>() } + @get:Rule val setFlagsRule = SetFlagsRule() + private lateinit var underTest: KeyguardTouchHandlingInteractor private val logger = kosmos.uiEventLogger private val testScope = kosmos.testScope private val keyguardRepository = kosmos.fakeKeyguardRepository private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + private val secureSettingsRepository = kosmos.userAwareSecureSettingsRepository + + @Mock private lateinit var powerManager: PowerManager @Before fun setUp() { MockitoAnnotations.initMocks(this) overrideResource(R.bool.long_press_keyguard_customize_lockscreen_enabled, true) + overrideResource(com.android.internal.R.bool.config_supportDoubleTapSleep, true) whenever(kosmos.accessibilityManagerWrapper.getRecommendedTimeoutMillis(anyInt(), anyInt())) .thenAnswer { it.arguments[0] } @@ -80,13 +99,13 @@ class KeyguardTouchHandlingInteractorTest : SysuiTestCase() { @After fun tearDown() { - mContext - .getOrCreateTestableResources() - .removeOverride(R.bool.long_press_keyguard_customize_lockscreen_enabled) + val testableResource = mContext.getOrCreateTestableResources() + testableResource.removeOverride(R.bool.long_press_keyguard_customize_lockscreen_enabled) + testableResource.removeOverride(com.android.internal.R.bool.config_supportDoubleTapSleep) } @Test - fun isEnabled() = + fun isLongPressEnabled() = testScope.runTest { val isEnabled = collectLastValue(underTest.isLongPressHandlingEnabled) KeyguardState.values().forEach { keyguardState -> @@ -101,7 +120,7 @@ class KeyguardTouchHandlingInteractorTest : SysuiTestCase() { } @Test - fun isEnabled_alwaysFalseWhenQuickSettingsAreVisible() = + fun isLongPressEnabled_alwaysFalseWhenQuickSettingsAreVisible() = testScope.runTest { val isEnabled = collectLastValue(underTest.isLongPressHandlingEnabled) KeyguardState.values().forEach { keyguardState -> @@ -112,7 +131,7 @@ class KeyguardTouchHandlingInteractorTest : SysuiTestCase() { } @Test - fun isEnabled_alwaysFalseWhenConfigEnabledBooleanIsFalse() = + fun isLongPressEnabled_alwaysFalseWhenConfigEnabledBooleanIsFalse() = testScope.runTest { overrideResource(R.bool.long_press_keyguard_customize_lockscreen_enabled, false) createUnderTest() @@ -294,6 +313,119 @@ class KeyguardTouchHandlingInteractorTest : SysuiTestCase() { assertThat(isMenuVisible).isFalse() } + @Test + @EnableFlags(FLAG_DOUBLE_TAP_TO_SLEEP) + fun isDoubleTapEnabled_flagEnabled_userSettingEnabled_onlyTrueInLockScreenState() { + testScope.runTest { + secureSettingsRepository.setBoolean(Settings.Secure.DOUBLE_TAP_TO_SLEEP, true) + + val isEnabled = collectLastValue(underTest.isDoubleTapHandlingEnabled) + KeyguardState.entries.forEach { keyguardState -> + setUpState(keyguardState = keyguardState) + + if (keyguardState == KeyguardState.LOCKSCREEN) { + assertThat(isEnabled()).isTrue() + } else { + assertThat(isEnabled()).isFalse() + } + } + } + } + + @Test + @EnableFlags(FLAG_DOUBLE_TAP_TO_SLEEP) + fun isDoubleTapEnabled_flagEnabled_userSettingDisabled_alwaysFalse() { + testScope.runTest { + secureSettingsRepository.setBoolean(Settings.Secure.DOUBLE_TAP_TO_SLEEP, false) + + val isEnabled = collectLastValue(underTest.isDoubleTapHandlingEnabled) + KeyguardState.entries.forEach { keyguardState -> + setUpState(keyguardState = keyguardState) + + assertThat(isEnabled()).isFalse() + } + } + } + + @Test + @DisableFlags(FLAG_DOUBLE_TAP_TO_SLEEP) + fun isDoubleTapEnabled_flagDisabled_userSettingEnabled_alwaysFalse() { + testScope.runTest { + secureSettingsRepository.setBoolean(Settings.Secure.DOUBLE_TAP_TO_SLEEP, true) + + val isEnabled = collectLastValue(underTest.isDoubleTapHandlingEnabled) + KeyguardState.entries.forEach { keyguardState -> + setUpState(keyguardState = keyguardState) + + assertThat(isEnabled()).isFalse() + } + } + } + + + + @Test + @EnableFlags(FLAG_DOUBLE_TAP_TO_SLEEP) + fun isDoubleTapEnabled_flagEnabledAndConfigDisabled_alwaysFalse() { + testScope.runTest { + secureSettingsRepository.setBoolean(Settings.Secure.DOUBLE_TAP_TO_SLEEP, true) + overrideResource(com.android.internal.R.bool.config_supportDoubleTapSleep, false) + createUnderTest() + + val isEnabled = collectLastValue(underTest.isDoubleTapHandlingEnabled) + KeyguardState.entries.forEach { keyguardState -> + setUpState(keyguardState = keyguardState) + + assertThat(isEnabled()).isFalse() + } + } + } + + @Test + @EnableFlags(FLAG_DOUBLE_TAP_TO_SLEEP) + fun isDoubleTapEnabled_quickSettingsVisible_alwaysFalse() { + testScope.runTest { + secureSettingsRepository.setBoolean(Settings.Secure.DOUBLE_TAP_TO_SLEEP, true) + + val isEnabled = collectLastValue(underTest.isDoubleTapHandlingEnabled) + KeyguardState.entries.forEach { keyguardState -> + setUpState(keyguardState = keyguardState, isQuickSettingsVisible = true) + + assertThat(isEnabled()).isFalse() + } + } + } + + @Test + @EnableFlags(FLAG_DOUBLE_TAP_TO_SLEEP) + fun onDoubleClick_doubleTapEnabled() { + testScope.runTest { + secureSettingsRepository.setBoolean(Settings.Secure.DOUBLE_TAP_TO_SLEEP, true) + val isEnabled by collectLastValue(underTest.isDoubleTapHandlingEnabled) + runCurrent() + + underTest.onDoubleClick() + + assertThat(isEnabled).isTrue() + verify(powerManager).goToSleep(anyLong()) + } + } + + @Test + @EnableFlags(FLAG_DOUBLE_TAP_TO_SLEEP) + fun onDoubleClick_doubleTapDisabled() { + testScope.runTest { + secureSettingsRepository.setBoolean(Settings.Secure.DOUBLE_TAP_TO_SLEEP, false) + val isEnabled by collectLastValue(underTest.isDoubleTapHandlingEnabled) + runCurrent() + + underTest.onDoubleClick() + + assertThat(isEnabled).isFalse() + verify(powerManager, never()).goToSleep(anyLong()) + } + } + private suspend fun createUnderTest(isRevampedWppFeatureEnabled: Boolean = true) { // This needs to be re-created for each test outside of kosmos since the flag values are // read during initialization to set up flows. Maybe there is a better way to handle that. @@ -309,6 +441,9 @@ class KeyguardTouchHandlingInteractorTest : SysuiTestCase() { accessibilityManager = kosmos.accessibilityManagerWrapper, pulsingGestureListener = kosmos.pulsingGestureListener, faceAuthInteractor = kosmos.deviceEntryFaceAuthInteractor, + secureSettingsRepository = secureSettingsRepository, + powerManager = powerManager, + systemClock = kosmos.fakeSystemClock, ) setUpState() } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt index 8df70ef0fd2e..7d5e9a5ed178 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt @@ -33,7 +33,7 @@ import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepositor import com.android.systemui.communal.domain.interactor.CommunalSceneTransitionInteractor import com.android.systemui.communal.domain.interactor.communalSceneInteractor import com.android.systemui.communal.domain.interactor.communalSceneTransitionInteractor -import com.android.systemui.communal.domain.interactor.setCommunalAvailable +import com.android.systemui.communal.domain.interactor.setCommunalV2Available import com.android.systemui.communal.domain.interactor.setCommunalV2ConfigEnabled import com.android.systemui.communal.domain.interactor.setCommunalV2Enabled import com.android.systemui.communal.shared.model.CommunalScenes @@ -1004,16 +1004,15 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest @BrokenWithSceneContainer(339465026) fun occludedToGlanceableHub_communalKtfRefactor() = testScope.runTest { - // GIVEN a device on lockscreen and communal is available - keyguardRepository.setKeyguardShowing(true) - kosmos.setCommunalAvailable(true) - runCurrent() - // GIVEN a prior transition has run to OCCLUDED from GLANCEABLE_HUB runTransitionAndSetWakefulness(KeyguardState.GLANCEABLE_HUB, KeyguardState.OCCLUDED) keyguardRepository.setKeyguardOccluded(true) runCurrent() + // GIVEN a device on lockscreen and communal is available + kosmos.setCommunalV2Available(true) + runCurrent() + // WHEN occlusion ends keyguardRepository.setKeyguardOccluded(false) runCurrent() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUIStateDispatcherTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUIStateDispatcherTest.kt index b82f5fce9e14..ff2e13b51e14 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUIStateDispatcherTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUIStateDispatcherTest.kt @@ -81,7 +81,7 @@ class SysUIStateDispatcherTest : SysuiTestCase() { private companion object { const val DISPLAY_1 = 1 const val DISPLAY_2 = 2 - const val FLAG_1 = 10L - const val FLAG_2 = 20L + const val FLAG_1 = 1L + const val FLAG_2 = 2L } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateExtTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateExtTest.kt index 09588f9f3751..d1b552906fbb 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateExtTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateExtTest.kt @@ -35,10 +35,10 @@ class SysUiStateExtTest : SysuiTestCase() { @Test fun updateFlags() { - underTest.updateFlags(Display.DEFAULT_DISPLAY, 1L to true, 2L to false, 3L to true) + underTest.updateFlags(Display.DEFAULT_DISPLAY, 1L to true, 2L to false, 4L to true) assertThat(underTest.flags and 1L).isNotEqualTo(0L) assertThat(underTest.flags and 2L).isEqualTo(0L) - assertThat(underTest.flags and 3L).isNotEqualTo(0L) + assertThat(underTest.flags and 4L).isNotEqualTo(0L) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt index e3fe24ca37c1..abecf33f611e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt @@ -46,12 +46,14 @@ import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsMode import com.android.systemui.statusbar.sysuiStatusBarStateController import com.android.systemui.util.animation.DisappearParameters import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.whenever +@OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) @RunWithLooper @@ -457,6 +459,20 @@ class QSFragmentComposeViewModelTest : AbstractQSFragmentComposeViewModelTest() } } + @Test + fun isEditing() = + with(kosmos) { + testScope.testWithinLifecycle { + underTest.containerViewModel.editModeViewModel.startEditing() + runCurrent() + assertThat(underTest.isEditing).isTrue() + + underTest.containerViewModel.editModeViewModel.stopEditing() + runCurrent() + assertThat(underTest.isEditing).isFalse() + } + } + private fun TestScope.setMediaState(state: MediaState) { with(kosmos) { val activeMedia = state == ACTIVE_MEDIA diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelTest.kt index 68a591dd075f..1d42424bc6ed 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelTest.kt @@ -16,11 +16,9 @@ package com.android.systemui.qs.panels.ui.viewmodel - import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.testScope import com.android.systemui.qs.FakeQSTile import com.android.systemui.qs.pipeline.data.repository.tileSpecRepository @@ -48,45 +46,43 @@ class DetailsViewModelTest : SysuiTestCase() { } @Test - fun changeTileDetailsViewModel() = with(kosmos) { - testScope.runTest { - val specs = listOf( - spec, - specNoDetails, - ) - tileSpecRepository.setTiles(0, specs) - runCurrent() + fun changeTileDetailsViewModel() = + with(kosmos) { + testScope.runTest { + val specs = listOf(spec, specNoDetails) + tileSpecRepository.setTiles(0, specs) + runCurrent() - val tiles = currentTilesInteractor.currentTiles.value + val tiles = currentTilesInteractor.currentTiles.value - assertThat(currentTilesInteractor.currentTilesSpecs.size).isEqualTo(2) - assertThat(tiles[1].spec).isEqualTo(specNoDetails) - (tiles[1].tile as FakeQSTile).hasDetailsViewModel = false + assertThat(currentTilesInteractor.currentTilesSpecs.size).isEqualTo(2) + assertThat(tiles[1].spec).isEqualTo(specNoDetails) + (tiles[1].tile as FakeQSTile).hasDetailsViewModel = false - assertThat(underTest.activeTileDetails).isNull() + assertThat(underTest.activeTileDetails).isNull() - // Click on the tile who has the `spec`. - assertThat(underTest.onTileClicked(spec)).isTrue() - assertThat(underTest.activeTileDetails).isNotNull() - assertThat(underTest.activeTileDetails?.getTitle()).isEqualTo("internet") + // Click on the tile who has the `spec`. + assertThat(underTest.onTileClicked(spec)).isTrue() + assertThat(underTest.activeTileDetails).isNotNull() + assertThat(underTest.activeTileDetails?.title).isEqualTo("internet") - // Click on a tile who dose not have a valid spec. - assertThat(underTest.onTileClicked(null)).isFalse() - assertThat(underTest.activeTileDetails).isNull() + // Click on a tile who dose not have a valid spec. + assertThat(underTest.onTileClicked(null)).isFalse() + assertThat(underTest.activeTileDetails).isNull() - // Click again on the tile who has the `spec`. - assertThat(underTest.onTileClicked(spec)).isTrue() - assertThat(underTest.activeTileDetails).isNotNull() - assertThat(underTest.activeTileDetails?.getTitle()).isEqualTo("internet") + // Click again on the tile who has the `spec`. + assertThat(underTest.onTileClicked(spec)).isTrue() + assertThat(underTest.activeTileDetails).isNotNull() + assertThat(underTest.activeTileDetails?.title).isEqualTo("internet") - // Click on a tile who dose not have a detailed view. - assertThat(underTest.onTileClicked(specNoDetails)).isFalse() - assertThat(underTest.activeTileDetails).isNull() + // Click on a tile who dose not have a detailed view. + assertThat(underTest.onTileClicked(specNoDetails)).isFalse() + assertThat(underTest.activeTileDetails).isNull() - underTest.closeDetailedView() - assertThat(underTest.activeTileDetails).isNull() + underTest.closeDetailedView() + assertThat(underTest.activeTileDetails).isNull() - assertThat(underTest.onTileClicked(null)).isFalse() + assertThat(underTest.onTileClicked(null)).isFalse() + } } - } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt index c3089761effc..5bde7ad27b7a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt @@ -691,11 +691,11 @@ class CurrentTilesInteractorImplTest : SysuiTestCase() { var currentModel: TileDetailsViewModel? = null val setCurrentModel = { model: TileDetailsViewModel? -> currentModel = model } tiles!![0].tile.getDetailsViewModel(setCurrentModel) - assertThat(currentModel?.getTitle()).isEqualTo("a") + assertThat(currentModel?.title).isEqualTo("a") currentModel = null tiles!![1].tile.getDetailsViewModel(setCurrentModel) - assertThat(currentModel?.getTitle()).isEqualTo("b") + assertThat(currentModel?.title).isEqualTo("b") currentModel = null tiles!![2].tile.getDetailsViewModel(setCurrentModel) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ModesDndTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ModesDndTileTest.kt new file mode 100644 index 000000000000..1adba6fcd45d --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ModesDndTileTest.kt @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2025 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.tiles + +import android.app.Flags +import android.os.Handler +import android.platform.test.annotations.EnableFlags +import android.service.quicksettings.Tile +import android.testing.TestableLooper +import android.testing.TestableLooper.RunWithLooper +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.internal.logging.MetricsLogger +import com.android.settingslib.notification.modes.TestModeBuilder +import com.android.systemui.SysuiTestCase +import com.android.systemui.classifier.FalsingManagerFake +import com.android.systemui.kosmos.mainCoroutineContext +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.kosmos.testScope +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.qs.shared.QSSettingsPackageRepository +import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler +import com.android.systemui.qs.tiles.impl.modes.domain.interactor.ModesDndTileDataInteractor +import com.android.systemui.qs.tiles.impl.modes.domain.interactor.ModesDndTileUserActionInteractor +import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesDndTileModel +import com.android.systemui.qs.tiles.impl.modes.ui.ModesDndTileMapper +import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProvider +import com.android.systemui.qs.tiles.viewmodel.QSTileConfigTestBuilder +import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig +import com.android.systemui.res.R +import com.android.systemui.statusbar.policy.data.repository.zenModeRepository +import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor +import com.android.systemui.statusbar.policy.ui.dialog.ModesDialogDelegate +import com.android.systemui.statusbar.policy.ui.dialog.modesDialogEventLogger +import com.android.systemui.testKosmos +import com.android.systemui.util.mockito.any +import com.android.systemui.util.settings.FakeSettings +import com.android.systemui.util.settings.SecureSettings +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.MockitoAnnotations +import org.mockito.kotlin.whenever + +@EnableFlags(Flags.FLAG_MODES_UI) +@SmallTest +@RunWith(AndroidJUnit4::class) +@RunWithLooper(setAsMainLooper = true) +class ModesDndTileTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val testDispatcher = kosmos.testDispatcher + + @Mock private lateinit var qsHost: QSHost + + @Mock private lateinit var metricsLogger: MetricsLogger + + @Mock private lateinit var statusBarStateController: StatusBarStateController + + @Mock private lateinit var activityStarter: ActivityStarter + + @Mock private lateinit var qsLogger: QSLogger + + @Mock private lateinit var uiEventLogger: QsEventLogger + + @Mock private lateinit var qsTileConfigProvider: QSTileConfigProvider + + @Mock private lateinit var dialogDelegate: ModesDialogDelegate + + @Mock private lateinit var settingsPackageRepository: QSSettingsPackageRepository + + private val inputHandler = FakeQSTileIntentUserInputHandler() + private val zenModeRepository = kosmos.zenModeRepository + private val tileDataInteractor = + ModesDndTileDataInteractor(context, kosmos.zenModeInteractor, testDispatcher) + private val mapper = ModesDndTileMapper(context.resources, context.theme) + + private lateinit var userActionInteractor: ModesDndTileUserActionInteractor + private lateinit var secureSettings: SecureSettings + private lateinit var testableLooper: TestableLooper + private lateinit var underTest: ModesDndTile + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + testableLooper = TestableLooper.get(this) + secureSettings = FakeSettings() + + // Allow the tile to load resources + whenever(qsHost.context).thenReturn(context) + whenever(qsHost.userContext).thenReturn(context) + + whenever(qsTileConfigProvider.getConfig(any())) + .thenReturn( + QSTileConfigTestBuilder.build { + uiConfig = + QSTileUIConfig.Resource( + iconRes = R.drawable.qs_dnd_icon_off, + labelRes = R.string.quick_settings_dnd_label, + ) + } + ) + + userActionInteractor = + ModesDndTileUserActionInteractor( + kosmos.mainCoroutineContext, + inputHandler, + dialogDelegate, + kosmos.zenModeInteractor, + kosmos.modesDialogEventLogger, + settingsPackageRepository, + ) + + underTest = + ModesDndTile( + qsHost, + uiEventLogger, + testableLooper.looper, + Handler(testableLooper.looper), + FalsingManagerFake(), + metricsLogger, + statusBarStateController, + activityStarter, + qsLogger, + qsTileConfigProvider, + tileDataInteractor, + mapper, + userActionInteractor, + ) + + underTest.initialize() + underTest.setListening(Object(), true) + + testableLooper.processAllMessages() + } + + @After + fun tearDown() { + underTest.destroy() + testableLooper.processAllMessages() + } + + @Test + fun stateUpdatesOnChange() = + testScope.runTest { + assertThat(underTest.state.state).isEqualTo(Tile.STATE_INACTIVE) + + zenModeRepository.activateMode(TestModeBuilder.MANUAL_DND) + runCurrent() + testableLooper.processAllMessages() + + assertThat(underTest.state.state).isEqualTo(Tile.STATE_ACTIVE) + } + + @Test + fun handleUpdateState_withModel_updatesState() = + testScope.runTest { + val tileState = + BooleanState().apply { + state = Tile.STATE_INACTIVE + secondaryLabel = "Old secondary label" + } + val model = ModesDndTileModel(isActivated = true) + + underTest.handleUpdateState(tileState, model) + + assertThat(tileState.state).isEqualTo(Tile.STATE_ACTIVE) + assertThat(tileState.secondaryLabel).isEqualTo("On") + } + + @Test + fun handleUpdateState_withNull_updatesState() = + testScope.runTest { + val tileState = + BooleanState().apply { + state = Tile.STATE_INACTIVE + secondaryLabel = "Old secondary label" + } + zenModeRepository.activateMode(TestModeBuilder.MANUAL_DND) + runCurrent() + + underTest.handleUpdateState(tileState, null) + + assertThat(tileState.state).isEqualTo(Tile.STATE_ACTIVE) + assertThat(tileState.secondaryLabel).isEqualTo("On") + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesDndTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesDndTileDataInteractorTest.kt new file mode 100644 index 000000000000..23d7b86df875 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesDndTileDataInteractorTest.kt @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2025 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.tiles.impl.modes.domain.interactor + +import android.app.Flags +import android.os.UserHandle +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.settingslib.notification.modes.TestModeBuilder +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.kosmos.testScope +import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger +import com.android.systemui.statusbar.policy.data.repository.fakeZenModeRepository +import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.toCollection +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@EnableFlags(Flags.FLAG_MODES_UI) +@RunWith(AndroidJUnit4::class) +class ModesDndTileDataInteractorTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val dispatcher = kosmos.testDispatcher + private val zenModeRepository = kosmos.fakeZenModeRepository + + private val underTest by lazy { + ModesDndTileDataInteractor(context, kosmos.zenModeInteractor, dispatcher) + } + + @Test + @EnableFlags(Flags.FLAG_MODES_UI_DND_TILE) + fun availability_flagOn_isTrue() = + testScope.runTest { + val availability = underTest.availability(TEST_USER).toCollection(mutableListOf()) + + assertThat(availability).containsExactly(true) + } + + @Test + @DisableFlags(Flags.FLAG_MODES_UI_DND_TILE) + fun availability_flagOff_isFalse() = + testScope.runTest { + val availability = underTest.availability(TEST_USER).toCollection(mutableListOf()) + + assertThat(availability).containsExactly(false) + } + + @Test + fun tileData_dndChanges_updateActivated() = + testScope.runTest { + val model by + collectLastValue( + underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest)) + ) + + runCurrent() + assertThat(model!!.isActivated).isFalse() + + zenModeRepository.activateMode(TestModeBuilder.MANUAL_DND) + runCurrent() + assertThat(model!!.isActivated).isTrue() + + zenModeRepository.deactivateMode(TestModeBuilder.MANUAL_DND) + runCurrent() + assertThat(model!!.isActivated).isFalse() + } + + @Test + fun tileData_otherModeChanges_notActivated() = + testScope.runTest { + val model by + collectLastValue( + underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest)) + ) + + runCurrent() + assertThat(model!!.isActivated).isFalse() + + zenModeRepository.addMode("Other mode") + runCurrent() + assertThat(model!!.isActivated).isFalse() + + zenModeRepository.activateMode("Other mode") + runCurrent() + assertThat(model!!.isActivated).isFalse() + } + + private companion object { + val TEST_USER = UserHandle.of(1)!! + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesDndTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesDndTileUserActionInteractorTest.kt new file mode 100644 index 000000000000..0a35b428bbc9 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesDndTileUserActionInteractorTest.kt @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2025 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.tiles.impl.modes.domain.interactor + +import android.platform.test.annotations.EnableFlags +import android.provider.Settings +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.settingslib.notification.modes.TestModeBuilder.MANUAL_DND +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.mainCoroutineContext +import com.android.systemui.kosmos.testScope +import com.android.systemui.qs.shared.QSSettingsPackageRepository +import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject +import com.android.systemui.qs.tiles.base.actions.qsTileIntentUserInputHandler +import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx +import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesDndTileModel +import com.android.systemui.statusbar.policy.data.repository.zenModeRepository +import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor +import com.android.systemui.statusbar.policy.ui.dialog.mockModesDialogDelegate +import com.android.systemui.statusbar.policy.ui.dialog.modesDialogEventLogger +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever + +@SmallTest +@RunWith(AndroidJUnit4::class) +@EnableFlags(android.app.Flags.FLAG_MODES_UI) +class ModesDndTileUserActionInteractorTest : SysuiTestCase() { + + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val inputHandler = kosmos.qsTileIntentUserInputHandler + private val mockDialogDelegate = kosmos.mockModesDialogDelegate + private val zenModeRepository = kosmos.zenModeRepository + private val zenModeInteractor = kosmos.zenModeInteractor + private val settingsPackageRepository = mock<QSSettingsPackageRepository>() + + private val underTest = + ModesDndTileUserActionInteractor( + kosmos.mainCoroutineContext, + inputHandler, + mockDialogDelegate, + zenModeInteractor, + kosmos.modesDialogEventLogger, + settingsPackageRepository, + ) + + @Before + fun setUp() { + whenever(settingsPackageRepository.getSettingsPackageName()).thenReturn(SETTINGS_PACKAGE) + } + + @Test + fun handleClick_dndActive_deactivatesDnd() = + testScope.runTest { + val dndMode by collectLastValue(zenModeInteractor.dndMode) + zenModeRepository.activateMode(MANUAL_DND) + assertThat(dndMode?.isActive).isTrue() + + underTest.handleInput(QSTileInputTestKtx.click(data = ModesDndTileModel(true))) + + assertThat(dndMode?.isActive).isFalse() + } + + @Test + fun handleClick_dndInactive_activatesDnd() = + testScope.runTest { + val dndMode by collectLastValue(zenModeInteractor.dndMode) + assertThat(dndMode?.isActive).isFalse() + + underTest.handleInput(QSTileInputTestKtx.click(data = ModesDndTileModel(false))) + + assertThat(dndMode?.isActive).isTrue() + } + + @Test + fun handleLongClick_active_opensSettings() = + testScope.runTest { + zenModeRepository.activateMode(MANUAL_DND) + runCurrent() + + underTest.handleInput(QSTileInputTestKtx.longClick(ModesDndTileModel(true))) + + QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput { + assertThat(it.intent.`package`).isEqualTo(SETTINGS_PACKAGE) + assertThat(it.intent.action).isEqualTo(Settings.ACTION_AUTOMATIC_ZEN_RULE_SETTINGS) + assertThat(it.intent.getStringExtra(Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID)) + .isEqualTo(MANUAL_DND.id) + } + } + + @Test + fun handleLongClick_inactive_opensSettings() = + testScope.runTest { + zenModeRepository.activateMode(MANUAL_DND) + zenModeRepository.deactivateMode(MANUAL_DND) + runCurrent() + + underTest.handleInput(QSTileInputTestKtx.longClick(ModesDndTileModel(false))) + + QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput { + assertThat(it.intent.`package`).isEqualTo(SETTINGS_PACKAGE) + assertThat(it.intent.action).isEqualTo(Settings.ACTION_AUTOMATIC_ZEN_RULE_SETTINGS) + assertThat(it.intent.getStringExtra(Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID)) + .isEqualTo(MANUAL_DND.id) + } + } + + companion object { + private const val SETTINGS_PACKAGE = "the.settings.package" + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesDndTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesDndTileMapperTest.kt new file mode 100644 index 000000000000..29f642a4325d --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesDndTileMapperTest.kt @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2025 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.tiles.impl.modes.ui + +import android.app.Flags +import android.graphics.drawable.TestStubDrawable +import android.platform.test.annotations.EnableFlags +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.common.shared.model.Icon +import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesDndTileModel +import com.android.systemui.qs.tiles.viewmodel.QSTileConfigTestBuilder +import com.android.systemui.qs.tiles.viewmodel.QSTileState +import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig +import com.android.systemui.res.R +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +@EnableFlags(Flags.FLAG_MODES_UI) +class ModesDndTileMapperTest : SysuiTestCase() { + val config = + QSTileConfigTestBuilder.build { + uiConfig = + QSTileUIConfig.Resource( + iconRes = R.drawable.qs_dnd_icon_off, + labelRes = R.string.quick_settings_modes_label, + ) + } + + val underTest = + ModesDndTileMapper( + context.orCreateTestableResources + .apply { + addOverride(R.drawable.qs_dnd_icon_on, TestStubDrawable()) + addOverride(R.drawable.qs_dnd_icon_off, TestStubDrawable()) + } + .resources, + context.theme, + ) + + @Test + fun map_inactiveState() { + val model = ModesDndTileModel(isActivated = false) + + val state = underTest.map(config, model) + + assertThat(state.activationState).isEqualTo(QSTileState.ActivationState.INACTIVE) + assertThat((state.icon as Icon.Loaded).res).isEqualTo(R.drawable.qs_dnd_icon_off) + assertThat(state.secondaryLabel).isEqualTo("Off") + } + + @Test + fun map_activeState() { + val model = ModesDndTileModel(isActivated = true) + + val state = underTest.map(config, model) + + assertThat(state.activationState).isEqualTo(QSTileState.ActivationState.ACTIVE) + assertThat((state.icon as Icon.Loaded).res).isEqualTo(R.drawable.qs_dnd_icon_on) + assertThat(state.secondaryLabel).isEqualTo("On") + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java index 4a304071ee97..268d62952fc7 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java @@ -40,6 +40,7 @@ import android.app.IActivityManager; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Rect; +import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.flag.junit.FlagsParameterization; import android.testing.TestableLooper.RunWithLooper; import android.view.View; @@ -49,6 +50,7 @@ import androidx.test.filters.SmallTest; import com.android.app.viewcapture.ViewCaptureAwareWindowManager; import com.android.internal.colorextraction.ColorExtractor; +import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; import com.android.systemui.biometrics.AuthController; import com.android.systemui.colorextraction.SysuiColorExtractor; @@ -265,6 +267,7 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { } @Test + @RequiresFlagsDisabled(Flags.FLAG_DISABLE_BLURRED_SHADE_VISIBLE) public void setBackgroundBlurRadius_expandedWithBlurs() { mNotificationShadeWindowController.setBackgroundBlurRadius(10); verify(mNotificationShadeWindowView).setVisibility(eq(View.VISIBLE)); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java index f54c28f4295b..998a7ea805a2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java @@ -33,7 +33,7 @@ import static android.provider.Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS; import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_NONE; import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_PUBLIC; -import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_SENSITIVE_CONTENT; +import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_OTP; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; @@ -82,7 +82,6 @@ import com.android.systemui.flags.DisableSceneContainer; import com.android.systemui.flags.EnableSceneContainer; import com.android.systemui.flags.FakeFeatureFlagsClassic; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; -import com.android.systemui.log.LogWtfHandlerRule; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.LauncherProxyService; import com.android.systemui.settings.UserTracker; @@ -108,7 +107,6 @@ import kotlinx.coroutines.flow.StateFlow; import org.junit.After; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -207,8 +205,6 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { private final FakeExecutor mBackgroundExecutor = new FakeExecutor(mFakeSystemClock); private final Executor mMainExecutor = Runnable::run; // Direct executor - @Rule public final LogWtfHandlerRule wtfHandlerRule = new LogWtfHandlerRule(); - @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -697,7 +693,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { mLockscreenUserManager.mConnectedToWifi.set(false); // Sensitive Content notifications are always redacted - assertEquals(REDACTION_TYPE_SENSITIVE_CONTENT, + assertEquals(REDACTION_TYPE_OTP, mLockscreenUserManager.getRedactionType(mSensitiveContentNotif)); } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java index c9d910c530ea..01046cd10d87 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java @@ -20,16 +20,29 @@ import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; import static junit.framework.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.ActivityOptions; import android.app.Notification; +import android.app.PendingIntent; import android.content.Context; +import android.content.Intent; import android.os.SystemClock; import android.os.UserHandle; +import android.platform.test.flag.junit.FlagsParameterization; import android.testing.TestableLooper; +import android.util.Pair; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.RemoteViews; -import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; @@ -42,19 +55,37 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.row.NotificationTestHelper; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.util.kotlin.JavaAdapter; 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; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + @SmallTest -@RunWith(AndroidJUnit4.class) +@RunWith(ParameterizedAndroidJunit4.class) @TestableLooper.RunWithLooper public class NotificationRemoteInputManagerTest extends SysuiTestCase { + + @Parameters(name = "{0}") + public static List<FlagsParameterization> getParams() { + return FlagsParameterization.allCombinationsOf(NotificationBundleUi.FLAG_NAME); + } + private static final String TEST_PACKAGE_NAME = "test"; private static final int TEST_UID = 0; @@ -69,14 +100,34 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { @Mock private NotificationClickNotifier mClickNotifier; @Mock private NotificationLockscreenUserManager mLockscreenUserManager; @Mock private PowerInteractor mPowerInteractor; + @Mock + NotificationRemoteInputManager.RemoteInputListener mRemoteInputListener; + private ActionClickLogger mActionClickLogger; + @Captor + ArgumentCaptor<NotificationRemoteInputManager.ClickHandler> mClickHandlerArgumentCaptor; + private Context mSpyContext; + private NotificationTestHelper mTestHelper; private TestableNotificationRemoteInputManager mRemoteInputManager; private NotificationEntry mEntry; + public NotificationRemoteInputManagerTest(FlagsParameterization flags) { + super(); + mSetFlagsRule.setFlagsParameterization(flags); + } + @Before - public void setUp() { + public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + mSpyContext = spy(mContext); + doNothing().when(mSpyContext).startIntentSender( + any(), any(), anyInt(), anyInt(), anyInt(), any()); + + + mTestHelper = new NotificationTestHelper(mSpyContext, mDependency); + mActionClickLogger = spy(new ActionClickLogger(logcatLogBuffer())); + mRemoteInputManager = new TestableNotificationRemoteInputManager(mContext, mock(NotifPipelineFlags.class), mLockscreenUserManager, @@ -87,9 +138,10 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { mRemoteInputUriController, new RemoteInputControllerLogger(logcatLogBuffer()), mClickNotifier, - new ActionClickLogger(logcatLogBuffer()), + mActionClickLogger, mock(JavaAdapter.class), mock(ShadeInteractor.class)); + mRemoteInputManager.setRemoteInputListener(mRemoteInputListener); mEntry = new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_NAME) .setOpPkg(TEST_PACKAGE_NAME) @@ -133,6 +185,70 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { assertTrue(mRemoteInputManager.shouldKeepForSmartReplyHistory(mEntry)); } + @Test + public void testActionClick() throws Exception { + RemoteViews.RemoteResponse response = mock(RemoteViews.RemoteResponse.class); + when(response.getLaunchOptions(any())).thenReturn( + Pair.create(mock(Intent.class), mock(ActivityOptions.class))); + ExpandableNotificationRow row = getRowWithReplyAction(); + View actionView = ((LinearLayout) row.getPrivateLayout().getExpandedChild().findViewById( + com.android.internal.R.id.actions)).getChildAt(0); + Notification n = getNotification(row); + CountDownLatch latch = new CountDownLatch(1); + Consumer<NotificationEntry> consumer = notificationEntry -> latch.countDown(); + if (!NotificationBundleUi.isEnabled()) { + mRemoteInputManager.addActionPressListener(consumer); + } + + mRemoteInputManager.getRemoteViewsOnClickHandler().onInteraction( + actionView, + n.actions[0].actionIntent, + response); + + verify(mActionClickLogger).logInitialClick(row.getKey(), 0, n.actions[0].actionIntent); + verify(mClickNotifier).onNotificationActionClick( + eq(row.getKey()), eq(0), eq(n.actions[0]), any(), eq(false)); + verify(mCallback).handleRemoteViewClick(eq(actionView), eq(n.actions[0].actionIntent), + eq(false), eq(0), mClickHandlerArgumentCaptor.capture()); + + mClickHandlerArgumentCaptor.getValue().handleClick(); + verify(mActionClickLogger).logStartingIntentWithDefaultHandler( + row.getKey(), n.actions[0].actionIntent, 0); + + verify(mRemoteInputListener).releaseNotificationIfKeptForRemoteInputHistory(row.getKey()); + if (NotificationBundleUi.isEnabled()) { + verify(row.getEntryAdapter()).onNotificationActionClicked(); + } else { + latch.await(10, TimeUnit.MILLISECONDS); + } + } + + private Notification getNotification(ExpandableNotificationRow row) { + if (NotificationBundleUi.isEnabled()) { + return row.getEntryAdapter().getSbn().getNotification(); + } else { + return row.getEntry().getSbn().getNotification(); + } + } + + private ExpandableNotificationRow getRowWithReplyAction() throws Exception { + PendingIntent pi = PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), + PendingIntent.FLAG_IMMUTABLE); + Notification n = new Notification.Builder(mSpyContext, "") + .setSmallIcon(com.android.systemui.res.R.drawable.ic_person) + .addAction(new Notification.Action(com.android.systemui.res.R.drawable.ic_person, + "reply", pi)) + .build(); + ExpandableNotificationRow row = mTestHelper.createRow(n); + row.onNotificationUpdated(); + row.getPrivateLayout().setExpandedChild(Notification.Builder.recoverBuilder(mSpyContext, n) + .createBigContentView().apply( + mSpyContext, + row.getPrivateLayout(), + mRemoteInputManager.getRemoteViewsOnClickHandler())); + return row; + } + private class TestableNotificationRemoteInputManager extends NotificationRemoteInputManager { TestableNotificationRemoteInputManager( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt index 8165d45c93df..326d8ffd3c7c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt @@ -34,7 +34,6 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.res.R import com.android.systemui.shade.ShadeExpansionChangeEvent -import com.android.systemui.shared.Flags as SharedFlags import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.phone.DozeParameters import com.android.systemui.statusbar.phone.ScrimController @@ -44,11 +43,10 @@ import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController import com.android.systemui.testKosmos import com.android.systemui.util.WallpaperController import com.android.systemui.util.mockito.eq +import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor import com.android.systemui.window.domain.interactor.WindowRootViewBlurInteractor import com.android.wm.shell.appzoomout.AppZoomOut import com.google.common.truth.Truth.assertThat -import java.util.Optional -import java.util.function.Consumer import org.junit.Before import org.junit.Rule import org.junit.Test @@ -69,6 +67,8 @@ import org.mockito.Mockito.reset import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.junit.MockitoJUnit +import java.util.Optional +import java.util.function.Consumer @RunWith(AndroidJUnit4::class) @RunWithLooper @@ -76,6 +76,7 @@ import org.mockito.junit.MockitoJUnit class NotificationShadeDepthControllerTest : SysuiTestCase() { private val kosmos = testKosmos() + private val applicationScope = kosmos.testScope.backgroundScope @Mock private lateinit var windowRootViewBlurInteractor: WindowRootViewBlurInteractor @Mock private lateinit var statusBarStateController: StatusBarStateController @Mock private lateinit var blurUtils: BlurUtils @@ -84,6 +85,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() { @Mock private lateinit var keyguardInteractor: KeyguardInteractor @Mock private lateinit var choreographer: Choreographer @Mock private lateinit var wallpaperController: WallpaperController + @Mock private lateinit var wallpaperInteractor: WallpaperInteractor @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController @Mock private lateinit var dumpManager: DumpManager @Mock private lateinit var appZoomOutOptional: Optional<AppZoomOut> @@ -128,12 +130,14 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() { keyguardInteractor, choreographer, wallpaperController, + wallpaperInteractor, notificationShadeWindowController, dozeParameters, context, ResourcesSplitShadeStateController(), windowRootViewBlurInteractor, appZoomOutOptional, + applicationScope, dumpManager, configurationController, ) @@ -310,19 +314,21 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() { } @Test - @DisableFlags(SharedFlags.FLAG_AMBIENT_AOD) - fun onDozeAmountChanged_appliesBlur() { + fun onDozeAmountChanged_doesNotApplyBlurWithAmbientAod() { + notificationShadeDepthController.wallpaperSupportsAmbientMode = false + statusBarStateListener.onDozeAmountChanged(1f, 1f) notificationShadeDepthController.updateBlurCallback.doFrame(0) - verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false)) + verify(blurUtils).applyBlur(any(), eq(0), eq(false)) } @Test - @EnableFlags(SharedFlags.FLAG_AMBIENT_AOD) - fun onDozeAmountChanged_doesNotApplyBlurWithAmbientAod() { + fun onDozeAmountChanged_appliesBlurWithAmbientAod() { + notificationShadeDepthController.wallpaperSupportsAmbientMode = true + statusBarStateListener.onDozeAmountChanged(1f, 1f) notificationShadeDepthController.updateBlurCallback.doFrame(0) - verify(blurUtils).applyBlur(any(), eq(0), eq(false)) + verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false)) } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapterTest.kt index b6889afa4e8a..faafa073be4c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapterTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapterTest.kt @@ -29,8 +29,10 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.res.R import com.android.systemui.statusbar.RankingBuilder +import com.android.systemui.statusbar.notification.mockNotificationActivityStarter import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.entryAdapterFactory +import com.android.systemui.statusbar.notification.row.mockNotificationActionClickManager import com.android.systemui.statusbar.notification.shared.NotificationBundleUi import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING import com.android.systemui.testKosmos @@ -355,16 +357,27 @@ class NotificationEntryAdapterTest : SysuiTestCase() { val notification: Notification = Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build() - val entry = - NotificationEntryBuilder() - .setNotification(notification) - .setImportance(NotificationManager.IMPORTANCE_MIN) - .build() + val entry = NotificationEntryBuilder().setNotification(notification).build() underTest = factory.create(entry) as NotificationEntryAdapter underTest.onNotificationBubbleIconClicked() - verify((factory as? EntryAdapterFactoryImpl)?.getNotificationActivityStarter()) - ?.onNotificationBubbleIconClicked(entry) + verify(kosmos.mockNotificationActivityStarter).onNotificationBubbleIconClicked(entry) + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun onNotificationActionClicked() { + val notification: Notification = + Notification.Builder(mContext, "") + .setSmallIcon(R.drawable.ic_person) + .addAction(Mockito.mock(Notification.Action::class.java)) + .build() + + val entry = NotificationEntryBuilder().setNotification(notification).build() + + underTest = factory.create(entry) as NotificationEntryAdapter + underTest.onNotificationActionClicked() + verify(kosmos.mockNotificationActionClickManager).onNotificationActionClicked(entry) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt index 30983550f0f9..44d88c31c5f1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt @@ -50,6 +50,8 @@ import com.android.systemui.statusbar.notification.interruption.NotificationInte import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderWrapper.DecisionImpl import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderWrapper.FullScreenIntentDecisionImpl import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider +import com.android.systemui.statusbar.notification.row.mockNotificationActionClickManager +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi import com.android.systemui.statusbar.phone.NotificationGroupTestHelper import com.android.systemui.testKosmos import com.android.systemui.util.concurrency.FakeExecutor @@ -138,6 +140,7 @@ class HeadsUpCoordinatorTest : SysuiTestCase() { headsUpViewBinder, visualInterruptionDecisionProvider, remoteInputManager, + kosmos.mockNotificationActionClickManager, launchFullScreenIntentProvider, flags, statusBarNotificationChipsInteractor, @@ -161,8 +164,14 @@ class HeadsUpCoordinatorTest : SysuiTestCase() { verify(notifPipeline).addOnBeforeFinalizeFilterListener(capture()) } onHeadsUpChangedListener = withArgCaptor { verify(headsUpManager).addListener(capture()) } - actionPressListener = withArgCaptor { - verify(remoteInputManager).addActionPressListener(capture()) + actionPressListener = if (NotificationBundleUi.isEnabled) { + withArgCaptor { + verify(kosmos.mockNotificationActionClickManager).addActionClickListener(capture()) + } + } else { + withArgCaptor { + verify(remoteInputManager).addActionPressListener(capture()) + } } given(headsUpManager.allEntries).willAnswer { huns.stream() } given(headsUpManager.isHeadsUpEntry(anyString())).willAnswer { invocation -> @@ -260,7 +269,7 @@ class HeadsUpCoordinatorTest : SysuiTestCase() { addHUN(entry) actionPressListener.accept(entry) - verify(headsUpManager, times(1)).setUserActionMayIndirectlyRemove(entry) + verify(headsUpManager, times(1)).setUserActionMayIndirectlyRemove(entry.key) whenever(headsUpManager.canRemoveImmediately(anyString())).thenReturn(true) assertFalse(notifLifetimeExtender.maybeExtendLifetime(entry, 0)) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java index c5752691da44..f9405af3f85d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java @@ -16,7 +16,9 @@ package com.android.systemui.statusbar.notification.collection.coordinator; +import static android.app.NotificationChannel.SYSTEM_RESERVED_IDS; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; +import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; @@ -45,6 +47,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.SbnBuilder; +import com.android.systemui.statusbar.notification.collection.BundleEntry; import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -273,6 +276,18 @@ public class RankingCoordinatorTest extends SysuiTestCase { } @Test + public void testSilentSectioner_acceptsBundle() { + BundleEntry bundleEntry = new BundleEntry("testBundleKey"); + assertTrue(mSilentSectioner.isInSection(bundleEntry)); + } + + @Test + public void testMinimizedSectioner_rejectsBundle() { + BundleEntry bundleEntry = new BundleEntry("testBundleKey"); + assertFalse(mMinimizedSectioner.isInSection(bundleEntry)); + } + + @Test public void testMinSection() { when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false); setRankingAmbient(true); @@ -327,6 +342,13 @@ public class RankingCoordinatorTest extends SysuiTestCase { } @Test + public void testAlertingSectioner_rejectsBundle() { + for (String id : SYSTEM_RESERVED_IDS) { + assertFalse(mAlertingSectioner.isInSection(makeClassifiedNotifEntry(id))); + } + } + + @Test public void statusBarStateCallbackTest() { mStatusBarStateCallback.onDozeAmountChanged(1f, 1f); verify(mInvalidationListener, times(1)) @@ -379,4 +401,11 @@ public class RankingCoordinatorTest extends SysuiTestCase { .build()); assertEquals(ambient, mEntry.getRanking().isAmbient()); } + + private NotificationEntry makeClassifiedNotifEntry(String channelId) { + NotificationChannel channel = new NotificationChannel(channelId, channelId, IMPORTANCE_LOW); + return new NotificationEntryBuilder() + .updateRanking((rankingBuilder -> rankingBuilder.setChannel(channel))) + .build(); + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt index 9804932918dc..8560b66d961f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt @@ -1071,7 +1071,7 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() { assertThat(underTest.canRemoveImmediately(notifEntry.key)).isFalse() - underTest.setUserActionMayIndirectlyRemove(notifEntry) + underTest.setUserActionMayIndirectlyRemove(notifEntry.key) assertThat(underTest.canRemoveImmediately(notifEntry.key)).isTrue() } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java index 9f35d631bd45..99f2596dbf1d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java @@ -17,7 +17,7 @@ package com.android.systemui.statusbar.notification.row; import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_PUBLIC; -import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_SENSITIVE_CONTENT; +import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_OTP; import static com.android.systemui.statusbar.NotificationLockscreenUserManager.RedactionType; import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_NONE; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL; @@ -472,7 +472,7 @@ public class NotificationContentInflaterTest extends SysuiTestCase { com.android.systemui.res.R.drawable.ic_person).setStyle(messagingStyle).build(); ExpandableNotificationRow row = mHelper.createRow(messageNotif); inflateAndWait(false, mNotificationInflater, FLAG_CONTENT_VIEW_PUBLIC, - REDACTION_TYPE_SENSITIVE_CONTENT, row); + REDACTION_TYPE_OTP, row); NotificationContentView publicView = row.getPublicLayout(); assertNotNull(publicView); // The display name should be included, but not the content or message text @@ -493,7 +493,7 @@ public class NotificationContentInflaterTest extends SysuiTestCase { .build(); ExpandableNotificationRow row = mHelper.createRow(notif); inflateAndWait(false, mNotificationInflater, FLAG_CONTENT_VIEW_PUBLIC, - REDACTION_TYPE_SENSITIVE_CONTENT, row); + REDACTION_TYPE_OTP, row); NotificationContentView publicView = row.getPublicLayout(); assertNotNull(publicView); assertFalse(hasText(publicView, contentText)); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt index 31413b06e5fd..063a04ab9f37 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt @@ -36,8 +36,8 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.res.R import com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_NONE +import com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_OTP import com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_PUBLIC -import com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_SENSITIVE_CONTENT import com.android.systemui.statusbar.NotificationLockscreenUserManager.RedactionType import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips import com.android.systemui.statusbar.notification.ConversationNotificationProcessor @@ -538,7 +538,7 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { false, notificationInflater, FLAG_CONTENT_VIEW_PUBLIC, - REDACTION_TYPE_SENSITIVE_CONTENT, + REDACTION_TYPE_OTP, newRow, ) // The display name should be included, but not the content or message text @@ -566,7 +566,7 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { false, notificationInflater, FLAG_CONTENT_VIEW_PUBLIC, - REDACTION_TYPE_SENSITIVE_CONTENT, + REDACTION_TYPE_OTP, newRow, ) var publicView = newRow.publicLayout diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java index 6415f8c25a37..e6b2c2541447 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java @@ -29,6 +29,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -363,6 +364,7 @@ public class NotificationTestHelper { .setUid(UID) .setInitialPid(2000) .setNotification(summary) + .setUser(USER_HANDLE) .setParent(GroupEntry.ROOT_ENTRY) .build(); GroupEntryBuilder groupEntry = new GroupEntryBuilder() @@ -743,11 +745,12 @@ public class NotificationTestHelper { mock(MetricsLogger.class), mock(PeopleNotificationIdentifier.class), mock(NotificationIconStyleProvider.class), - mock(VisualStabilityCoordinator.class) + mock(VisualStabilityCoordinator.class), + mock(NotificationActionClickManager.class) ).create(entry); row.initialize( - entryAdapter, + spy(entryAdapter), entry, mock(RemoteInputViewSubcomponent.Factory.class), APP_NAME, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt index 531b30b9547a..0fb0548582ce 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt @@ -18,27 +18,27 @@ package com.android.systemui.statusbar.notification.shared import com.google.common.truth.Correspondence val byKey: Correspondence<ActiveNotificationModel, String> = - Correspondence.transforming({ it?.key }, "has a key of") + Correspondence.transforming({ it.key }, "has a key of") val byIsAmbient: Correspondence<ActiveNotificationModel, Boolean> = - Correspondence.transforming({ it?.isAmbient }, "has an isAmbient value of") + Correspondence.transforming({ it.isAmbient }, "has an isAmbient value of") val byIsSuppressedFromStatusBar: Correspondence<ActiveNotificationModel, Boolean> = Correspondence.transforming( - { it?.isSuppressedFromStatusBar }, + { it.isSuppressedFromStatusBar }, "has an isSuppressedFromStatusBar value of", ) val byIsSilent: Correspondence<ActiveNotificationModel, Boolean> = - Correspondence.transforming({ it?.isSilent }, "has an isSilent value of") + Correspondence.transforming({ it.isSilent }, "has an isSilent value of") val byIsRowDismissed: Correspondence<ActiveNotificationModel, Boolean> = - Correspondence.transforming({ it?.isRowDismissed }, "has an isRowDismissed value of") + Correspondence.transforming({ it.isRowDismissed }, "has an isRowDismissed value of") val byIsLastMessageFromReply: Correspondence<ActiveNotificationModel, Boolean> = Correspondence.transforming( - { it?.isLastMessageFromReply }, + { it.isLastMessageFromReply }, "has an isLastMessageFromReply value of", ) val byIsPulsing: Correspondence<ActiveNotificationModel, Boolean> = - Correspondence.transforming({ it?.isPulsing }, "has an isPulsing value of") + Correspondence.transforming({ it.isPulsing }, "has an isPulsing value of") val byIsPromoted: Correspondence<ActiveNotificationModel, Boolean> = Correspondence.transforming( - { it?.promotedContent != null }, + { it.promotedContent != null }, "has (or doesn't have) a promoted content model", ) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt index 08ecbac1582c..41cca19346f0 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt @@ -38,6 +38,7 @@ import com.android.systemui.statusbar.ui.fakeSystemBarUtilsProxy import com.android.systemui.testKosmos import com.google.common.truth.Expect import com.google.common.truth.Truth.assertThat +import kotlin.math.roundToInt import org.junit.Assume import org.junit.Before import org.junit.Rule @@ -1572,7 +1573,11 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() { fullStackHeight: Float = 3000f, ) { ambientState.headsUpTop = headsUpTop - ambientState.headsUpBottom = headsUpBottom + if (NotificationsHunSharedAnimationValues.isEnabled) { + headsUpAnimator.headsUpAppearHeightBottom = headsUpBottom.roundToInt() + } else { + ambientState.headsUpBottom = headsUpBottom + } ambientState.stackTop = stackTop ambientState.stackCutoff = stackCutoff diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt index 12cf3b6cd2cf..2da692b4cb45 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt @@ -1513,7 +1513,39 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() { @Test @DisableSceneContainer - fun shadeShown_sceneFlagOff_noStatusBarViewsShown() = + fun shadeSlightlyShown_sceneFlagOff_statusBarViewsShown() = + kosmos.runTest { + val clockVisible by collectLastValue(underTest.isClockVisible) + val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible) + val systemInfoVisible by collectLastValue(underTest.systemInfoCombinedVis) + transitionKeyguardToGone() + + kosmos.shadeTestUtil.setShadeExpansion(0.1f) + + assertThat(clockVisible!!.visibility).isEqualTo(View.VISIBLE) + assertThat(notifIconsVisible!!.visibility).isEqualTo(View.VISIBLE) + assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.VISIBLE) + } + + @Test + @DisableSceneContainer + fun shadeHalfShown_sceneFlagOff_noStatusBarViewsShown() = + kosmos.runTest { + val clockVisible by collectLastValue(underTest.isClockVisible) + val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible) + val systemInfoVisible by collectLastValue(underTest.systemInfoCombinedVis) + transitionKeyguardToGone() + + kosmos.shadeTestUtil.setShadeExpansion(0.5f) + + assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE) + assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE) + assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE) + } + + @Test + @DisableSceneContainer + fun shadeFullyShown_sceneFlagOff_noStatusBarViewsShown() = kosmos.runTest { val clockVisible by collectLastValue(underTest.isClockVisible) val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible) @@ -1527,6 +1559,83 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() { assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE) } + /** Regression test for b/394257529#comment24. */ + @Test + @DisableSceneContainer + fun qqsToQsTransition_sceneFlagOff_statusBarViewsNeverShown() = + kosmos.runTest { + val clockVisible by collectLastValue(underTest.isClockVisible) + val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible) + val systemInfoVisible by collectLastValue(underTest.systemInfoCombinedVis) + transitionKeyguardToGone() + + kosmos.shadeTestUtil.setShadeAndQsExpansion(shadeExpansion = 1f, qsExpansion = 0f) + assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE) + assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE) + assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE) + + kosmos.shadeTestUtil.setShadeAndQsExpansion(shadeExpansion = 0.9f, qsExpansion = 0.1f) + assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE) + assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE) + assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE) + + kosmos.shadeTestUtil.setShadeAndQsExpansion(shadeExpansion = 0.6f, qsExpansion = 0.4f) + assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE) + assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE) + assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE) + + kosmos.shadeTestUtil.setShadeAndQsExpansion(shadeExpansion = 0.5f, qsExpansion = 0.5f) + assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE) + assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE) + assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE) + + kosmos.shadeTestUtil.setShadeAndQsExpansion(shadeExpansion = 0.2f, qsExpansion = 0.8f) + assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE) + assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE) + assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE) + + kosmos.shadeTestUtil.setShadeAndQsExpansion(shadeExpansion = 0f, qsExpansion = 1f) + assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE) + assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE) + assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE) + } + + /** Regression test for b/394257529#comment24. */ + @Test + @DisableSceneContainer + fun qsToQqsTransition_sceneFlagOff_statusBarViewsNeverShown() = + kosmos.runTest { + val clockVisible by collectLastValue(underTest.isClockVisible) + val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible) + val systemInfoVisible by collectLastValue(underTest.systemInfoCombinedVis) + transitionKeyguardToGone() + + kosmos.shadeTestUtil.setShadeAndQsExpansion(shadeExpansion = 0f, qsExpansion = 1f) + assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE) + assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE) + assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE) + + kosmos.shadeTestUtil.setShadeAndQsExpansion(shadeExpansion = 0.3f, qsExpansion = 0.7f) + assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE) + assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE) + assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE) + + kosmos.shadeTestUtil.setShadeAndQsExpansion(shadeExpansion = 0.5f, qsExpansion = 0.5f) + assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE) + assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE) + assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE) + + kosmos.shadeTestUtil.setShadeAndQsExpansion(shadeExpansion = 0.7f, qsExpansion = 0.3f) + assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE) + assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE) + assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE) + + kosmos.shadeTestUtil.setShadeAndQsExpansion(shadeExpansion = 1f, qsExpansion = 0f) + assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE) + assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE) + assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE) + } + @Test @EnableSceneContainer fun shadeShown_sceneFlagOn_noStatusBarViewsShown() = diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt index cc6a7b93eef3..a0f1a5ce386e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt @@ -18,6 +18,7 @@ package com.android.systemui.wallpapers.data.repository import android.app.WallpaperInfo import android.app.WallpaperManager +import android.app.WallpaperManager.FLAG_LOCK import android.content.ComponentName import android.content.Intent import android.content.pm.UserInfo @@ -29,6 +30,7 @@ import com.android.app.wallpaperManager import com.android.internal.R import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.broadcastDispatcher +import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.testScope import com.android.systemui.res.R as SysUIR @@ -44,6 +46,7 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.eq import org.mockito.kotlin.any import org.mockito.kotlin.doAnswer import org.mockito.kotlin.mock @@ -64,6 +67,7 @@ class WallpaperRepositoryImplTest : SysuiTestCase() { private val testScope = kosmos.testScope private val userRepository = kosmos.fakeUserRepository private val broadcastDispatcher = kosmos.broadcastDispatcher + private val configRepository = kosmos.fakeConfigurationRepository // Initialized in each test since certain flows rely on mocked data that isn't // modifiable after start, like wallpaperManager.isWallpaperSupported @@ -251,10 +255,18 @@ class WallpaperRepositoryImplTest : SysuiTestCase() { secureSettings.putInt(Settings.Secure.DOZE_ALWAYS_ON_WALLPAPER_ENABLED, 1) context.orCreateTestableResources.addOverride( R.bool.config_dozeSupportsAodWallpaper, - true, + false, ) - + configRepository.onAnyConfigurationChange() val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) + assertThat(latest).isFalse() + + // Validate that a configuration change recalculates the flow + context.orCreateTestableResources.addOverride( + R.bool.config_dozeSupportsAodWallpaper, + true, + ) + configRepository.onAnyConfigurationChange() assertThat(latest).isTrue() } @@ -275,17 +287,17 @@ class WallpaperRepositoryImplTest : SysuiTestCase() { @Test @EnableFlags(SharedFlags.FLAG_EXTENDED_WALLPAPER_EFFECTS) - fun shouldSendNotificationLayout_setExtendedEffectsWallpaper_launchSendLayoutJob() = + fun shouldSendNotificationLayout_setExtendedEffectsWallpaper() = testScope.runTest { underTest = kosmos.wallpaperRepository val latest by collectLastValue(underTest.shouldSendFocalArea) - val extedendEffectsWallpaper = + val extendedEffectsWallpaper = mock<WallpaperInfo>().apply { whenever(this.component).thenReturn(ComponentName(context, focalAreaTarget)) } whenever(kosmos.wallpaperManager.getWallpaperInfoForUser(any())) - .thenReturn(extedendEffectsWallpaper) + .thenReturn(extendedEffectsWallpaper) broadcastDispatcher.sendIntentToMatchingReceiversOnly( context, Intent(Intent.ACTION_WALLPAPER_CHANGED), @@ -295,7 +307,7 @@ class WallpaperRepositoryImplTest : SysuiTestCase() { @Test @EnableFlags(SharedFlags.FLAG_EXTENDED_WALLPAPER_EFFECTS) - fun shouldSendNotificationLayout_setNotExtendedEffectsWallpaper_cancelSendLayoutJob() = + fun shouldSendNotificationLayout_setNotExtendedEffectsWallpaper() = testScope.runTest { underTest = kosmos.wallpaperRepository val latest by collectLastValue(underTest.shouldSendFocalArea) @@ -322,6 +334,51 @@ class WallpaperRepositoryImplTest : SysuiTestCase() { assertThat(latest).isFalse() } + @Test + @EnableFlags(SharedFlags.FLAG_EXTENDED_WALLPAPER_EFFECTS) + fun shouldSendNotificationLayout_setExtendedEffectsWallpaperOnlyForHomescreen() = + testScope.runTest { + underTest = kosmos.wallpaperRepository + val latest by collectLastValue(underTest.shouldSendFocalArea) + val extendedEffectsWallpaper = + mock<WallpaperInfo>().apply { + whenever(this.component).thenReturn(ComponentName("", focalAreaTarget)) + } + + whenever(kosmos.wallpaperManager.lockScreenWallpaperExists()).thenReturn(true) + whenever(kosmos.wallpaperManager.getWallpaperInfoForUser(any())) + .thenReturn(extendedEffectsWallpaper) + whenever(kosmos.wallpaperManager.getWallpaperInfo(eq(FLAG_LOCK), any())) + .thenReturn(UNSUPPORTED_WP) + broadcastDispatcher.sendIntentToMatchingReceiversOnly( + context, + Intent(Intent.ACTION_WALLPAPER_CHANGED), + ) + assertThat(latest).isFalse() + } + + @Test + @EnableFlags(SharedFlags.FLAG_EXTENDED_WALLPAPER_EFFECTS) + fun shouldSendNotificationLayout_setExtendedEffectsWallpaperOnlyForLockscreen() = + testScope.runTest { + underTest = kosmos.wallpaperRepository + val latest by collectLastValue(underTest.shouldSendFocalArea) + val extendedEffectsWallpaper = + mock<WallpaperInfo>().apply { + whenever(this.component).thenReturn(ComponentName("", focalAreaTarget)) + } + whenever(kosmos.wallpaperManager.lockScreenWallpaperExists()).thenReturn(true) + whenever(kosmos.wallpaperManager.getWallpaperInfoForUser(any())) + .thenReturn(UNSUPPORTED_WP) + whenever(kosmos.wallpaperManager.getWallpaperInfo(eq(FLAG_LOCK), any())) + .thenReturn(extendedEffectsWallpaper) + broadcastDispatcher.sendIntentToMatchingReceiversOnly( + context, + Intent(Intent.ACTION_WALLPAPER_CHANGED), + ) + assertThat(latest).isTrue() + } + private companion object { val USER_WITH_UNSUPPORTED_WP = UserInfo(/* id= */ 3, /* name= */ "user3", /* flags= */ 0) val UNSUPPORTED_WP = diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt index b52db83d513c..7657a2179d4f 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt @@ -13,7 +13,6 @@ */ package com.android.systemui.plugins.clocks -import android.graphics.RectF import com.android.systemui.plugins.annotations.ProtectedInterface import com.android.systemui.plugins.annotations.SimpleProperty import java.io.PrintWriter @@ -50,5 +49,5 @@ interface ClockController { } interface ClockEventListener { - fun onBoundsChanged(bounds: RectF) + fun onBoundsChanged(bounds: VRectF) } diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceEvents.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceEvents.kt index 20ee6c120ee8..a658c15a1a99 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceEvents.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceEvents.kt @@ -45,6 +45,7 @@ interface ClockFaceEvents { * render within the centered targetRect to avoid obstructing other elements. The specified * targetRegion is relative to the parent view. */ + @Deprecated("No longer necessary, pending removal") fun onTargetRegionChanged(targetRegion: Rect?) /** Called to notify the clock about its display. */ diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt index 02a3902a042c..f9ff75d5fdc8 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt @@ -16,7 +16,6 @@ package com.android.systemui.plugins.clocks -import android.graphics.Rect import android.view.View import android.view.View.MeasureSpec import com.android.systemui.log.core.LogLevel @@ -56,12 +55,9 @@ class ClockLogger(private val view: View?, buffer: MessageBuffer, tag: String) : } fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { - d({ "onLayout($bool1, ${Rect(int1, int2, long1.toInt(), long2.toInt())})" }) { + d({ "onLayout($bool1, ${VRect(long1.toULong())})" }) { bool1 = changed - int1 = left - int2 = top - long1 = right.toLong() - long2 = bottom.toLong() + long1 = VRect(left, top, right, bottom).data.toLong() } } @@ -108,8 +104,11 @@ class ClockLogger(private val view: View?, buffer: MessageBuffer, tag: String) : } } - fun animateDoze() { - d("animateDoze()") + fun animateDoze(isDozing: Boolean, isAnimated: Boolean) { + d({ "animateDoze(isDozing=$bool1, isAnimated=$bool2)" }) { + bool1 = isDozing + bool2 = isAnimated + } } fun animateCharge() { @@ -117,10 +116,7 @@ class ClockLogger(private val view: View?, buffer: MessageBuffer, tag: String) : } fun animateFidget(x: Float, y: Float) { - d({ "animateFidget($str1, $str2)" }) { - str1 = x.toString() - str2 = y.toString() - } + d({ "animateFidget(${VPointF(long1.toULong())})" }) { long1 = VPointF(x, y).data.toLong() } } companion object { diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/VPoint.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VPoint.kt index 3dae5305542b..1fb37ec28835 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/VPoint.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VPoint.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.shared.clocks +package com.android.systemui.plugins.clocks import android.graphics.Point import android.graphics.PointF @@ -30,22 +30,20 @@ private val Y_MASK: ULong = 0x00000000FFFFFFFFU private fun unpackX(data: ULong): Int = ((data and X_MASK) shr 32).toInt() -private fun unpackY(data: ULong): Int = (data and Y_MASK).toInt() +private fun unpackY(data: ULong): Int = ((data and Y_MASK) shr 0).toInt() private fun pack(x: Int, y: Int): ULong { - return ((x.toULong() shl 32) and X_MASK) or (y.toULong() and Y_MASK) + return ((x.toULong() shl 32) and X_MASK) or ((y.toULong() shl 0) and Y_MASK) } @JvmInline -value class VPointF(private val data: ULong) { +value class VPointF(val data: ULong) { val x: Float get() = Float.fromBits(unpackX(data)) val y: Float get() = Float.fromBits(unpackY(data)) - constructor() : this(0f, 0f) - constructor(pt: PointF) : this(pt.x, pt.y) constructor(x: Int, y: Int) : this(x.toFloat(), y.toFloat()) @@ -139,15 +137,13 @@ value class VPointF(private val data: ULong) { } @JvmInline -value class VPoint(private val data: ULong) { +value class VPoint(val data: ULong) { val x: Int get() = unpackX(data) val y: Int get() = unpackY(data) - constructor() : this(0, 0) - constructor(x: Int, y: Int) : this(pack(x, y)) fun toPoint() = Point(x, y) diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VRect.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VRect.kt new file mode 100644 index 000000000000..3c1adf22a405 --- /dev/null +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VRect.kt @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2025 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.plugins.clocks + +import android.graphics.Rect +import android.graphics.RectF +import android.util.Half + +private val LEFT_MASK: ULong = 0xFFFF000000000000U +private val TOP_MASK: ULong = 0x0000FFFF00000000U +private val RIGHT_MASK: ULong = 0x00000000FFFF0000U +private val BOTTOM_MASK: ULong = 0x000000000000FFFFU + +private fun unpackLeft(data: ULong): Short = ((data and LEFT_MASK) shr 48).toShort() + +private fun unpackTop(data: ULong): Short = ((data and TOP_MASK) shr 32).toShort() + +private fun unpackRight(data: ULong): Short = ((data and RIGHT_MASK) shr 16).toShort() + +private fun unpackBottom(data: ULong): Short = ((data and BOTTOM_MASK) shr 0).toShort() + +private fun pack(left: Short, top: Short, right: Short, bottom: Short): ULong { + return ((left.toULong() shl 48) and LEFT_MASK) or + ((top.toULong() shl 32) and TOP_MASK) or + ((right.toULong() shl 16) and RIGHT_MASK) or + ((bottom.toULong() shl 0) and BOTTOM_MASK) +} + +@JvmInline +value class VRectF(val data: ULong) { + val left: Float + get() = fromBits(unpackLeft(data)) + + val top: Float + get() = fromBits(unpackTop(data)) + + val right: Float + get() = fromBits(unpackRight(data)) + + val bottom: Float + get() = fromBits(unpackBottom(data)) + + val width: Float + get() = right - left + + val height: Float + get() = bottom - top + + constructor(rect: RectF) : this(rect.left, rect.top, rect.right, rect.bottom) + + constructor( + rect: Rect + ) : this( + left = rect.left.toFloat(), + top = rect.top.toFloat(), + right = rect.right.toFloat(), + bottom = rect.bottom.toFloat(), + ) + + constructor( + left: Float, + top: Float, + right: Float, + bottom: Float, + ) : this(pack(toBits(left), toBits(top), toBits(right), toBits(bottom))) + + val center: VPointF + get() = VPointF(left, top) + size / 2f + + val size: VPointF + get() = VPointF(width, height) + + override fun toString() = "($left, $top) -> ($right, $bottom)" + + companion object { + private fun toBits(value: Float): Short = Half.halfToShortBits(Half.toHalf(value)) + + private fun fromBits(value: Short): Float = Half.toFloat(Half.intBitsToHalf(value.toInt())) + + fun fromCenter(center: VPointF, size: VPointF): VRectF { + return VRectF( + center.x - size.x / 2, + center.y - size.y / 2, + center.x + size.x / 2, + center.y + size.y / 2, + ) + } + + fun fromTopLeft(pos: VPointF, size: VPointF): VRectF { + return VRectF(pos.x, pos.y, pos.x + size.x, pos.y + size.y) + } + + val ZERO = VRectF(0f, 0f, 0f, 0f) + } +} + +@JvmInline +value class VRect(val data: ULong) { + val left: Int + get() = unpackLeft(data).toInt() + + val top: Int + get() = unpackTop(data).toInt() + + val right: Int + get() = unpackRight(data).toInt() + + val bottom: Int + get() = unpackBottom(data).toInt() + + val width: Int + get() = right - left + + val height: Int + get() = bottom - top + + constructor( + rect: Rect + ) : this( + left = rect.left.toShort(), + top = rect.top.toShort(), + right = rect.right.toShort(), + bottom = rect.bottom.toShort(), + ) + + constructor( + left: Int, + top: Int, + right: Int, + bottom: Int, + ) : this( + left = left.toShort(), + top = top.toShort(), + right = right.toShort(), + bottom = bottom.toShort(), + ) + + constructor( + left: Short, + top: Short, + right: Short, + bottom: Short, + ) : this(pack(left, top, right, bottom)) + + val center: VPoint + get() = VPoint(left, top) + size / 2 + + val size: VPoint + get() = VPoint(width, height) + + override fun toString() = "($left, $top) -> ($right, $bottom)" + + companion object { + val ZERO = VRect(0, 0, 0, 0) + + fun fromCenter(center: VPoint, size: VPoint): VRect { + return VRect( + (center.x - size.x / 2).toShort(), + (center.y - size.y / 2).toShort(), + (center.x + size.x / 2).toShort(), + (center.y + size.y / 2).toShort(), + ) + } + + fun fromTopLeft(pos: VPoint, size: VPoint): VRect { + return VRect( + pos.x.toShort(), + pos.y.toShort(), + (pos.x + size.x).toShort(), + (pos.y + size.y).toShort(), + ) + } + } +} diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/TileDetailsViewModel.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/TileDetailsViewModel.kt index be0362fd7481..ac7a85742385 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/TileDetailsViewModel.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/TileDetailsViewModel.kt @@ -16,15 +16,13 @@ package com.android.systemui.plugins.qs -/** - * The base view model class for rendering the Tile's TileDetailsView. - */ -abstract class TileDetailsViewModel { +/** The view model interface for rendering the Tile's TileDetailsView. */ +interface TileDetailsViewModel { // The callback when the settings button is clicked. Currently this is the same as the on tile // long press callback - abstract fun clickOnSettingsButton() + fun clickOnSettingsButton() - abstract fun getTitle(): String + val title: String - abstract fun getSubTitle(): String + val subTitle: String } diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml index 1a49bbb27c8f..0524b34e6b2e 100644 --- a/packages/SystemUI/res-keyguard/values-ar/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml @@ -21,11 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"أدخل رقم التعريف الشخصي (PIN)"</string> - <string name="keyguard_enter_pin" msgid="8114529922480276834">"أدخِل رقم التعريف الشخصي"</string> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"يُرجى إدخال رقم التعريف الشخصي"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"أدخل النقش"</string> <string name="keyguard_enter_pattern" msgid="7616595160901084119">"ارسم النقش"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"أدخل كلمة المرور"</string> - <string name="keyguard_enter_password" msgid="6483623792371009758">"أدخِل كلمة المرور"</string> + <string name="keyguard_enter_password" msgid="6483623792371009758">"يُرجى إدخال كلمة المرور"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"بطاقة غير صالحة."</string> <string name="keyguard_charged" msgid="5478247181205188995">"اكتمل الشحن"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • جارٍ الشحن لاسلكيًا"</string> diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml index 9eb89b67fdde..cd63405f1c00 100644 --- a/packages/SystemUI/res-keyguard/values-hi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml @@ -23,7 +23,7 @@ <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"अपना पिन डालें"</string> <string name="keyguard_enter_pin" msgid="8114529922480276834">"पिन डालें"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"अपना पैटर्न डालें"</string> - <string name="keyguard_enter_pattern" msgid="7616595160901084119">"पैटर्न ड्रॉ करें"</string> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"पैटर्न बनाएं"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"अपना पासवर्ड डालें"</string> <string name="keyguard_enter_password" msgid="6483623792371009758">"पासवर्ड डालें"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"गलत कार्ड."</string> diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml index f014c298e2c6..67ee3ed1b99d 100644 --- a/packages/SystemUI/res-keyguard/values-iw/strings.xml +++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml @@ -23,7 +23,7 @@ <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"מה קוד האימות שלך?"</string> <string name="keyguard_enter_pin" msgid="8114529922480276834">"צריך להזין קוד אימות"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"יש להזין קו ביטול נעילה"</string> - <string name="keyguard_enter_pattern" msgid="7616595160901084119">"צריך לצייר קו ביטול נעילה"</string> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"צריך לצייר את קו פתיחת הנעילה"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"יש להזין סיסמה"</string> <string name="keyguard_enter_password" msgid="6483623792371009758">"צריך להזין סיסמה"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"כרטיס לא חוקי."</string> diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml index 6b08a3a420cc..dbfc4940614a 100644 --- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml @@ -62,7 +62,7 @@ <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"请重试,或输入 PIN 码"</string> <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"请重试,或输入密码"</string> <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"请重试,或绘制解锁图案"</string> - <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"如果出错的尝试次数太多,必须输入 PIN 码才能解锁"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"如果错误次数太多,则必须输入 PIN 码才能解锁"</string> <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"如果多次尝试失败,必须输入密码才能解锁"</string> <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"如果出错的尝试次数太多,必须绘制图案才能解锁"</string> <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"请使用 PIN 码或指纹解锁"</string> diff --git a/packages/SystemUI/res/drawable/notification_2025_smart_reply_button_background.xml b/packages/SystemUI/res/drawable/notification_2025_smart_reply_button_background.xml index d398f60ddc3c..84e228e436cb 100644 --- a/packages/SystemUI/res/drawable/notification_2025_smart_reply_button_background.xml +++ b/packages/SystemUI/res/drawable/notification_2025_smart_reply_button_background.xml @@ -21,9 +21,9 @@ <item> <inset android:insetLeft="0dp" - android:insetTop="8dp" + android:insetTop="6dp" android:insetRight="0dp" - android:insetBottom="8dp"> + android:insetBottom="6dp"> <shape android:shape="rectangle"> <corners android:radius="@dimen/notification_2025_smart_reply_button_corner_radius" /> <stroke android:width="@dimen/smart_reply_button_stroke_width" diff --git a/packages/SystemUI/res/layout/sidefps_view.xml b/packages/SystemUI/res/layout/sidefps_view.xml index e80ed26cffe5..22599a35ed64 100644 --- a/packages/SystemUI/res/layout/sidefps_view.xml +++ b/packages/SystemUI/res/layout/sidefps_view.xml @@ -20,6 +20,7 @@ android:id="@+id/sidefps_animation" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:contentDescription="@string/accessibility_side_fingerprint_indicator_label" app:lottie_autoPlay="true" app:lottie_loop="true" app:lottie_rawRes="@raw/sfps_pulse"/>
\ No newline at end of file diff --git a/packages/SystemUI/res/raw/fingerprint_dialogue_unlocked_to_checkmark_success_lottie.json b/packages/SystemUI/res/raw/fingerprint_dialogue_unlocked_to_checkmark_success_lottie.json index b1d6a270bc67..3f03fcff7603 100644 --- a/packages/SystemUI/res/raw/fingerprint_dialogue_unlocked_to_checkmark_success_lottie.json +++ b/packages/SystemUI/res/raw/fingerprint_dialogue_unlocked_to_checkmark_success_lottie.json @@ -1 +1 @@ -{"v":"5.7.13","fr":60,"ip":0,"op":55,"w":80,"h":80,"nm":"unlocked_to_checkmark_success","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".colorAccentPrimary","cl":"colorAccentPrimary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[47.143,32,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[2.761,0],[0,-2.7],[0,0]],"o":[[0,0],[0,-2.7],[-2.761,0],[0,0],[0,0]],"v":[[5,5],[5,-0.111],[0,-5],[-5,-0.111],[-5.01,4]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450990677,0.890196084976,0.992156863213,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"t":10,"s":[0]}],"ix":4},"w":{"a":0,"k":2.5,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":85,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".colorAccentPrimary","cl":"colorAccentPrimary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[38,45,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[18,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":2,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450990677,0.890196084976,0.992156863213,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"t":10,"s":[0]}],"ix":4},"w":{"a":0,"k":2.5,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":85,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".colorAccentPrimary","cl":"colorAccentPrimary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[37.999,44.999,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.42,0],[0,1.42],[1.42,0],[0,-1.42]],"o":[[1.42,0],[0,-1.42],[-1.42,0],[0,1.42]],"v":[[0,2.571],[2.571,0],[0,-2.571],[-2.571,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.827450990677,0.890196084976,0.992156863213,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"t":10,"s":[0]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":85,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".green200","cl":"green200","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40.5,40.75,0],"ix":2,"l":2},"a":{"a":0,"k":[12.5,-6.25,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":10,"s":[60,60,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":19,"s":[112,112,100]},{"t":30,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-10.556,-9.889],[7.444,6.555],[34.597,-20.486]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.658823529412,0.854901960784,0.709803921569,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":10,"s":[0]},{"t":20,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":10,"op":910,"st":10,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".green200","cl":"green200","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0]},{"t":15,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2,"l":2},"a":{"a":0,"k":[40.25,40.25,0],"ix":1,"l":2},"s":{"a":0,"k":[93.5,93.5,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.12,0],[0,-22.08],[-22.08,0],[0,22.08]],"o":[[-22.08,0],[0,22.08],[22.12,0],[0,-22.08]],"v":[[-0.04,-40],[-40,0],[-0.04,40],[40,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[40.25,40.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.658823529412,0.854901960784,0.709803921569,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0]},{"t":15,"s":[100]}],"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":10,"s":[0]},{"t":20,"s":[4]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":10,"op":77,"st":10,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".grey700","cl":"grey700","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2,"l":2},"a":{"a":0,"k":[40.25,40.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.12,0],[0,-22.08],[-22.08,0],[0,22.08]],"o":[[-22.08,0],[0,22.08],[22.12,0],[0,-22.08]],"v":[[-0.04,-40],[-40,0],[-0.04,40],[40,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.278431385756,0.278431385756,0.278431385756,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[100]},{"t":20,"s":[0]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[40.25,40.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file +{"v":"5.7.13","fr":60,"ip":0,"op":55,"w":80,"h":80,"nm":"unlocked_to_checkmark_success","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".onPrimary","cl":"onPrimary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[47.143,32,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[2.761,0],[0,-2.7],[0,0]],"o":[[0,0],[0,-2.7],[-2.761,0],[0,0],[0,0]],"v":[[5,5],[5,-0.111],[0,-5],[-5,-0.111],[-5.01,4]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450990677,0.890196084976,0.992156863213,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"t":10,"s":[0]}],"ix":4},"w":{"a":0,"k":2.5,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":85,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".onPrimary","cl":"onPrimary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[38,45,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[18,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":2,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450990677,0.890196084976,0.992156863213,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"t":10,"s":[0]}],"ix":4},"w":{"a":0,"k":2.5,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":85,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".onPrimary","cl":"onPrimary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[37.999,44.999,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.42,0],[0,1.42],[1.42,0],[0,-1.42]],"o":[[1.42,0],[0,-1.42],[-1.42,0],[0,1.42]],"v":[[0,2.571],[2.571,0],[0,-2.571],[-2.571,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.827450990677,0.890196084976,0.992156863213,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"t":10,"s":[0]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":85,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".green200","cl":"green200","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40.5,40.75,0],"ix":2,"l":2},"a":{"a":0,"k":[12.5,-6.25,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":10,"s":[60,60,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":19,"s":[112,112,100]},{"t":30,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-10.556,-9.889],[7.444,6.555],[34.597,-20.486]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.658823529412,0.854901960784,0.709803921569,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":10,"s":[0]},{"t":20,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":10,"op":910,"st":10,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".green200","cl":"green200","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0]},{"t":15,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2,"l":2},"a":{"a":0,"k":[40.25,40.25,0],"ix":1,"l":2},"s":{"a":0,"k":[93.5,93.5,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.12,0],[0,-22.08],[-22.08,0],[0,22.08]],"o":[[-22.08,0],[0,22.08],[22.12,0],[0,-22.08]],"v":[[-0.04,-40],[-40,0],[-0.04,40],[40,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[40.25,40.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.658823529412,0.854901960784,0.709803921569,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0]},{"t":15,"s":[100]}],"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":10,"s":[0]},{"t":20,"s":[4]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":10,"op":77,"st":10,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".primary","cl":"primary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2,"l":2},"a":{"a":0,"k":[40.25,40.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.12,0],[0,-22.08],[-22.08,0],[0,22.08]],"o":[[-22.08,0],[0,22.08],[22.12,0],[0,-22.08]],"v":[[-0.04,-40],[-40,0],[-0.04,40],[40,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.278431385756,0.278431385756,0.278431385756,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[100]},{"t":20,"s":[0]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[40.25,40.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index cbec8c2e0b82..62363358f663 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Ontdemp omgewing"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Nutsgoed"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Intydse Onderskrifte"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Nota"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblokkeer toestelmikrofoon?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Deblokkeer toestelkamera?"</string> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Gebruik verdeelde skerm met app aan die regterkant"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Gebruik verdeelde skerm met app aan die linkerkant"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Gebruik volskerm"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Gebruik rekenaaraansig"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Skakel oor na app regs of onder terwyl jy verdeelde skerm gebruik"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Skakel oor na app links of bo terwyl jy verdeelde skerm gebruik"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Tydens verdeelde skerm: verplaas ’n app van een skerm na ’n ander"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 655f06037922..e180d114a75a 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"በዙሪያ ያሉትን ድምፅ-ከል አንሳ"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"መሣሪያዎች"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"የቀጥታ መግለጫ ጽሑፍ"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"ማስታወሻ"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"መተግበሪያ በስተቀኝ ላይ ሆኖ የተከፈለ ማያ ገፅን ይጠቀሙ"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"መተግበሪያ በስተግራ ላይ ሆኖ የተከፈለ ማያ ገፅን ይጠቀሙ"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"ሙሉ ገፅ ዕይታን ይጠቀሙ"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"የዴስክቶፕ ዕይታ ይጠቀሙ"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"የተከፈለ ማያ ገጽን ሲጠቀሙ በቀኝ ወይም ከታች ወዳለ መተግበሪያ ይቀይሩ"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"የተከፈለ ማያ ገጽን ሲጠቀሙ በቀኝ ወይም ከላይ ወዳለ መተግበሪያ ይቀይሩ"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"በተከፈለ ማያ ገጽ ወቅት፡- መተግበሪያን ከአንዱ ወደ ሌላው ተካ"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index b2d71da5b61d..416eee837b22 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -423,18 +423,17 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"الأصوات المحيطة"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"اليسرى"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"اليمنى"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"الأصوات المحيطة"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"الأصوات المحيطة بالجهة اليسرى"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"الأصوات المحيطة بالجهة اليمنى"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"توسيع لوحة التحكّم الموحّدة إلى عناصر تحكُّم منفصلة على اليسار واليمين"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"تصغير عناصر التحكّم في الصوت إلى لوحة تحكُّم موحّدة"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"كتم الأصوات المحيطة"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"إعادة الأصوات المحيطة"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"الأدوات"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"النسخ النصي التلقائي"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"ملاحظات"</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> @@ -907,7 +906,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"استخدام \"وضع تقسيم الشاشة\" مع تثبيت التطبيق على اليمين"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"استخدام \"وضع تقسيم الشاشة\" مع تثبيت التطبيق على اليسار"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"استخدام وضع ملء الشاشة"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"استخدام وضع العرض المخصّص للكمبيوتر المكتبي"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"التبديل إلى التطبيق على اليسار أو الأسفل أثناء استخدام \"تقسيم الشاشة\""</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"التبديل إلى التطبيق على اليمين أو الأعلى أثناء استخدام \"تقسيم الشاشة\""</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"استبدال تطبيق بآخر في وضع \"تقسيم الشاشة\""</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 6aa9d66ab48f..4340f2132e78 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"আশ-পাশৰ ধ্বনি আনমিউট কৰক"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"সঁজুলি"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"লাইভ কেপশ্বন"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"টোকা"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"সোঁফালে থকা এপ্টোৰ সৈতে বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰক"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"বাওঁফালে থকা এপ্টোৰ সৈতে বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰক"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"পূৰ্ণ স্ক্ৰীন ব্যৱহাৰ কৰক"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"ডেস্কটপ ভিউ ব্যৱহাৰ কৰক"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰাৰ সময়ত সোঁফালে অথবা তলত থকা এপলৈ সলনি কৰক"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰাৰ সময়ত বাওঁফালে অথবা ওপৰত থকা এপলৈ সলনি কৰক"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"বিভাজিত স্ক্ৰীনৰ ব্যৱহাৰ কৰাৰ সময়ত: কোনো এপ্ এখন স্ক্ৰীনৰ পৰা আনখনলৈ নিয়ক"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index b87432f5d342..226c39dad194 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Ətraf mühiti səssiz rejimdən çıxarın"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Alətlər"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Canlı Altyazı"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Qeyd"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Tətbiq sağda olmaqla bölünmüş ekranı istifadə edin"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Tətbiq solda olmaqla bölünmüş ekranı istifadə edin"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Tam ekrandan istifadə edin"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Masaüstü görünüşdən istifadə edin"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Bölünmüş ekran istifadə edərkən sağda və ya aşağıda tətbiqə keçin"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Bölünmüş ekran istifadə edərkən solda və ya yuxarıda tətbiqə keçin"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Bölünmüş ekran rejimində: tətbiqi birindən digərinə dəyişin"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index a875e7361335..0d7619d36e75 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Uključi zvuk okruženja"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Alatke"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Titl uživo"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Beleška"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Želite da odblokirate mikrofon uređaja?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Želite da odblokirate kameru uređaja?"</string> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Koristi podeljeni ekran sa aplikacijom s desne strane"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Koristi podeljeni ekran sa aplikacijom s leve strane"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Koristi prikaz preko celog ekrana"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Koristi prikaz za računare"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Pređi u aplikaciju zdesna ili ispod dok je podeljen ekran"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Pređite u aplikaciju sleva ili iznad dok koristite podeljeni ekran"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"U režimu podeljenog ekrana: zamena jedne aplikacije drugom"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 75d0a44f38a1..809b60b712a1 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Уключыць навакольныя гукі"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Інструменты"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Аўтаматычныя субцітры"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Нататка"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Падзяліць экран і памясціць праграму справа"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Падзяліць экран і памясціць праграму злева"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Выкарыстоўваць поўнаэкранны рэжым"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Выкарыстоўваць версію для камп’ютараў"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Пераключыцца на праграму справа або ўнізе на падзеленым экране"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Пераключыцца на праграму злева або ўверсе на падзеленым экране"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"У рэжыме падзеленага экрана замяніць адну праграму на іншую"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 4f3d64124e04..9f7a9cdda45b 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -423,18 +423,17 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Околни звуци"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Ляво"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Дясно"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"Околни звуци"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"Околни звуци отляво"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"Околни звуци отдясно"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Разгъване до отделни контроли за ляво и дясно"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Свиване до обединена контрола"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Спиране на околните звуци"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Включване на околните звуци"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Инструменти"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Надписи на живо"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Бележка"</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> @@ -907,7 +906,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Използване на разделен екран с приложението вдясно"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Използване на разделен екран с приложението вляво"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Използване режима на цял екран"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Използване на изгледа за настолни компютри"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Превключване към приложението вдясно/отдолу в режима на разделен екран"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Превключване към приложението вляво/отгоре в режима на разделен екран"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"При разделен екран: замяна на дадено приложение с друго"</string> @@ -1003,8 +1003,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Добавяне към позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Невалидна позиция."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"Панелът вече е добавен"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Панелът е добавен"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Панелът е премахнат"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Редактор за бързи настройки."</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 3fd699db612f..f1d97700c6f3 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"সারাউন্ডিং আনমিউট করুন"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"টুল"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"লাইভ ক্যাপশন"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"মনে রাখবেন"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"ডানদিকে বর্তমান অ্যাপে স্প্লিট স্ক্রিন ব্যবহার করুন"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"বাঁদিকে বর্তমান অ্যাপে স্প্লিট স্ক্রিন ব্যবহার করুন"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"ফুল-স্ক্রিন মোড ব্যবহার করুন"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"ডেস্কটপ ভিউ ব্যবহার করুন"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"স্প্লিট স্ক্রিন ব্যবহার করার সময় ডানদিকের বা নিচের অ্যাপে পাল্টে নিন"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"স্প্লিট স্ক্রিন ব্যবহার করার সময় বাঁদিকের বা উপরের অ্যাপে পাল্টে নিন"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"\'স্প্লিট স্ক্রিন\' থাকাকালীন: একটি অ্যাপ থেকে অন্যটিতে পাল্টান"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 0b5af1771614..57b83d933f53 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Uključivanje zvuka okruženja"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Alati"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Automatski titlovi"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Bilješka"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Korištenje podijeljenog ekrana s aplikacijom na desnoj strani"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Korištenje podijeljenog ekrana s aplikacijom na lijevoj strani"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Korištenje prikaza preko cijelog ekrana"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Korištenje prikaza na računaru"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Prelazak u aplikaciju desno ili ispod uz podijeljeni ekran"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Pređite u aplikaciju lijevo ili iznad dok koristite podijeljeni ekran"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Za vrijeme podijeljenog ekrana: zamjena jedne aplikacije drugom"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 0225d2b27ca8..d2f942eeb628 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -423,18 +423,17 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Entorn"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Esquerra"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Dreta"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"Entorn"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"Entorn esquerre"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"Entorn dret"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Desplega els controls separats d\'esquerra i dreta"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Replega per unificar el control"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Silencia l\'entorn"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Deixa de silenciar l\'entorn"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Eines"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Subtítols instantanis"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Nota"</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> @@ -907,7 +906,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Utilitzar la pantalla dividida amb l\'aplicació a la dreta"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Utilitzar la pantalla dividida amb l\'aplicació a l\'esquerra"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Utilitza la pantalla completa"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Utilitza la visualització per a ordinadors"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Canvia a l\'aplicació de la dreta o de sota amb la pantalla dividida"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Canvia a l\'aplicació de l\'esquerra o de dalt amb la pantalla dividida"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Durant el mode de pantalla dividida: substitueix una app per una altra"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 8a6980e355c0..5149f9d8c1af 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Zapnout zvuk okolí"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Nástroje"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Okamžité titulky"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Poznámka"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Odblokovat mikrofon zařízení?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Odblokovat fotoaparát zařízení?"</string> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Použít rozdělenou obrazovku s aplikací vpravo"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Použít rozdělenou obrazovku s aplikací vlevo"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Použít celou obrazovku"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Použít zobrazení na počítači"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Přepnout na aplikaci vpravo nebo dole v režimu rozdělené obrazovky"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Přepnout na aplikaci vlevo nebo nahoře v režimu rozdělené obrazovky"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"V režimu rozdělené obrazovky: nahradit jednu aplikaci druhou"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 60c5c1c5e1c0..baf010ddae5d 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Ignorer ikke omgivelser"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Værktøjer"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Livetekstning"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Note"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Brug opdelt skærm med appen til højre"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Brug opdelt skærm med appen til venstre"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Brug fuld skærm"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Brug computervenlig visning"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Skift til en app til højre eller nedenfor, når du bruger opdelt skærm"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Skift til en app til venstre eller ovenfor, når du bruger opdelt skærm"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Ved opdelt skærm: Udskift én app med en anden"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 66b60b18cdae..8c8e994dd9cc 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Stummschaltung der Umgebungsgeräusche aufheben"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Tools"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Automatische Untertitel"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Notiz"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Splitscreen mit der App auf der rechten Seite nutzen"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Splitscreen mit der App auf der linken Seite nutzen"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Vollbildmodus verwenden"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Desktop-Ansicht verwenden"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Im Splitscreen-Modus zu einer App rechts oder unten wechseln"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Im Splitscreen-Modus zu einer App links oder oben wechseln"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Im Splitscreen: eine App durch eine andere ersetzen"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 639aee2d038e..daebf7006498 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Κατάργηση σίγασης ήχων περιβάλλοντος"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Εργαλεία"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Ζωντανοί υπότιτλοι"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Σημείωση"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Χρήση διαχωρισμού οθόνης με την εφαρμογή στα δεξιά"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Χρήση διαχωρισμού οθόνης με την εφαρμογή στα αριστερά"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Χρήση πλήρους οθόνης"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Χρήση προβολής για υπολογιστές"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Εναλλαγή στην εφαρμογή δεξιά ή κάτω κατά τη χρήση διαχωρισμού οθόνης"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Εναλλαγή σε εφαρμογή αριστερά ή επάνω κατά τη χρήση διαχωρισμού οθόνης"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Κατά τον διαχωρισμό οθόνης: αντικατάσταση μιας εφαρμογής με άλλη"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 62441c8682f3..875b21a72166 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -423,18 +423,17 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Surroundings"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Left"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Right"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"Surroundings"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"Left surroundings"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"Right surroundings"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Expand to left and right separated controls"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Collapse to unified control"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Mute surroundings"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Unmute surroundings"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Tools"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Live Caption"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Note"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string> @@ -907,7 +906,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Use split screen with app on the right"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Use split screen with app on the left"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Use fullscreen"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Use desktop view"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Switch to the app on the right or below while using split screen"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Switch to the app on the left or above while using split screen"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"During split screen: Replace an app from one to another"</string> @@ -1003,8 +1003,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Add to position <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position invalid."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"Tile already added"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tile added"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tile removed"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Quick settings editor."</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 69aca1fb223e..4e4295ab56a2 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -432,6 +432,7 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Unmute surroundings"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Tools"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Live Caption"</string> + <string name="hearing_devices_settings_button" msgid="999474385481812222">"Settings"</string> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Note"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string> @@ -904,7 +905,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Use split screen with app on the right"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Use split screen with app on the left"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Use full screen"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Use desktop view"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Switch to app on right or below while using split screen"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Switch to app on left or above while using split screen"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"During split screen: replace an app from one to another"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 62441c8682f3..875b21a72166 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -423,18 +423,17 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Surroundings"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Left"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Right"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"Surroundings"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"Left surroundings"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"Right surroundings"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Expand to left and right separated controls"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Collapse to unified control"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Mute surroundings"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Unmute surroundings"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Tools"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Live Caption"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Note"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string> @@ -907,7 +906,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Use split screen with app on the right"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Use split screen with app on the left"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Use fullscreen"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Use desktop view"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Switch to the app on the right or below while using split screen"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Switch to the app on the left or above while using split screen"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"During split screen: Replace an app from one to another"</string> @@ -1003,8 +1003,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Add to position <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position invalid."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"Tile already added"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tile added"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tile removed"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Quick settings editor."</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 62441c8682f3..875b21a72166 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -423,18 +423,17 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Surroundings"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Left"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Right"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"Surroundings"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"Left surroundings"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"Right surroundings"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Expand to left and right separated controls"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Collapse to unified control"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Mute surroundings"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Unmute surroundings"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Tools"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Live Caption"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Note"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string> @@ -907,7 +906,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Use split screen with app on the right"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Use split screen with app on the left"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Use fullscreen"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Use desktop view"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Switch to the app on the right or below while using split screen"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Switch to the app on the left or above while using split screen"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"During split screen: Replace an app from one to another"</string> @@ -1003,8 +1003,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Add to position <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position invalid."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"Tile already added"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tile added"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tile removed"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Quick settings editor."</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 840afd45cdf2..c2dd040426a8 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -423,18 +423,16 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Sonido envolvente"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Izquierda"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Derecha"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"Sonido envolvente"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"Entorno de la izquierda"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"Entorno de la derecha"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Expandir los controles separados a la izquierda y a la derecha"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Contraer al control unificado"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Silenciar el sonido envolvente"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Activar el sonido envolvente"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Herramientas"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Subtitulado instantáneo"</string> + <string name="hearing_devices_settings_button" msgid="999474385481812222">"Configuración"</string> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Nota"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"¿Quieres desbloquear el micrófono del dispositivo?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"¿Quieres desbloquear la cámara del dispositivo?"</string> @@ -907,7 +905,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Usar la pantalla dividida con la app a la derecha"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Usar la pantalla dividida con la app a la izquierda"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Usar la pantalla completa"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Usar la vista para computadoras de escritorio"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Ubicar la app a la derecha o abajo cuando usas la pantalla dividida"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Ubicar la app a la izquierda o arriba cuando usas la pantalla dividida"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Durante pantalla dividida: Reemplaza una app con otra"</string> @@ -1003,8 +1002,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Agregar a la posición <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posición no válida"</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posición <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"Tarjeta ya agregada"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Se agregó la tarjeta"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Se quitó la tarjeta"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de Configuración rápida"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 177f298d0121..7902db813708 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Dejar de silenciar alrededores"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Herramientas"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Subtítulos automáticos"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Nota"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Usar la pantalla dividida con la aplicación a la derecha"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Usar la pantalla dividida con la aplicación a la izquierda"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Usar pantalla completa"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Usar vista para ordenador"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Cambiar a la aplicación de la derecha o de abajo en pantalla dividida"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Cambiar a la app de la izquierda o de arriba en pantalla dividida"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Con pantalla dividida: reemplazar una aplicación por otra"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index be021fc96f9d..723a3eb1f401 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Ümbritsevate helide vaigistuse tühistamine"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Tööriistad"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Reaalajas subtiitrid"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Märkus"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Kas tühistada seadme mikrofoni blokeerimine?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Kas tühistada seadme kaamera blokeerimine?"</string> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Jagatud ekraanikuva kasutamine, rakendus kuvatakse paremal"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Jagatud ekraanikuva kasutamine, rakendus kuvatakse vasakul"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Lülita täisekraanile"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Kasuta arvutivaadet"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Paremale või alumisele rakendusele lülitamine jagatud ekraani ajal"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Vasakule või ülemisele rakendusele lülitamine jagatud ekraani ajal"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Ekraanikuva jagamise ajal: ühe rakenduse asendamine teisega"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index edcc17225ace..55b223ae5ac1 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Aktibatu ingurunearen audioa"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Tresnak"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Istanteko azpitituluak"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Oharra"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Erabili pantaila zatitua eta ezarri aplikazio hau eskuinean"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Erabili pantaila zatitua eta ezarri aplikazio hau ezkerrean"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Erabili pantaila osoa"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Erabili ordenagailuetarako ikuspegia"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Aldatu eskuineko edo beheko aplikaziora pantaila zatitua erabiltzean"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Aldatu ezkerreko edo goiko aplikaziora pantaila zatitua erabiltzean"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Pantaila zatituan zaudela, ordeztu aplikazio bat beste batekin"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index f1f6a14568a5..c28ec975e931 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"صدادار کردن پیرامون"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ابزارها"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"زیرنویس زنده ناشنوایان"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"یادداشت"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"استفاده از صفحهٔ دونیمه با قرار گرفتن برنامه در سمت راست"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"استفاده از صفحهٔ دونیمه با قرار گرفتن برنامه در سمت چپ"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"استفاده از حالت تمامصفحه"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"استفاده از نمای ویژه رایانه رومیزی"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"رفتن به برنامه سمت راست یا پایین درحین استفاده از صفحهٔ دونیمه"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"رفتن به برنامه سمت چپ یا بالا درحین استفاده از صفحهٔ دونیمه"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"درحین صفحهٔ دونیمه: برنامهای را با دیگری جابهجا میکند"</string> @@ -1003,8 +1006,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"افزودن به موقعیت <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"موقعیت نامعتبر است."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"موقعیت <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"کاشی قبلاً اضافه شده است"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"کاشی اضافه شد"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"کاشی حذف شد"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ویرایشگر تنظیمات سریع."</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 747659956dbf..98f4883fe880 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -437,6 +437,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Poista ympäristön mykistys"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Työkalut"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Livetekstitys"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Muistiinpano"</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> @@ -909,7 +911,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Käytä jaettua näyttöä niin, että sovellus on oikealla"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Käytä jaettua näyttöä niin, että sovellus on vasemmalla"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Käytä koko näytön tilaa"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Käytä tietokonenäkymää"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Vaihda sovellukseen oikealla tai alapuolella jaetussa näytössä"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Vaihda sovellukseen vasemmalla tai yläpuolella jaetussa näytössä"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Jaetun näytön aikana: korvaa sovellus toisella"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index e22f306b0d57..95adcd3e05a4 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Réactiver les sons de l\'environnement"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Outils"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Sous-titres instantanés"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Note"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Débloquer le microphone de l\'appareil?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Débloquer l\'appareil photo de l\'appareil?"</string> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Utiliser l\'Écran divisé avec l\'appli à droite"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Utiliser l\'Écran divisé avec l\'appli à gauche"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Utiliser le mode plein écran"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Utiliser l\'affichage sur ordinateur de bureau"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Passer à l\'appli à droite ou en dessous avec l\'Écran divisé"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Passer à l\'appli à gauche ou au-dessus avec l\'Écran divisé"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"En mode d\'écran divisé : remplacer une appli par une autre"</string> @@ -1003,8 +1006,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ajouter à la position <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position incorrecte."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"Tuile déjà ajoutée"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tuile ajoutée"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tuile retirée"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Éditeur de paramètres rapides."</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index cceab1c3689b..04c147cdd5a7 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Réactiver le mode Sons environnants"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Outils"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Sous-titres instantanés"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Note"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Débloquer le micro de l\'appareil ?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Débloquer la caméra de l\'appareil ?"</string> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Utiliser l\'écran partagé avec l\'appli sur la droite"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Utiliser l\'écran partagé avec l\'appli sur la gauche"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Utiliser le mode plein écran"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Utiliser l\'affichage sur ordinateur"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Passer à l\'appli à droite ou en dessous avec l\'écran partagé"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Passez à l\'appli à gauche ou au-dessus avec l\'écran partagé"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"En mode écran partagé : Remplacer une appli par une autre"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index f54a634eaa18..6ab779a2569c 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Activar o son ambiental"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Ferramentas"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Subtítulos instantáneos"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Nota"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Usar pantalla dividida coa aplicación na dereita"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Usar pantalla dividida coa aplicación na esquerda"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Usar a pantalla completa"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Usar a vista para ordenadores"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Cambiar á aplicación da dereita ou de abaixo coa pantalla dividida"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Cambiar á aplicación da esquerda ou de arriba coa pantalla dividida"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"En modo de pantalla dividida: Substituír unha aplicación por outra"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 1830b347f829..a0dbf73fa73f 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -438,6 +438,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"આસપાસના અવાજો અનમ્યૂટ કરો"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ટૂલ"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"લાઇવ કૅપ્શન"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"નોંધ"</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> @@ -910,7 +912,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"હાલની ઍપને જમણી બાજુએ રાખીને વિભાજિત સ્ક્રીનનો ઉપયોગ કરો"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"હાલની ઍપને ડાબી બાજુએ રાખીને વિભાજિત સ્ક્રીનનો ઉપયોગ કરો"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"પૂર્ણ સ્ક્રીનનો ઉપયોગ કરો"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"ડેસ્કટૉપ વ્યૂનો ઉપયોગ કરો"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"વિભાજિત સ્ક્રીનનો ઉપયોગ કરતી વખતે જમણી બાજુ કે નીચેની ઍપ પર સ્વિચ કરો"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"વિભાજિત સ્ક્રીનનો ઉપયોગ કરતી વખતે ડાબી બાજુની કે ઉપરની ઍપ પર સ્વિચ કરો"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"વિભાજિત સ્ક્રીન દરમિયાન: એક ઍપને બીજી ઍપમાં બદલો"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 644980062f9f..0b8666115cb6 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"आस-पास के वॉल्यूम को अनम्यूट करें"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"टूल"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"लाइव कैप्शन"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"नोट"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"स्प्लिट स्क्रीन की सुविधा चालू करें और इस ऐप्लिकेशन को दाईं ओर दिखाएं"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"स्प्लिट स्क्रीन की सुविधा चालू करें और इस ऐप्लिकेशन को बाईं ओर दिखाएं"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"फ़ुल स्क्रीन मोड का इस्तेमाल करें"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"डेस्कटॉप व्यू मोड का इस्तेमाल करें"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"स्प्लिट स्क्रीन पर, दाईं ओर या नीचे के ऐप पर स्विच करने के लिए"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"स्प्लिट स्क्रीन पर, बाईं ओर या ऊपर के ऐप पर स्विच करने के लिए"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"स्प्लिट स्क्रीन के दौरान: एक ऐप्लिकेशन को दूसरे ऐप्लिकेशन से बदलें"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 7db95fe316ce..608b498d2100 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Uključi zvuk okruženja"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Alati"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Automatski titlovi"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Napomena"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Upotreba podijeljenog zaslona s aplikacijom s desne strane"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Upotreba podijeljenog zaslona s aplikacijom s lijeve strane"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Upotreba prikaza na cijelom zaslonu"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Upotreba prikaza na računalu"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Prelazak na aplikaciju zdesna ili ispod uz podijeljeni zaslon"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Prelazak na aplikaciju slijeva ili iznad uz podijeljeni zaslon"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Tijekom podijeljenog zaslona: zamijeni aplikaciju drugom"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 906ce54f33fd..36187b97d70b 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Környezet némításának feloldása"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Eszközök"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Élő feliratozás"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Megjegyzés"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Feloldja az eszköz mikrofonjának letiltását?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Feloldja az eszköz kamerájának letiltását?"</string> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Osztott képernyő használata, az alkalmazás a jobb oldalon van"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Osztott képernyő használata, az alkalmazás a bal oldalon van"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Teljes képernyő használata"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Asztali nézet használata"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Váltás a jobb oldalt, illetve lent lévő appra osztott képernyő esetén"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Váltás a bal oldalt, illetve fent lévő appra osztott képernyő esetén"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Osztott képernyőn: az egyik alkalmazás lecserélése egy másikra"</string> @@ -1003,8 +1006,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Hozzáadás a következő pozícióhoz: <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Érvénytelen pozíció."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. hely"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"A kártya már hozzá van adva"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kártya hozzáadva"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kártya eltávolítva"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Gyorsbeállítások szerkesztője"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 57a822e138c2..6a7543f754fd 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -423,18 +423,17 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Շրջակայք"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Ձախ"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Աջ"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"Շրջակայք"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"Ձախ շրջակայք"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"Աջ շրջակայք"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Ծավալել՝ դարձնելով կառավարման աջ և ձախ առանձնացված տարրեր"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Ծալել՝ դարձնելով կառավարման մեկ միասնական տարր"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Անջատել շրջակայքի ձայները"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Միացնել շրջակայքի ձայները"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Գործիքներ"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Կենդանի ենթագրեր"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Նշում"</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> @@ -907,7 +906,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Տրոհել էկրանը և տեղավորել այս հավելվածը աջ կողմում"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Տրոհել էկրանը և տեղավորել այս հավելվածը ձախ կողմում"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Օգտագործեք լիաէկրան ռեժիմը"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Օգտագործեք համակարգչային տարբերակը"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Անցեք աջ կողմի կամ ներքևի հավելվածին տրոհված էկրանի միջոցով"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Անցեք աջ կողմի կամ վերևի հավելվածին տրոհված էկրանի միջոցով"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Տրոհված էկրանի ռեժիմում մեկ հավելվածը փոխարինել մյուսով"</string> @@ -1003,8 +1003,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ավելացնել դիրք <xliff:g id="POSITION">%1$d</xliff:g>-ում"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Դիրքն անվավեր է։"</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Դիրք <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"Սալիկն արդեն ավելացվել է"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Սալիկն ավելացվեց"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Սալիկը հեռացվեց"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Արագ կարգավորումների խմբագրիչ:"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 2d38c8fa8e7a..c09e03c428d2 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Bunyikan suara sekitar"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Alat"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Teks Otomatis"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Catatan"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Gunakan layar terpisah dengan aplikasi di sebelah kanan"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Gunakan layar terpisah dengan aplikasi di sebelah kiri"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Gunakan layar penuh"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Gunakan tampilan desktop"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Beralih ke aplikasi di bagian kanan atau bawah saat menggunakan layar terpisah"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Beralih ke aplikasi di bagian kiri atau atas saat menggunakan layar terpisah"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Dalam layar terpisah: ganti salah satu aplikasi dengan yang lain"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 5c37bdb40161..b853a5561c4c 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -423,18 +423,17 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Umhverfi"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Vinstri"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Hægri"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"Umhverfi"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"Umhverfi til vinstri"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"Umhverfi til hægri"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Aðskilja stýringar til vinstri og hægri"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Taka saman í eina stýringu"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Þagga umhverfi"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Kveikja á hljóði umhverfis"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Verkfæri"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Skjátextar í rauntíma"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Glósa"</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> @@ -907,7 +906,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Notaðu skjáskiptingu fyrir forritið til hægri"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Notaðu skjáskiptingu fyrir forritið til vinstri"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Nota allan skjáinn"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Nota tölvuútgáfu"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Skiptu í forrit til hægri eða fyrir neðan þegar skjáskipting er notuð"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Skiptu í forrit til vinstri eða fyrir ofan þegar skjáskipting er notuð"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Í skjáskiptingu: Skipta forriti út fyrir annað forrit"</string> @@ -1003,8 +1003,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Bæta við í stöðu <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Staða ógild."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Staða <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"Skífu hefur þegar verið bætt við"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Reit bætt við"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Reitur fjarlægður"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Flýtistillingaritill."</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index a21b6dbac247..ceb1ca1c5cb4 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -423,18 +423,17 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Audio ambientale"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Sinistra"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Destra"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"Audio ambientale"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"Audio ambientale a sinistra"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"Audio ambientale a destra"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Espandi controlli separati a sinistra e a destra"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Comprimi in controllo unificato"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Disattiva audio ambientale"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Riattiva audio ambientale"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Strumenti"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Sottotitoli in tempo reale"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Nota"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vuoi sbloccare il microfono del dispositivo?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vuoi sbloccare la fotocamera del dispositivo?"</string> @@ -907,7 +906,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Utilizza lo schermo diviso con l\'app a destra"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Utilizza lo schermo diviso con l\'app a sinistra"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Utilizza la modalità a schermo intero"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Utilizza la visualizzazione desktop"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Passa all\'app a destra o sotto mentre usi lo schermo diviso"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Passa all\'app a sinistra o sopra mentre usi lo schermo diviso"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Con lo schermo diviso: sostituisci un\'app con un\'altra"</string> @@ -1003,8 +1003,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Aggiungi alla posizione <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posizione non valida."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posizione <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"Riquadro già aggiunto"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Riquadro aggiunto"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Riquadro rimosso"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor di impostazioni rapide."</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 936b10e520d5..8123c7e2ea38 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -252,10 +252,8 @@ <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"התבצע חיבור אל <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> <string name="accessibility_cast_name" msgid="7344437925388773685">"מחובר אל <xliff:g id="CAST">%s</xliff:g>."</string> <string name="accessibility_expand_group" msgid="521237935987978624">"הרחבת הקבוצה."</string> - <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) --> - <skip /> - <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) --> - <skip /> + <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"הוספת מכשיר לקבוצה"</string> + <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"הסרת מכשיר מקבוצה"</string> <string name="accessibility_open_application" msgid="1749126077501259712">"פתיחת האפליקציה."</string> <string name="accessibility_not_connected" msgid="4061305616351042142">"אין חיבור."</string> <string name="data_connection_roaming" msgid="375650836665414797">"נדידה"</string> @@ -333,8 +331,7 @@ <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"קלט"</string> <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"מכשירי שמיעה"</string> <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ההפעלה מתבצעת…"</string> - <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) --> - <skip /> + <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"אי אפשר לשנות את הבהירות כי היא נקבעת על ידי האפליקציה העליונה"</string> <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"סיבוב אוטומטי"</string> <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"סיבוב אוטומטי של המסך"</string> <string name="quick_settings_location_label" msgid="2621868789013389163">"מיקום"</string> @@ -438,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"ביטול השתקת הרעשים בסביבה"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"כלים"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"כתוביות מיידיות"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"פתק"</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> @@ -910,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"שימוש במסך מפוצל כשהאפליקציה בצד ימין"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"שימוש במסך מפוצל כשהאפליקציה בצד שמאל"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"שימוש במסך מלא"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"שימוש בתצוגה למחשב"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"מעבר לאפליקציה משמאל או למטה בזמן שימוש במסך מפוצל"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"מעבר לאפליקציה מימין או למעלה בזמן שימוש במסך מפוצל"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"כשהמסך מפוצל: החלפה בין אפליקציה אחת לאחרת"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index d5ecfe538b89..2fc703c44ca2 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -423,18 +423,16 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"周囲の音"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"左"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"右"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"周囲の音"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"周囲の音(左)"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"周囲の音(右)"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"開く - 左右それぞれで制御する"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"閉じる - まとめて制御する"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"周囲の音をミュート"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"周囲の音のミュートを解除"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ツール"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"自動字幕起こし"</string> + <string name="hearing_devices_settings_button" msgid="999474385481812222">"設定"</string> <string name="quick_settings_notes_label" msgid="1028004078001002623">"注"</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> @@ -907,7 +905,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"分割画面の使用(アプリを右側に表示)"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"分割画面の使用(アプリを左側に表示)"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"全画面表示に切り替える"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"デスクトップ ビューを使用する"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"分割画面の使用時に右側または下部のアプリに切り替える"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"分割画面の使用時に左側または上部のアプリに切り替える"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"分割画面中: アプリを順に置換する"</string> @@ -1003,8 +1002,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"ポジション <xliff:g id="POSITION">%1$d</xliff:g> に追加"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"位置が無効です。"</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置: <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"タイルはすでに追加されています"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"タイルを追加しました"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"タイルを削除しました"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"クイック設定エディタ"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 2e3dc98eb153..86f8e33b2d76 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -423,18 +423,16 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"გარემოცვა"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"მარცხენა"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"მარჯვენა"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"გარემოცვა"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"მარცხენა გარემოცვა"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"მარჯვენა გარემოცვა"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"განცალკევებული მართვის საშუალებების გაფართოება მარცხნივ და მარჯვნივ"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"ერთიანი მართვის ჩაკეცვა"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"გარემოცვის დადუმება"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"გარემოცვის დადუმების მოხსნა"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ხელსაწყოები"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"ავტოსუბტიტრები"</string> + <string name="hearing_devices_settings_button" msgid="999474385481812222">"პარამეტრები"</string> <string name="quick_settings_notes_label" msgid="1028004078001002623">"ჩანიშვნა"</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> @@ -907,7 +905,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"ეკრანის გაყოფის გამოყენება აპზე მარჯვნივ"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"ეკრანის გაყოფის გამოყენება აპზე მარცხნივ"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"სრული ეკრანის გამოყენება"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"დესკტოპის ხედის გამოყენება"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ეკრანის გაყოფის გამოყენებისას აპზე მარჯვნივ ან ქვემოთ გადართვა"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ეკრანის გაყოფის გამოყენებისას აპზე მარცხნივ ან ზემოთ გადართვა"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"ეკრანის გაყოფის დროს: ერთი აპის მეორით ჩანაცვლება"</string> @@ -1003,8 +1002,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"დამატება პოზიციაზე <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"პოზიცია არასწორია."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"პოზიცია <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"მოზაიკის ფილა უკვე დამატებულია"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"მოზაიკის ფილა დაემატა"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"მოზაიკის ფილა ამოიშალა"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"სწრაფი პარამეტრების რედაქტორი."</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 1c4d31a6b758..1a7532b938d7 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -247,7 +247,7 @@ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Құрылғы деректерін конфигурациялау үшін басыңыз."</string> <string name="accessibility_bluetooth_device_settings_gear_with_name" msgid="114373701123165491">"<xliff:g id="DEVICE_NAME">%s</xliff:g>. Құрылғы мәліметтерін конфигурациялау"</string> <string name="accessibility_bluetooth_device_settings_see_all" msgid="5260390270128256620">"Барлық құрылғыны көру"</string> - <string name="accessibility_bluetooth_device_settings_pair_new_device" msgid="7988547106800504256">"Жаңа құрылғыны жұптау"</string> + <string name="accessibility_bluetooth_device_settings_pair_new_device" msgid="7988547106800504256">"Жаңа құрылғымен жұптау"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батарея зарядының мөлшері белгісіз."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> қосылған."</string> <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> трансляциясына қосылды."</string> @@ -306,7 +306,7 @@ <string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string> <string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Жұптасқан құрылғылар жоқ"</string> <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Құрылғыны жалғау не ажырату үшін түртіңіз."</string> - <string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Жаңа құрылғыны жұптау"</string> + <string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Жаңа құрылғымен жұптау"</string> <string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Барлығын көру"</string> <string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth-ты пайдалану"</string> <string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Қосылды"</string> @@ -415,7 +415,7 @@ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Қосулы"</string> <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Ажыратулы"</string> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Есту құрылғылары"</string> - <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Жаңа құрылғыны жұптау"</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> @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Айналаның дыбысын қосу"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Құралдар"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Live Caption"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Ескертпе"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Қолданбаны бөлінген экранның оң жағынан пайдалану"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Қолданбаны бөлінген экранның сол жағынан пайдалану"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Толық экранды пайдалану"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Компьютерлік нұсқаны пайдалану"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Бөлінген экранда оң не төмен жақтағы қолданбаға ауысу"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Бөлінген экранда сол не жоғары жақтағы қолданбаға ауысу"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Экранды бөлу кезінде: бір қолданбаны басқасымен алмастыру"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 8b3bfcc1d30b..43c5c700d206 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"បើកសំឡេងមជ្ឈដ្ឋានជុំវិញ"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ឧបករណ៍"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"អក្សររត់ក្នុងពេលជាក់ស្ដែង"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"កំណត់ចំណាំ"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"ប្រើមុខងារបំបែកអេក្រង់ជាមួយកម្មវិធីនៅខាងស្ដាំ"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"ប្រើមុខងារបំបែកអេក្រង់ជាមួយកម្មវិធីនៅខាងឆ្វេង"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"ប្រើអេក្រង់ពេញ"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"ប្រើទិដ្ឋភាពលើកុំព្យូទ័រ"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ប្ដូរទៅកម្មវិធីនៅខាងស្ដាំ ឬខាងក្រោម ពេលកំពុងប្រើមុខងារបំបែកអេក្រង់"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ប្ដូរទៅកម្មវិធីនៅខាងឆ្វេង ឬខាងលើ ពេលកំពុងប្រើមុខងារបំបែកអេក្រង់"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"ក្នុងអំឡុងពេលប្រើមុខងារបំបែកអេក្រង់៖ ជំនួសកម្មវិធីពីមួយទៅមួយទៀត"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 50f8c60537ba..8de5281e0a3f 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -423,18 +423,16 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"ಆ್ಯಂಬಿಯೆಂಟ್ ವಾಲ್ಯೂಮ್"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ಎಡ"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"ಬಲ"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"ಆ್ಯಂಬಿಯೆಂಟ್ ವಾಲ್ಯೂಮ್"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"ಎಡಭಾಗದ ಆ್ಯಂಬಿಯೆಂಟ್ ವಾಲ್ಯೂಮ್"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"ಬಲಭಾಗದ ಆ್ಯಂಬಿಯೆಂಟ್ ವಾಲ್ಯೂಮ್"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"ಪ್ರತ್ಯೇಕ ಎಡ ಮತ್ತು ಬಲ ಕಂಟ್ರೋಲ್ಗಳಿಗಾಗಿ ವಿಸ್ತರಿಸಿ"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"ಯೂನಿಫೈಡ್ ಕಂಟ್ರೋಲ್ಗಾಗಿ ಕುಗ್ಗಿಸಿ"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"ಆ್ಯಂಬಿಯೆಂಟ್ ವಾಲ್ಯೂಮ್ ಅನ್ನು ಮ್ಯೂಟ್ ಮಾಡಿ"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"ಆ್ಯಂಬಿಯೆಂಟ್ ವಾಲ್ಯೂಮ್ ಅನ್ನು ಅನ್ಮ್ಯೂಟ್ ಮಾಡಿ"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ಟೂಲ್ಗಳು"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"ಲೈವ್ ಕ್ಯಾಪ್ಶನ್"</string> + <string name="hearing_devices_settings_button" msgid="999474385481812222">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> <string name="quick_settings_notes_label" msgid="1028004078001002623">"ಟಿಪ್ಪಣಿ"</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> @@ -907,7 +905,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"ಬಲಭಾಗದಲ್ಲಿ ಆ್ಯಪ್ ಮೂಲಕ ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಬಳಸಿ"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"ಎಡಭಾಗದಲ್ಲಿ ಆ್ಯಪ್ ಮೂಲಕ ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಬಳಸಿ"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"ಫುಲ್ಸ್ಕ್ರೀನ್ ಅನ್ನು ಬಳಸಿ"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"ಡೆಸ್ಕ್ಟಾಪ್ ವೀಕ್ಷಣೆಯನ್ನು ಬಳಸಿ"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ಸ್ಕ್ರೀನ್ ಬೇರ್ಪಡಿಸಿ ಮೋಡ್ ಬಳಸುವಾಗ ಬಲಭಾಗ ಅಥವಾ ಕೆಳಭಾಗದಲ್ಲಿರುವ ಆ್ಯಪ್ಗೆ ಬದಲಿಸಿ"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ಸ್ಕ್ರೀನ್ ಬೇರ್ಪಡಿಸಿ ಮೋಡ್ ಬಳಸುವಾಗ ಎಡಭಾಗ ಅಥವಾ ಮೇಲ್ಭಾಗದಲ್ಲಿರುವ ಆ್ಯಪ್ಗೆ ಬದಲಿಸಿ"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"ಸ್ಕ್ರೀನ್ ಬೇರ್ಪಡಿಸುವ ಸಮಯದಲ್ಲಿ: ಒಂದು ಆ್ಯಪ್ನಿಂದ ಮತ್ತೊಂದು ಆ್ಯಪ್ಗೆ ಬದಲಿಸಿ"</string> @@ -1003,8 +1002,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ಸ್ಥಾನಕ್ಕೆ ಸೇರಿಸಿ"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ಸ್ಥಾನವು ಅಮಾನ್ಯವಾಗಿದೆ."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ಸ್ಥಾನ <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"ಟೈಲ್ ಅನ್ನು ಈಗಾಗಲೇ ಸೇರಿಸಲಾಗಿದೆ"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ಟೈಲ್ ಸೇರಿಸಲಾಗಿದೆ"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ಟೈಲ್ ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳ ಎಡಿಟರ್."</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 7342f32f116e..c3a1a1a63bc5 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"주변 소리 음소거 해제"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"도구"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"실시간 자막"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"메모"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"앱이 오른쪽에 오도록 화면 분할 사용"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"앱이 왼쪽에 오도록 화면 분할 사용"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"전체 화면 사용"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"데스크톱 뷰 사용"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"화면 분할을 사용하는 중에 오른쪽 또는 아래쪽에 있는 앱으로 전환"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"화면 분할을 사용하는 중에 왼쪽 또는 위쪽에 있는 앱으로 전환하기"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"화면 분할 중: 다른 앱으로 바꾸기"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index f21ee1a401b7..23cc8ee23fb6 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Айланадагы үндөрдү чыгаруу"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Куралдар"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Ыкчам коштомо жазуулар"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Учкай маалымат"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Колдонмону оңго жылдырып, экранды бөлүү"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Колдонмону солго жылдырып, экранды бөлүү"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Толук экранды колдонуу"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Компьютердик версияны колдонуу"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Бөлүнгөн экранда сол же төмөн жактагы колдонмого которулуу"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Бөлүнгөн экранды колдонуп жатканда сол же жогору жактагы колдонмого которулуңуз"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Экранды бөлүү режиминде бир колдонмону экинчисине алмаштыруу"</string> @@ -1003,8 +1006,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g>-позицияга кошуу"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Абал жараксыз."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>-позиция"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"Карточка кошулган"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Карта кошулду"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Карта өчүрүлдү"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Ыкчам параметрлер түзөткүчү."</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 4c778d1ac869..69b79b89cb80 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -423,18 +423,17 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"ສຽງແວດລ້ອມ"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ຊ້າຍ"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"ຂວາ"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"ສຽງແວດລ້ອມ"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"ສຽງແວດລ້ອມຂ້າງຊ້າຍ"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"ສຽງແວດລ້ອມຂ້າງຂວາ"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"ຂະຫຍາຍເປັນການຄວບຄຸມທີ່ແຍກເບື້ອງຊ້າຍ ແລະ ຂວາ"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"ຫຍໍ້ລົງເປັນການຄວບຄຸມແບບຮວມ"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"ປິດສຽງແວດລ້ອມ"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"ເຊົາປິດສຽງແວດລ້ອມ"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ເຄື່ອງມື"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"ຄຳບັນຍາຍສົດ"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"ບັນທຶກ"</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> @@ -907,7 +906,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"ໃຊ້ໂໝດແບ່ງໜ້າຈໍໂດຍໃຫ້ແອັບຢູ່ເບື້ອງຂວາ"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"ໃຊ້ໂໝດແບ່ງໜ້າຈໍໂດຍໃຫ້ແອັບຢູ່ເບື້ອງຊ້າຍ"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"ໃຊ້ແບບເຕັມຈໍ"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"ໃຊ້ມຸມມອງເດັສທັອບ"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ສະຫຼັບໄປໃຊ້ແອັບຢູ່ຂວາ ຫຼື ທາງລຸ່ມໃນຂະນະທີ່ໃຊ້ແບ່ງໜ້າຈໍ"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ສະຫຼັບໄປໃຊ້ແອັບຢູ່ຊ້າຍ ຫຼື ທາງເທິງໃນຂະນະທີ່ໃຊ້ແບ່ງໜ້າຈໍ"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"ໃນລະຫວ່າງແບ່ງໜ້າຈໍ: ໃຫ້ປ່ຽນຈາກແອັບໜຶ່ງເປັນອີກແອັບໜຶ່ງ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index f387a4ed4178..1ed102d9869b 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -423,18 +423,16 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Aplinka"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Kairė"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Dešinė"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"Aplinka"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"Aplinka kairėje"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"Aplinka dešinėje"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Išskleisti į atskirus kairįjį ir dešinįjį valdiklius"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Sutraukti į bendrą valdiklį"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Nutildyti aplinką"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Įjungti aplinkos garsą"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Įrankiai"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Subtitrai realiuoju laiku"</string> + <string name="hearing_devices_settings_button" msgid="999474385481812222">"Nustatymai"</string> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Pastaba"</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> @@ -907,7 +905,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Naudokite išskaidyto ekrano režimą su programa dešinėje"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Naudokite išskaidyto ekrano režimą su programa kairėje"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Naudoti viso ekrano režimą"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Naudoti rodinio versiją staliniams kompiuteriams"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Perjunkite į programą dešinėje arba apačioje išskaidyto ekrano režimu"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Perjunkite į programą kairėje arba viršuje išskaidyto ekrano režimu"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Išskaidyto ekrano režimu: pakeisti iš vienos programos į kitą"</string> @@ -1003,8 +1002,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Pridėkite <xliff:g id="POSITION">%1$d</xliff:g> pozicijoje"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Padėtis netinkama."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> pozicija"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"Išklotinė jau pridėta"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Išklotinė pridėta"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Išklotinė pašalinta"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Sparčiųjų nustatymų redagavimo priemonė."</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index fd549219134f..06bc60102c48 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Ieslēgt apkārtnes skaņas"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Rīki"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Subtitri reāllaikā"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Piezīme"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Izmantot ekrāna sadalīšanu ar lietotni labajā pusē"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Izmantot ekrāna sadalīšanu ar lietotni kreisajā pusē"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Izmantot pilnekrāna režīmu"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Izmantot skatu datorā"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Pāriet uz lietotni pa labi/lejā, kamēr izmantojat sadalīto ekrānu."</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Pāriet uz lietotni pa kreisi/augšā, kamēr izmantojat sadalīto ekrānu."</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Ekrāna sadalīšanas režīmā: pārvietot lietotni no viena ekrāna uz otru"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 2afe93ea7aae..c1a5d365c4b0 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Вклучи го звукот на опкружувањето"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Алатки"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Автоматски титлови"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Белешка"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Користете поделен екран со апликацијата оддесно"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Користете поделен екран со апликацијата одлево"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Користете цел екран"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Користете приказ на компјутер"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Префрлете се на апликацијата десно или долу при користењето поделен екран"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Префрлете се на апликацијата лево или горе при користењето поделен екран"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"При поделен екран: префрлете ги аплик. од едната на другата страна"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 48d07cb2ae28..fc004c06360c 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"സറൗണ്ടിംഗ്സ് അൺമ്യൂട്ട് ചെയ്യുക"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ടൂളുകൾ"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"തത്സമയ ക്യാപ്ഷൻ"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"കുറിപ്പ്"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"വലതുവശത്തുള്ള ആപ്പിനൊപ്പം സ്ക്രീൻ വിഭജന മോഡ് ഉപയോഗിക്കുക"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"ഇടതുവശത്തുള്ള ആപ്പിനൊപ്പം സ്ക്രീൻ വിഭജന മോഡ് ഉപയോഗിക്കുക"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"പൂർണ സ്ക്രീൻ ഉപയോഗിക്കുക"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"ഡെസ്ക്ടോപ്പ് വ്യൂ ഉപയോഗിക്കുക"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"സ്ക്രീൻ വിഭജന മോഡ് ഉപയോഗിക്കുമ്പോൾ വലതുവശത്തെ/താഴത്തെ ആപ്പിലേക്ക് മാറുക"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"സ്ക്രീൻ വിഭജന മോഡ് ഉപയോഗിക്കുമ്പോൾ ഇടതുവശത്തെ/മുകളിലെ ആപ്പിലേക്ക് മാറൂ"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"സ്ക്രീൻ വിഭജന മോഡിൽ: ഒരു ആപ്പിൽ നിന്ന് മറ്റൊന്നിലേക്ക് മാറുക"</string> @@ -1003,8 +1006,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> എന്ന സ്ഥാനത്തേക്ക് ചേർക്കുക"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"സ്ഥാനം അസാധുവാണ്."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"സ്ഥാനം <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"ടൈൽ ഇതിനകം ചേർത്തിട്ടുണ്ട്"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ടൈൽ ചേർത്തു"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ടൈൽ നീക്കം ചെയ്തു"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ദ്രുത ക്രമീകരണ എഡിറ്റർ."</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index c7fb7da28ead..7d53c479a4b9 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Орчин тойрны дууг нээх"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Хэрэгсэл"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Шууд тайлбар"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Тэмдэглэл"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Аппыг баруун талд байгаагаар дэлгэцийг хуваахыг ашиглах"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Аппыг зүүн талд байгаагаар дэлгэцийг хуваахыг ашиглах"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Бүтэн дэлгэцийг ашиглах"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Дэлгэц дээр харагдах байдлыг ашиглах"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Дэлгэц хуваахыг ашиглаж байхдаа баруун талд эсвэл доор байх апп руу сэлгэ"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Дэлгэц хуваахыг ашиглаж байхдаа зүүн талд эсвэл дээр байх апп руу сэлгэ"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Дэлгэц хуваах үеэр: аппыг нэгээс нөгөөгөөр солих"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 2c5a9a85845d..9eca378c63b3 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"जवळपासचे आवाज अनम्यूट करा"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"टूल"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"लाइव्ह कॅप्शन"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"टीप"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"ॲप उजवीकडे ठेवून स्प्लिट स्क्रीन वापरा"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"ॲप डावीकडे ठेवून स्प्लिट स्क्रीन वापरा"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"फुल स्क्रीन वापरा"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"डेस्कटॉप दृश्य पहा"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"स्प्लिट स्क्रीन वापरताना उजवीकडील किंवा खालील अॅपवर स्विच करा"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"स्प्लिट स्क्रीन वापरताना डावीकडील किंवा वरील अॅपवर स्विच करा"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"स्प्लिट स्क्रीनदरम्यान: एक अॅप दुसऱ्या अॅपने बदला"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 557509860f07..7f7c77743b5d 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -423,18 +423,17 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Persekitaran"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Kiri"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Kanan"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"Persekitaran"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"Persekitaran kiri"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"Persekitaran kanan"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Kembangkan kepada kawalan berasingan sebelah kiri dan kanan"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Kuncupkan kepada kawalan yang disatukan"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Redamkan persekitaran"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Nyahredam persekitaran"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Alatan"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Sari Kata Langsung"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Nota"</string> <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> @@ -907,7 +906,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Gunakan skrin pisah dengan apl pada sebelah kanan"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Gunakan skrin pisah dengan apl pada sebelah kiri"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Gunakan skrin penuh"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Gunakan paparan desktop"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Tukar kepada apl di sebelah kanan/bawah semasa menggunakan skrin pisah"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Tukar kepada apl di sebelah kiri/atas semasa menggunakan skrin pisah"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Semasa skrin pisah: gantikan apl daripada satu apl kepada apl lain"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index b428422e5f07..42cfe5eeb5fb 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"ဝန်းကျင်အသံ ပြန်ဖွင့်ရန်"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"တူးလ်များ"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"တိုက်ရိုက်စာတန်း"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"မှတ်စု"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"အက်ပ်ကို ညာ၌ထားကာ မျက်နှာပြင် ခွဲ၍ပြသခြင်း သုံးရန်"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"အက်ပ်ကို ဘယ်၌ထားကာ မျက်နှာပြင် ခွဲ၍ပြသခြင်း သုံးရန်"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"ဖန်သားပြင်အပြည့် သုံးရန်"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"ဒက်စ်တော့မြင်ကွင်း သုံးရန်"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"မျက်နှာပြင်ခွဲ၍ပြသခြင်း သုံးစဉ် ညာ (သို့) အောက်ရှိအက်ပ်သို့ ပြောင်းရန်"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းသုံးစဉ် ဘယ် (သို့) အထက်ရှိအက်ပ်သို့ ပြောင်းရန်"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"မျက်နှာပြင် ခွဲ၍ပြသစဉ်- အက်ပ်တစ်ခုကို နောက်တစ်ခုနှင့် အစားထိုးရန်"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 95740758c6e7..3b6e891708bc 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Slå på lyden for omgivelsene"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Verktøy"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Direkteteksting"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Merknad"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vil du oppheve blokkeringen av enhetsmikrofonen?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vil du oppheve blokkeringen av enhetskameraet?"</string> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Bruk delt skjerm med appen til høyre"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Bruk delt skjerm med appen til venstre"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Bruk fullskjerm"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Bruk datamaskinvisning"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Bytt til appen til høyre eller under mens du bruker delt skjerm"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Bytt til appen til venstre eller over mens du bruker delt skjerm"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"I delt skjerm: Bytt ut en app"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 4d37f8fd760b..936a0a653220 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"वरपरका आवाज अनम्युट गर्नुहोस्"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"टुलहरू"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"लाइभ क्याप्सन"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"नोट"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"हालको एप दायाँ भागमा पारेर स्प्लिट स्क्रिन प्रयोग गर्नुहोस्"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"हालको एप बायाँ भागमा पारेर स्प्लिट स्क्रिन प्रयोग गर्नुहोस्"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"फुल स्क्रिन प्रयोग गर्नुहोस्"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"डेस्कटप भ्यू प्रयोग गर्नुहोस्"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"स्प्लिट स्क्रिन प्रयोग गर्दै गर्दा दायाँ वा तलको एप चलाउनुहोस्"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"स्प्लिट स्क्रिन प्रयोग गर्दै गर्दा बायाँ वा माथिको एप चलाउनुहोस्"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"स्प्लिट स्क्रिन प्रयोग गरिएका बेला: एउटा स्क्रिनमा भएको एप अर्कोमा लैजानुहोस्"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 26d87522595b..2a81bb424c8e 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -423,18 +423,17 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Omgevingsgeluid"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Links"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Rechts"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"Omgevingsgeluid"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"Omgevingsgeluid links"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"Omgevingsgeluid rechts"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Uitvouwen naar gescheiden bediening voor links en rechts"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Samenvouwen tot geïntegreerde bediening"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Omgevingsgeluid uitzetten"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Omgevingsgeluid aanzetten"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Tools"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Live ondertiteling"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Notitie"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Microfoon van apparaat niet meer blokkeren?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Apparaatcamera niet meer blokkeren?"</string> @@ -907,7 +906,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Gesplitst scherm gebruiken met de app aan de rechterkant"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Gesplitst scherm gebruiken met de app aan de linkerkant"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Volledig scherm gebruiken"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Desktopweergave gebruiken"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Naar de app rechts of onderaan gaan als je een gesplitst scherm gebruikt"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Naar de app links of bovenaan gaan als je een gesplitst scherm gebruikt"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Tijdens gesplitst scherm: een app vervangen door een andere"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index a0e360cf6bcb..e12fe7ecb39e 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"ପରିପାର୍ଶ୍ୱକୁ ଅନମ୍ୟୁଟ କରନ୍ତୁ"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ଟୁଲ"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"ଲାଇଭ କେପ୍ସନ"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"ନୋଟ"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"ଡାହାଣରେ ଆପ ସହିତ ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନକୁ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"ବାମରେ ଆପ ସହିତ ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନକୁ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନ ବ୍ୟବହାର କରନ୍ତୁ"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"ଡେସ୍କଟପ ଭ୍ୟୁ ବ୍ୟବହାର କରନ୍ତୁ"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବା ସମୟରେ ଡାହାଣପଟର ବା ତଳର ଆପକୁ ସୁଇଚ କରନ୍ତୁ"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବା ସମୟରେ ବାମପଟର ବା ଉପରର ଆପକୁ ସୁଇଚ କରନ୍ତୁ"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ସମୟରେ: କୌଣସି ଆପକୁ ଗୋଟିଏରୁ ଅନ୍ୟ ଏକ ଆପରେ ବଦଳାନ୍ତୁ"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index f2a6612bdb8a..26d26dc1e795 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"ਆਲੇ-ਦੁਆਲੇ ਦੇ ਸ਼ੋਰ ਨੂੰ ਅਣਮਿਊਟ ਕਰੋ"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ਟੂਲ"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"ਲਾਈਵ ਸੁਰਖੀਆਂ"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"ਨੋਟ-ਕਥਨ"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"ਸੱਜੇ ਪਾਸੇ ਵਾਲੀ ਐਪ ਨਾਲ ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"ਖੱਬੇ ਪਾਸੇ ਵਾਲੀ ਐਪ ਨਾਲ ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"ਪੂਰੀ ਸਕ੍ਰੀਨ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"ਡੈਸਕਟਾਪ ਦ੍ਰਿਸ਼ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੀ ਵਰਤੋਂ ਕਰਨ ਵੇਲੇ ਸੱਜੇ ਜਾਂ ਹੇਠਾਂ ਮੌਜੂਦ ਐਪ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੀ ਵਰਤੋਂ ਕਰਨ ਵੇਲੇ ਖੱਬੇ ਜਾਂ ਉੱਪਰ ਮੌਜੂਦ ਐਪ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੌਰਾਨ: ਇੱਕ ਐਪ ਨਾਲ ਦੂਜੀ ਐਪ ਨੂੰ ਬਦਲੋ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 99e99e1a2e6a..6b526f292507 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Wyłącz wyciszenie otoczenia"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Narzędzia"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Napisy na żywo"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Notatka"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Odblokować mikrofon urządzenia?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Odblokować aparat urządzenia?"</string> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Podziel ekran z aplikacją widoczną po prawej"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Podziel ekran z aplikacją widoczną po lewej"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Użyj trybu pełnoekranowego"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Użyj wersji na komputery"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Przełącz się na aplikację po prawej lub poniżej na podzielonym ekranie"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Przełącz się na aplikację po lewej lub powyżej na podzielonym ekranie"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Podczas podzielonego ekranu: zastępowanie aplikacji"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 4663dba04bc2..07f87ee1a0cc 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Ativar som ambiente"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Ferramentas"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Legenda instantânea"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Observação"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Desbloquear o microfone do dispositivo?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Desbloquear a câmera do dispositivo?"</string> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Usar a tela dividida com o app à direita"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Usar a tela dividida com o app à esquerda"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Usar tela cheia"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Usar a versão para computadores"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Mudar para o app à direita ou abaixo ao usar a tela dividida"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Mudar para o app à esquerda ou acima ao usar a tela dividida"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Com a tela dividida: substituir um app por outro"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 7a0e4f6e68b2..de1057d543c8 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -423,18 +423,16 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Ambiente"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Esquerda"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Direita"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"Ambiente"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"Ambiente à esquerda"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"Ambiente à direita"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Expandir para controlos separados do lado direito e esquerdo"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Reduzir para controlo unificado"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Desativar som do ambiente"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Reativar som do ambiente"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Ferramentas"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Legendas instantâneas"</string> + <string name="hearing_devices_settings_button" msgid="999474385481812222">"Definições"</string> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Nota"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Desbloquear o microfone do dispositivo?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Desbloquear a câmara do dispositivo?"</string> @@ -907,7 +905,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Use o ecrã dividido com a app à direita"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Use o ecrã dividido com a app à esquerda"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Use o ecrã inteiro"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Use a vista de computador"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Mudar para a app à direita ou abaixo enquanto usa o ecrã dividido"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Mude para a app à esquerda ou acima enquanto usa o ecrã dividido"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Durante o ecrã dividido: substituir uma app por outra"</string> @@ -1003,8 +1002,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adicione à posição <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posição inválida."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posição <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"Mosaico já adicionado"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Cartão adicionado"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Cartão removido"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de definições rápidas."</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 4663dba04bc2..07f87ee1a0cc 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Ativar som ambiente"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Ferramentas"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Legenda instantânea"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Observação"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Desbloquear o microfone do dispositivo?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Desbloquear a câmera do dispositivo?"</string> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Usar a tela dividida com o app à direita"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Usar a tela dividida com o app à esquerda"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Usar tela cheia"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Usar a versão para computadores"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Mudar para o app à direita ou abaixo ao usar a tela dividida"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Mudar para o app à esquerda ou acima ao usar a tela dividida"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Com a tela dividida: substituir um app por outro"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index e8b826b940f4..a6b4983aa0ae 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Activează sunetul ambiental"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Instrumente"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Subtitrări live"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Notă"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Folosește ecranul împărțit cu aplicația în dreapta"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Folosește ecranul împărțit cu aplicația în stânga"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Folosește ecranul complet"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Folosește afișarea pe desktop"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Treci la aplicația din dreapta sau de mai jos cu ecranul împărțit"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Treci la aplicația din stânga sau de mai sus cu ecranul împărțit"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"În modul ecran împărțit: înlocuiește o aplicație cu alta"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 52458ebd176d..693024bcb274 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -423,18 +423,17 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Окружающие звуки"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Левый"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Правый"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"Окружающие звуки"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"Звуки слева"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"Звуки справа"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Разделить на левый и правый элемент управления"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Объединить в один элемент управления"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Заглушить окружающие звуки"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Не заглушать окружающие звуки"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Инструменты"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Автоматические субтитры"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Заметка"</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> @@ -907,7 +906,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Разделить экран и поместить открытое приложение справа"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Разделить экран и поместить открытое приложение слева"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Полноэкранный режим"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Версия для ПК"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Перейти к приложению справа или внизу на разделенном экране"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Перейти к приложению слева или вверху на разделенном экране"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"В режиме разделения экрана заменить одно приложение другим"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 84a981f9db89..8632e13397d2 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"අවට නිහඬ නොකරන්න"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"මෙවලම්"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"සජීවී සිරස්තල"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"සටහන"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"දකුණේ යෙදුම සමග බෙදීම් තිරය භාවිතා කරන්න"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"වම් පැත්තේ යෙදුම සමග බෙදීම් තිරය භාවිතා කරන්න"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"පූර්ණ තිරය භාවිතා කරන්න"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"ඩෙස්ක්ටොප් දසුන භාවිතා කරන්න"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"බෙදුම් තිරය භාවිත කරන අතරතුර දකුණේ හෝ පහළින් ඇති යෙදුමට මාරු වන්න"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"බෙදුම් තිරය භාවිත කරන අතරතුර වමේ හෝ ඉහළ ඇති යෙදුමට මාරු වන්න"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"බෙදුම් තිරය අතරතුර: යෙදුමක් එකකින් තවත් එකක් ප්රතිස්ථාපනය කරන්න"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 78a332a6c45c..03509f314b2b 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -423,18 +423,17 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Okolie"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Vľavo"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Vpravo"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"Okolie"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"Okolie zľava"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"Okolie sprava"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Rozbaliť na samostatné ovládanie ľavej a pravej strany"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Zbaliť na jednotné ovládanie"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Vypnúť zvuk okolia"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Zapnúť zvuk okolia"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Nástroje"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Živý prepis"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Poznámka"</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> @@ -907,7 +906,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Rozdelenie obrazovky, aktuálna aplikácia vpravo"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Rozdelenie obrazovky, aktuálna aplikácia vľavo"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Používať celú obrazovku"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Používať zobrazenie v počítači"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Prechod na aplikáciu vpravo alebo dole pri rozdelenej obrazovke"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Prechod na aplikáciu vľavo alebo hore pri rozdelenej obrazovke"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Počas rozdelenej obrazovky: nahradenie aplikácie inou"</string> @@ -1003,8 +1003,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Pridať na <xliff:g id="POSITION">%1$d</xliff:g>. pozíciu"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Pozícia je neplatná."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. pozícia"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"Karta už bola pridaná"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Karta bola pridaná"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Karta bola odstránená"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor rýchlych nastavení"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 93649f5039d0..10a236c0ed5b 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -423,18 +423,16 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Okolica"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Levo"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Desno"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"Okolica"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"Okolica na levi"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"Okolica na desni"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Razširitev na ločene kontrolnike za levo in desno stran"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Strnitev v enotni kontrolnik"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Izklop okoliškega zvoka"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Vklop okoliškega zvoka"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Orodja"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Samodejni podnapisi"</string> + <string name="hearing_devices_settings_button" msgid="999474385481812222">"Nastavitve"</string> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Opomba"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Želite odblokirati mikrofon v napravi?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Želite odblokirati fotoaparat v napravi?"</string> @@ -907,7 +905,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Uporaba razdeljenega zaslona z aplikacijo na desni"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Uporaba razdeljenega zaslona z aplikacijo na levi"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Uporaba celozaslonskega načina"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Uporaba pogleda za namizni računalnik"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Preklop na aplikacijo desno ali spodaj med uporabo razdeljenega zaslona"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Preklop na aplikacijo levo ali zgoraj med uporabo razdeljenega zaslona"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Pri razdeljenem zaslonu: medsebojna zamenjava aplikacij"</string> @@ -1003,8 +1002,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodajanje na položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Položaj je neveljaven."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"Ploščica je že dodana"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Ploščica je bila dodana"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Ploščica je bila odstranjena"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Urejevalnik hitrih nastavitev."</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 5e69808d7f63..a32fc8aaf267 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Anulo vendosjen në heshtje të ambientit rrethues"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Veglat"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Titrat në çast"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Shënim"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Përdor ekranin e ndarë me aplikacionin në të djathtë"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Përdor ekranin e ndarë me aplikacionin në të majtë"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Përdor ekranin e plotë"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Përdor pamjen e desktopit"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Kalo tek aplikacioni djathtas ose poshtë kur përdor ekranin e ndarë"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Kalo tek aplikacioni në të majtë ose sipër kur përdor ekranin e ndarë"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Gjatë ekranit të ndarë: zëvendëso një aplikacion me një tjetër"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 1b645a8e2017..f99301c44e7d 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Укључи звук окружења"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Алатке"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Титл уживо"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Белешка"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Користи подељени екран са апликацијом с десне стране"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Користи подељени екран са апликацијом с леве стране"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Користи приказ преко целог екрана"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Користи приказ за рачунаре"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Пређи у апликацију здесна или испод док је подељен екран"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Пређите у апликацију слева или изнад док користите подељени екран"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"У режиму подељеног екрана: замена једне апликације другом"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index a4129e0afb18..0085ed26e4cd 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Slå på omgivningsljudet"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Verktyg"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Live Caption"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Anteckning"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vill du återaktivera enhetens mikrofon?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vill du återaktivera enhetens kamera?"</string> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Använd delad skärm med appen till höger"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Använd delad skärm med appen till vänster"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Använd helskärm"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Använd datorvyn"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Byt till appen till höger eller nedanför när du använder delad skärm"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Byt till appen till vänster eller ovanför när du använder delad skärm"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Med delad skärm: ersätt en app med en annan"</string> @@ -1003,8 +1006,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Lägg till på position <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Positionen är ogiltig."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"Kortet har redan lagts till"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kortet har lagts till"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kortet har tagits bort"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Redigerare för snabbinställningar."</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index cb82afff7f91..b7d208a95d85 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Rejesha sauti ya mazingira"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Zana"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Manukuu Papo Hapo"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Dokezo"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Ungependa kuwacha kuzuia maikrofoni ya kifaa?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Ungependa kuacha kuzuia kamera ya kifaa?"</string> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Tumia hali ya kugawa skrini na programu ya sasa iwe upande wa kulia"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Tumia hali ya kugawa skrini na programu ya sasa iwe upande wa kushoto"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Tumia skrini nzima"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Tumia mwonekano wa kompyuta"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Badilisha ili uende kwenye programu iliyo kulia au chini unapotumia hali ya kugawa skrini"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Badilisha uende kwenye programu iliyo kushoto au juu unapotumia hali ya kugawa skrini"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Ukigawanya skrini: badilisha kutoka programu moja hadi nyingine"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 77be6ea6a64b..473be6f14093 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"சுற்றுப்புறங்களின் ஒலியை இயக்கும்"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"கருவிகள்"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"உடனடி வசனம்"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"குறிப்பு"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"ஆப்ஸ் வலதுபுறம் வரும்படி திரைப் பிரிப்பைப் பயன்படுத்துதல்"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"ஆப்ஸ் இடதுபுறம் வரும்படி திரைப் பிரிப்பைப் பயன்படுத்துதல்"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"முழுத்திரையைப் பயன்படுத்து"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"டெஸ்க்டாப் காட்சியைப் பயன்படுத்து"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"திரைப் பிரிப்பைப் பயன்படுத்தும்போது வலது/கீழ் உள்ள ஆப்ஸுக்கு மாறுதல்"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"திரைப் பிரிப்பைப் பயன்படுத்தும்போது இடது/மேலே உள்ள ஆப்ஸுக்கு மாறுதல்"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"திரைப் பிரிப்பின்போது: ஓர் ஆப்ஸுக்குப் பதிலாக மற்றொன்றை மாற்றுதல்"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index b4665190f33d..a75dd225bb24 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -423,18 +423,16 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"పరిసరాలు"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ఎడమ వైపునకు"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"కుడి వైపునకు"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"పరిసరాలు"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"ఎడమ వైపు పరిసరాలు"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"కుడి వైపు పరిసరాలు"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"ఎడమ, కుడి అని వేరు చేయబడిన కంట్రోల్స్కు విస్తరించండి"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"యూనిఫైడ్ కంట్రోల్కు కుదించండి"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"పరిసరాలను మ్యూట్ చేయండి"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"పరిసరాలను అన్మ్యూట్ చేయండి"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"టూల్స్"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"లైవ్ క్యాప్షన్"</string> + <string name="hearing_devices_settings_button" msgid="999474385481812222">"సెట్టింగ్లు"</string> <string name="quick_settings_notes_label" msgid="1028004078001002623">"గమనిక"</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> @@ -907,7 +905,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"కుడి వైపు ప్రస్తుత యాప్తో స్ప్లిట్ స్క్రీన్ను ఉపయోగించండి"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"ఎడమ వైపు ప్రస్తుత యాప్తో స్ప్లిట్ స్క్రీన్ను ఉపయోగించండి"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"ఫుల్ స్క్రీన్ను ఉపయోగించండి"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"డెస్క్టాప్ వీక్షణను ఉపయోగించండి"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"స్ప్లిట్ స్క్రీన్ ఉపయోగిస్తున్నప్పుడు కుడి లేదా కింద యాప్నకు మారండి"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"స్ప్లిట్ స్క్రీన్ ఉపయోగిస్తున్నప్పుడు ఎడమ లేదా పైన యాప్నకు మారండి"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"స్ప్లిట్ స్క్రీన్ సమయంలో: ఒక దాన్నుండి మరో దానికి యాప్ రీప్లేస్ చేయండి"</string> @@ -1004,8 +1003,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> స్థానానికి జోడించండి"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ప్రస్తుత పొజిషన్ చెల్లదు."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"స్థానం <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"టైల్ను ఇప్పటికే జోడించారు"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"టైల్ జోడించబడింది"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"టైల్ తీసివేయబడింది"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"శీఘ్ర సెట్టింగ్ల ఎడిటర్."</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index e816c04a5e65..e1413f2ebe65 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -423,18 +423,17 @@ <string name="hearing_devices_ambient_label" msgid="629440938614895797">"เสียงแวดล้อม"</string> <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ซ้าย"</string> <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"ขวา"</string> - <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) --> - <skip /> - <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) --> - <skip /> + <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"เสียงแวดล้อม"</string> + <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"เสียงแวดล้อมด้านซ้าย"</string> + <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"เสียงแวดล้อมด้านขวา"</string> <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"ขยายเป็นการควบคุมที่แยกด้านซ้ายและขวา"</string> <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"ยุบเป็นการควบคุมแบบรวม"</string> <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"ปิดเสียงแวดล้อม"</string> <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"เปิดเสียงแวดล้อม"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"เครื่องมือ"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"คำบรรยายสด"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"จดบันทึก"</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> @@ -907,7 +906,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"ใช้โหมดแยกหน้าจอโดยให้แอปอยู่ด้านขวา"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"ใช้โหมดแยกหน้าจอโดยให้แอปอยู่ด้านซ้าย"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"ใช้โหมดเต็มหน้าจอ"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"ใช้มุมมองบนเดสก์ท็อป"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"เปลี่ยนไปใช้แอปทางด้านขวาหรือด้านล่างขณะใช้โหมดแยกหน้าจอ"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"เปลี่ยนไปใช้แอปทางด้านซ้ายหรือด้านบนขณะใช้โหมดแยกหน้าจอ"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"ระหว่างใช้โหมดแยกหน้าจอ: เปลี่ยนแอปหนึ่งเป็นอีกแอปหนึ่ง"</string> @@ -1003,8 +1003,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"เพิ่มไปยังตำแหน่ง <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ตำแหน่งไม่ถูกต้อง"</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ตำแหน่ง <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"เพิ่มการ์ดแล้ว"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"เพิ่มชิ้นส่วนแล้ว"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"นำชิ้นส่วนออกแล้ว"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ตัวแก้ไขการตั้งค่าด่วน"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index d996218c64db..aff1621dd4cf 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -435,6 +435,7 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"I-unmute ang paligid"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Mga Tool"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Instant Caption"</string> + <string name="hearing_devices_settings_button" msgid="999474385481812222">"Mga Setting"</string> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Tala"</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> @@ -907,7 +908,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Gumamit ng split screen nang nasa kanan ang app"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Gumamit ng split screen nang nasa kaliwa ang app"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Gamitin ang full screen"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Gamitin ang desktop view"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Lumipat sa app sa kanan o ibaba habang ginagamit ang split screen"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Lumipat sa app sa kaliwa o itaas habang ginagamit ang split screen"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Habang nasa split screen: magpalit-palit ng app"</string> @@ -1003,8 +1005,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Idagdag sa posisyong <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Invalid ang posisyon."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisyon <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"Naidagdag na ang tile"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Idinagdag ang tile"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Inalis ang tile"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor ng Mga mabilisang setting."</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 9d789417b09f..eb5b95143af7 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Çevredeki sesleri aç"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Araçlar"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Canlı Altyazı"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Not"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Cihaz mikrofonunun engellemesi kaldırılsın mı?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Cihaz kamerasının engellemesi kaldırılsın mı?"</string> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Sağdaki uygulamayla birlikte bölünmüş ekranı kullan"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Soldaki uygulamayla birlikte bölünmüş ekranı kullan"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Tam ekran kullanın"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Masaüstü görünümünü kullanın"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Bölünmüş ekran kullanırken sağdaki veya alttaki uygulamaya geçiş yap"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Bölünmüş ekran kullanırken soldaki veya üstteki uygulamaya geçiş yapın"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Bölünmüş ekran etkinken: Bir uygulamayı başkasıyla değiştir"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 97e5bb70313f..1f5d0aac98c6 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Увімкнути звуки оточення"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Інструменти"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Живі субтитри"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Нотатка"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Розділити екран і показувати додаток праворуч"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Розділити екран і показувати додаток ліворуч"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Використовувати повноекранний режим"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Використовувати версію для комп’ютера"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Перейти до додатка праворуч або внизу на розділеному екрані"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Під час розділення екрана перемикатися на додаток ліворуч або вгорі"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Під час розділення екрана: замінити додаток іншим"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 41ba6b235284..bcaa91240d53 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -252,8 +252,8 @@ <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> سے منسلک ہیں۔"</string> <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> سے منسلک ہے۔"</string> <string name="accessibility_expand_group" msgid="521237935987978624">"گروپ کو پھیلائیں۔"</string> - <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"آلہ کو گروپ شامل کریں۔"</string> - <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"آلہ کو گروپ سے ہٹائیں"</string> + <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"آلہ کو گروپ میں شامل کریں۔"</string> + <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"آلہ کو گروپ سے ہٹائیں۔"</string> <string name="accessibility_open_application" msgid="1749126077501259712">"ایپلیکیشن کھولیں۔"</string> <string name="accessibility_not_connected" msgid="4061305616351042142">"مربوط نہیں ہے۔"</string> <string name="data_connection_roaming" msgid="375650836665414797">"رومنگ"</string> @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"اطراف کی آواز چالو کریں"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"ٹولز"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"لائیو کیپشن"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"نوٹ"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"بائیں جانب ایپ کے ساتھ اسپلٹ اسکرین کا استعمال کریں"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"دائیں جانب ایپ کے ساتھ اسپلٹ اسکرین کا استعمال کریں"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"فُل اسکرین استعمال کریں"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"ڈیسک ٹاپ منظر استعمال کریں"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"اسپلٹ اسکرین کا استعمال کرتے ہوئے دائیں یا نیچے ایپ پر سوئچ کریں"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"اسپلٹ اسکرین کا استعمال کرتے ہوئے بائیں یا اوپر ایپ پر سوئچ کریں"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"اسپلٹ اسکرین کے دوران: ایک ایپ کو دوسرے سے تبدیل کریں"</string> @@ -1003,8 +1006,7 @@ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"پوزیشن <xliff:g id="POSITION">%1$d</xliff:g> میں شامل کریں"</string> <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"پوزیشن غلط ہے۔"</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"پوزیشن <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) --> - <skip /> + <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"ٹائل پہلے ہی شامل کر دیا گیا ہے"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ٹائل کو شامل کیا گیا"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ٹائل کو ہٹا دیا گیا"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"فوری ترتیبات کا ایڈیٹر۔"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index f713ddc13b80..bf070b5535bd 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Atrof-muhitni sukutdan chiqarish"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Vositalar"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Jonli izoh"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Qayd"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Qurilma mikrofoni blokdan chiqarilsinmi?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Qurilma kamerasi blokdan chiqarilsinmi?"</string> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Ekranni ajratib, joriy ilovani oʻngga joylash"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Ekranni ajratib, joriy ilovani chapga joylash"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Butun ekrandan foydalanish"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Desktop versiyadan foydalanish"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Ajratilgan ekranda oʻngdagi yoki pastdagi ilovaga almashish"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Ajratilgan ekranda chapdagi yoki yuqoridagi ilovaga almashish"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Ajratilgan rejimda ilovalarni oʻzaro almashtirish"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 2f266a781525..9e11f3813842 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Bật tiếng xung quanh"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Công cụ"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Phụ đề trực tiếp"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Ghi chú"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Bỏ chặn micrô của thiết bị?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Bỏ chặn camera của thiết bị?"</string> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Dùng tính năng chia đôi màn hình với ứng dụng ở bên phải"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Dùng tính năng chia đôi màn hình với ứng dụng ở bên trái"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Dùng chế độ toàn màn hình"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Dùng chế độ xem trên máy tính để bàn"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Chuyển sang ứng dụng bên phải hoặc ở dưới khi đang chia đôi màn hình"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Chuyển sang ứng dụng bên trái hoặc ở trên khi đang chia đôi màn hình"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Trong chế độ chia đôi màn hình: thay một ứng dụng bằng ứng dụng khác"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 480debcb239b..cbc4e5183f43 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -150,7 +150,7 @@ <string name="cast_to_other_device_stop_dialog_title" msgid="7836517190930357326">"停止投屏吗?"</string> <string name="cast_to_other_device_stop_dialog_message_entire_screen_with_device" msgid="1474703115926205251">"您正在将整个屏幕投放到“<xliff:g id="DEVICE_NAME">%1$s</xliff:g>”上"</string> <string name="cast_to_other_device_stop_dialog_message_entire_screen" msgid="8419219169553867625">"您正在将整个屏幕投放到附近的设备上"</string> - <string name="cast_to_other_device_stop_dialog_message_specific_app_with_device" msgid="2715934698604085519">"您正在将“<xliff:g id="APP_BEING_SHARED_NAME">%1$s</xliff:g>”投放到“<xliff:g id="DEVICE_NAME">%2$s</xliff:g>”上"</string> + <string name="cast_to_other_device_stop_dialog_message_specific_app_with_device" msgid="2715934698604085519">"目前正在将“<xliff:g id="APP_BEING_SHARED_NAME">%1$s</xliff:g>”投放到“<xliff:g id="DEVICE_NAME">%2$s</xliff:g>”"</string> <string name="cast_to_other_device_stop_dialog_message_specific_app" msgid="8616103075630934513">"您正在将“<xliff:g id="APP_BEING_SHARED_NAME">%1$s</xliff:g>”投放到附近的设备上"</string> <string name="cast_to_other_device_stop_dialog_message_generic_with_device" msgid="9213582497852420203">"您正在向“<xliff:g id="DEVICE_NAME">%1$s</xliff:g>”上投放内容"</string> <string name="cast_to_other_device_stop_dialog_message_generic" msgid="4100272100480415076">"您正在向附近的设备投放内容"</string> @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"取消周围声音静音"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"工具"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"实时字幕"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"记事"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"使用分屏模式,并将应用置于右侧"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"使用分屏模式,并将应用置于左侧"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"使用全屏"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"使用桌面版视图"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"使用分屏模式时,切换到右侧或下方的应用"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"使用分屏模式时,切换到左侧或上方的应用"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"在分屏期间:将一个应用替换为另一个应用"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index bc9e0c580901..0e1de31e0a08 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"取消環境聲音靜音"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"工具"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"即時字幕"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"筆記"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"使用分割螢幕,並在右側顯示應用程式"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"使用分割螢幕,並在左側顯示應用程式"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"使用全螢幕"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"使用桌面電腦檢視模式"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"使用分割螢幕時,切換至右邊或下方的應用程式"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"使用分割螢幕時,切換至左邊或上方的應用程式"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"使用分割螢幕期間:更換應用程式"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 02fda5a68313..a34333bcbc80 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -435,6 +435,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"取消環境靜音"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"工具"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"即時字幕"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"筆記"</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> @@ -907,7 +909,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"使用分割畫面,並在右側顯示應用程式"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"使用分割畫面,並在左側顯示應用程式"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"使用全螢幕模式"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"使用電腦檢視畫面"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"使用分割畫面時,切換到右邊或上方的應用程式"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"使用分割畫面時,切換到左邊或上方的應用程式"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"使用分割畫面期間:更換應用程式"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 886cbdf2b097..7d43adc83376 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -437,6 +437,8 @@ <string name="hearing_devices_ambient_unmute" msgid="2187938085943876814">"Susa ukuthula ezindaweni ezizungezile"</string> <string name="hearing_devices_tools_label" msgid="1929081464316074476">"Amathuluzi"</string> <string name="quick_settings_hearing_devices_live_caption_title" msgid="1054814050932225451">"Okushuthwe Bukhoma"</string> + <!-- no translation found for hearing_devices_settings_button (999474385481812222) --> + <skip /> <string name="quick_settings_notes_label" msgid="1028004078001002623">"Inothi"</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> @@ -909,7 +911,8 @@ <string name="system_multitasking_rhs" msgid="8779289852395243004">"Sebenzisa ukuhlukanisa isikrini nge-app kwesokudla"</string> <string name="system_multitasking_lhs" msgid="7348595296208696452">"Sebenzisa ukuhlukanisa isikrini nge-app kwesokunxele"</string> <string name="system_multitasking_full_screen" msgid="4221409316059910349">"Sebenzisa isikrini esigcwele"</string> - <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"Sebenzisa ukubuka kwedeskithophu"</string> + <!-- no translation found for system_multitasking_desktop_view (8871367687089347180) --> + <skip /> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Shintshela ku-app ngakwesokudla noma ngezansi ngenkathi usebenzisa uhlukanisa isikrini"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Shintshela ku-app ngakwesokunxele noma ngaphezulu ngenkathi usebenzisa ukuhlukanisa isikrini"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Ngesikhathi sokuhlukaniswa kwesikrini: shintsha i-app ngenye"</string> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 78e719f6289a..549fdefd8f7a 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -115,7 +115,7 @@ <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" --> <string name="quick_settings_tiles_stock" translatable="false"> - internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,color_correction,dream,font_scaling,record_issue,hearing_devices,notes,desktopeffects + internet,bt,flashlight,dnd,modes_dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,color_correction,dream,font_scaling,record_issue,hearing_devices,notes,desktopeffects </string> <!-- The tiles to display in QuickSettings --> diff --git a/packages/SystemUI/res/values/tiles_states_strings.xml b/packages/SystemUI/res/values/tiles_states_strings.xml index faf06f3d39f0..bcd49b91d894 100644 --- a/packages/SystemUI/res/values/tiles_states_strings.xml +++ b/packages/SystemUI/res/values/tiles_states_strings.xml @@ -85,6 +85,16 @@ <item>On</item> </string-array> + <!-- State names for dnd (Do not disturb) mode tile: unavailable, off, on. + This subtitle is shown when the tile is in that particular state but does not set its own + subtitle, so some of these may never appear on screen. They should still be translated as + if they could appear. [CHAR LIMIT=32] --> + <string-array name="tile_states_modes_dnd"> + <item>Unavailable</item> + <item>Off</item> + <item>On</item> + </string-array> + <!-- State names for flashlight tile: unavailable, off, on. This subtitle is shown when the tile is in that particular state but does not set its own subtitle, so some of these may never appear on screen. They should still be translated as diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt index 1549b699eee6..763b1072f968 100644 --- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt @@ -21,7 +21,6 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.content.res.Resources -import android.graphics.RectF import android.os.Trace import android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS import android.provider.Settings.Global.ZEN_MODE_OFF @@ -60,6 +59,7 @@ import com.android.systemui.plugins.clocks.ClockEventListener import com.android.systemui.plugins.clocks.ClockFaceController import com.android.systemui.plugins.clocks.ClockMessageBuffers import com.android.systemui.plugins.clocks.ClockTickRate +import com.android.systemui.plugins.clocks.VRectF import com.android.systemui.plugins.clocks.WeatherData import com.android.systemui.plugins.clocks.ZenData import com.android.systemui.plugins.clocks.ZenData.ZenMode @@ -250,7 +250,7 @@ constructor( private var largeClockOnSecondaryDisplay = false val dozeAmount = MutableStateFlow(0f) - val onClockBoundsChanged = MutableStateFlow<RectF?>(null) + val onClockBoundsChanged = MutableStateFlow<VRectF>(VRectF.ZERO) private fun isDarkTheme(): Boolean { val isLightTheme = TypedValue() @@ -315,7 +315,7 @@ constructor( private val clockListener = object : ClockEventListener { - override fun onBoundsChanged(bounds: RectF) { + override fun onBoundsChanged(bounds: VRectF) { onClockBoundsChanged.value = bounds } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt index 39f55803bb73..c4e1ccf6b62e 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt @@ -31,7 +31,7 @@ import com.android.systemui.biometrics.shared.model.SensorStrength import com.android.systemui.biometrics.shared.model.toSensorStrength import com.android.systemui.biometrics.shared.model.toSensorType import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt index 230b30bc548e..cce33fdf16c1 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt @@ -21,7 +21,7 @@ import android.util.Log import com.android.systemui.biometrics.AuthController import com.android.systemui.biometrics.shared.model.PromptKind import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import javax.inject.Inject import kotlinx.coroutines.channels.awaitClose diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt index 40313e3158aa..6484116233ca 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt @@ -21,7 +21,7 @@ import android.content.res.Configuration import com.android.systemui.biometrics.data.repository.DisplayStateRepository import com.android.systemui.biometrics.shared.model.DisplayRotation import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.display.data.repository.DisplayRepository diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt index 30b98a658821..ceb2b10ab517 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt @@ -99,11 +99,6 @@ constructor( show() } else if (showIndicatorForDeviceEntry) { show() - overlayView?.announceForAccessibility( - applicationContext.resources.getString( - R.string.accessibility_side_fingerprint_indicator_label - ) - ) } else { hide() } @@ -182,6 +177,11 @@ constructor( overlayShowAnimator.start() + /** + * Intercepts TYPE_WINDOW_STATE_CHANGED accessibility event, preventing Talkback + * from speaking @string/accessibility_fingerprint_label twice when sensor location + * indicator is in focus + */ it.setAccessibilityDelegate( object : View.AccessibilityDelegate() { override fun dispatchPopulateAccessibilityEvent( @@ -190,8 +190,7 @@ constructor( ): Boolean { return if ( event.getEventType() === - android.view.accessibility.AccessibilityEvent - .TYPE_WINDOW_STATE_CHANGED + AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED ) { true } else { diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothAutoOnRepository.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothAutoOnRepository.kt index 7f1cb5da474d..dea3c472a476 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothAutoOnRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothAutoOnRepository.kt @@ -21,7 +21,7 @@ import android.util.Log import com.android.settingslib.bluetooth.BluetoothCallback import com.android.settingslib.bluetooth.LocalBluetoothManager import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsViewModel.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsViewModel.kt index 5863a9385234..7d8752ef7222 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsViewModel.kt @@ -21,18 +21,14 @@ import com.android.systemui.plugins.qs.TileDetailsViewModel class BluetoothDetailsViewModel( private val onSettingsClick: () -> Unit, val detailsContentViewModel: BluetoothDetailsContentViewModel, -) : TileDetailsViewModel() { +) : TileDetailsViewModel { override fun clickOnSettingsButton() { onSettingsClick() } - override fun getTitle(): String { - // TODO: b/378513956 Update the placeholder text - return "Bluetooth" - } + // TODO: b/378513956 Update the placeholder text + override val title = "Bluetooth" - override fun getSubTitle(): String { - // TODO: b/378513956 Update the placeholder text - return "Tap to connect or disconnect a device" - } + // TODO: b/378513956 Update the placeholder text + override val subTitle = "Tap to connect or disconnect a device" } diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractor.kt index 55d4d3efbe27..9e0f10277197 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractor.kt @@ -22,7 +22,7 @@ import android.bluetooth.BluetoothAdapter.STATE_ON import com.android.settingslib.bluetooth.BluetoothCallback import com.android.settingslib.bluetooth.LocalBluetoothManager import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt index b606c19b3503..e458b8092cda 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt @@ -24,7 +24,7 @@ import com.android.settingslib.bluetooth.CachedBluetoothDevice import com.android.settingslib.bluetooth.LocalBluetoothManager import com.android.settingslib.volume.domain.interactor.AudioModeInteractor import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/SimBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/SimBouncerRepository.kt index b9e1c55fbade..89208364178d 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/SimBouncerRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/SimBouncerRepository.kt @@ -28,7 +28,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.bouncer.data.model.SimBouncerModel import com.android.systemui.bouncer.data.model.SimPukInputModel import com.android.systemui.broadcast.BroadcastDispatcher -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background diff --git a/packages/SystemUI/src/com/android/systemui/brightness/data/repository/ScreenBrightnessRepository.kt b/packages/SystemUI/src/com/android/systemui/brightness/data/repository/ScreenBrightnessRepository.kt index e6d6293733d4..636b3ab66dd5 100644 --- a/packages/SystemUI/src/com/android/systemui/brightness/data/repository/ScreenBrightnessRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/brightness/data/repository/ScreenBrightnessRepository.kt @@ -24,7 +24,7 @@ import com.android.systemui.brightness.shared.model.BrightnessLog import com.android.systemui.brightness.shared.model.LinearBrightness import com.android.systemui.brightness.shared.model.formatBrightness import com.android.systemui.brightness.shared.model.logDiffForTable -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt index 183a3cc26b95..724670d955dd 100644 --- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt +++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt @@ -32,7 +32,7 @@ import com.android.internal.annotations.VisibleForTesting import com.android.systemui.Dumpable import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.BroadcastRunning import com.android.systemui.dagger.qualifiers.Main diff --git a/packages/SystemUI/src/com/android/systemui/camera/data/repository/CameraSensorPrivacyRepository.kt b/packages/SystemUI/src/com/android/systemui/camera/data/repository/CameraSensorPrivacyRepository.kt index 7816a1487c01..dac5b7efaade 100644 --- a/packages/SystemUI/src/com/android/systemui/camera/data/repository/CameraSensorPrivacyRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/camera/data/repository/CameraSensorPrivacyRepository.kt @@ -19,7 +19,7 @@ package com.android.systemui.camera.data.repository import android.hardware.SensorPrivacyManager import android.hardware.SensorPrivacyManager.Sensors.CAMERA import android.os.UserHandle -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/TouchHandlingView.kt b/packages/SystemUI/src/com/android/systemui/common/ui/view/TouchHandlingView.kt index 42f1b738ec20..6c3535a42a6e 100644 --- a/packages/SystemUI/src/com/android/systemui/common/ui/view/TouchHandlingView.kt +++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/TouchHandlingView.kt @@ -27,17 +27,17 @@ import android.view.ViewConfiguration import android.view.accessibility.AccessibilityNodeInfo import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction import androidx.core.view.accessibility.AccessibilityNodeInfoCompat +import com.android.systemui.Flags.doubleTapToSleep import com.android.systemui.log.TouchHandlingViewLogger import com.android.systemui.shade.TouchLogger -import kotlin.math.pow -import kotlin.math.sqrt import kotlinx.coroutines.DisposableHandle /** - * View designed to handle long-presses. + * View designed to handle long-presses and double taps. * - * The view will not handle any long pressed by default. To set it up, set up a listener and, when - * ready to start consuming long-presses, set [setLongPressHandlingEnabled] to `true`. + * The view will not handle any gestures by default. To set it up, set up a listener and, when ready + * to start consuming gestures, set the gesture's enable function ([setLongPressHandlingEnabled], + * [setDoublePressHandlingEnabled]) to `true`. */ class TouchHandlingView( context: Context, @@ -62,6 +62,9 @@ class TouchHandlingView( /** Notifies that the gesture was too short for a long press, it is actually a click. */ fun onSingleTapDetected(view: View, x: Int, y: Int) = Unit + + /** Notifies that a double tap has been detected by the given view. */ + fun onDoubleTapDetected(view: View) = Unit } var listener: Listener? = null @@ -70,6 +73,7 @@ class TouchHandlingView( private val interactionHandler: TouchHandlingViewInteractionHandler by lazy { TouchHandlingViewInteractionHandler( + context = context, postDelayed = { block, timeoutMs -> val dispatchToken = Any() @@ -84,6 +88,9 @@ class TouchHandlingView( onSingleTapDetected = { x, y -> listener?.onSingleTapDetected(this@TouchHandlingView, x = x, y = y) }, + onDoubleTapDetected = { + if (doubleTapToSleep()) listener?.onDoubleTapDetected(this@TouchHandlingView) + }, longPressDuration = longPressDuration, allowedTouchSlop = allowedTouchSlop, logger = logger, @@ -100,13 +107,17 @@ class TouchHandlingView( interactionHandler.isLongPressHandlingEnabled = isEnabled } + fun setDoublePressHandlingEnabled(isEnabled: Boolean) { + interactionHandler.isDoubleTapHandlingEnabled = isEnabled + } + override fun dispatchTouchEvent(event: MotionEvent): Boolean { return TouchLogger.logDispatchTouch("long_press", event, super.dispatchTouchEvent(event)) } @SuppressLint("ClickableViewAccessibility") - override fun onTouchEvent(event: MotionEvent?): Boolean { - return interactionHandler.onTouchEvent(event?.toModel()) + override fun onTouchEvent(event: MotionEvent): Boolean { + return interactionHandler.onTouchEvent(event) } private fun setupAccessibilityDelegate() { @@ -154,33 +165,3 @@ class TouchHandlingView( } } } - -private fun MotionEvent.toModel(): TouchHandlingViewInteractionHandler.MotionEventModel { - return when (actionMasked) { - MotionEvent.ACTION_DOWN -> - TouchHandlingViewInteractionHandler.MotionEventModel.Down(x = x.toInt(), y = y.toInt()) - MotionEvent.ACTION_MOVE -> - TouchHandlingViewInteractionHandler.MotionEventModel.Move( - distanceMoved = distanceMoved() - ) - MotionEvent.ACTION_UP -> - TouchHandlingViewInteractionHandler.MotionEventModel.Up( - distanceMoved = distanceMoved(), - gestureDuration = gestureDuration(), - ) - MotionEvent.ACTION_CANCEL -> TouchHandlingViewInteractionHandler.MotionEventModel.Cancel - else -> TouchHandlingViewInteractionHandler.MotionEventModel.Other - } -} - -private fun MotionEvent.distanceMoved(): Float { - return if (historySize > 0) { - sqrt((x - getHistoricalX(0)).pow(2) + (y - getHistoricalY(0)).pow(2)) - } else { - 0f - } -} - -private fun MotionEvent.gestureDuration(): Long { - return eventTime - downTime -} diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/TouchHandlingViewInteractionHandler.kt b/packages/SystemUI/src/com/android/systemui/common/ui/view/TouchHandlingViewInteractionHandler.kt index 5863fc644c8e..fe509d74edc0 100644 --- a/packages/SystemUI/src/com/android/systemui/common/ui/view/TouchHandlingViewInteractionHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/TouchHandlingViewInteractionHandler.kt @@ -17,12 +17,20 @@ package com.android.systemui.common.ui.view +import android.content.Context import android.graphics.Point +import android.view.GestureDetector +import android.view.MotionEvent +import android.view.ViewConfiguration import com.android.systemui.log.TouchHandlingViewLogger +import kotlin.math.pow +import kotlin.math.sqrt +import kotlin.properties.Delegates import kotlinx.coroutines.DisposableHandle /** Encapsulates logic to handle complex touch interactions with a [TouchHandlingView]. */ class TouchHandlingViewInteractionHandler( + context: Context, /** * Callback to run the given [Runnable] with the given delay, returning a [DisposableHandle] * allowing the delayed runnable to be canceled before it is run. @@ -34,6 +42,8 @@ class TouchHandlingViewInteractionHandler( private val onLongPressDetected: (x: Int, y: Int) -> Unit, /** Callback reporting the a single tap gesture was detected at the given coordinates. */ private val onSingleTapDetected: (x: Int, y: Int) -> Unit, + /** Callback reporting that a double tap gesture was detected. */ + private val onDoubleTapDetected: () -> Unit, /** Time for the touch to be considered a long-press in ms */ var longPressDuration: () -> Long, /** @@ -58,48 +68,98 @@ class TouchHandlingViewInteractionHandler( } var isLongPressHandlingEnabled: Boolean = false + var isDoubleTapHandlingEnabled: Boolean = false var scheduledLongPressHandle: DisposableHandle? = null + private var doubleTapAwaitingUp: Boolean = false + private var lastDoubleTapDownEventTime: Long? = null + /** Record coordinate for last DOWN event for single tap */ val lastEventDownCoordinate = Point(-1, -1) - fun onTouchEvent(event: MotionEventModel?): Boolean { - if (!isLongPressHandlingEnabled) { - return false - } - return when (event) { - is MotionEventModel.Down -> { - scheduleLongPress(event.x, event.y) - lastEventDownCoordinate.x = event.x - lastEventDownCoordinate.y = event.y - true + private val gestureDetector = + GestureDetector( + context, + object : GestureDetector.SimpleOnGestureListener() { + override fun onDoubleTap(event: MotionEvent): Boolean { + if (isDoubleTapHandlingEnabled) { + doubleTapAwaitingUp = true + lastDoubleTapDownEventTime = event.eventTime + return true + } + return false + } + }, + ) + + fun onTouchEvent(event: MotionEvent): Boolean { + if (isDoubleTapHandlingEnabled) { + gestureDetector.onTouchEvent(event) + if (event.actionMasked == MotionEvent.ACTION_UP && doubleTapAwaitingUp) { + lastDoubleTapDownEventTime?.let { time -> + if ( + event.eventTime - time < ViewConfiguration.getDoubleTapTimeout() + ) { + cancelScheduledLongPress() + onDoubleTapDetected() + } + } + doubleTapAwaitingUp = false + } else if (event.actionMasked == MotionEvent.ACTION_CANCEL && doubleTapAwaitingUp) { + doubleTapAwaitingUp = false } - is MotionEventModel.Move -> { - if (event.distanceMoved > allowedTouchSlop) { - logger?.cancelingLongPressDueToTouchSlop(event.distanceMoved, allowedTouchSlop) + } + + if (isLongPressHandlingEnabled) { + val motionEventModel = event.toModel() + + return when (motionEventModel) { + is MotionEventModel.Down -> { + scheduleLongPress(motionEventModel.x, motionEventModel.y) + lastEventDownCoordinate.x = motionEventModel.x + lastEventDownCoordinate.y = motionEventModel.y + true + } + + is MotionEventModel.Move -> { + if (motionEventModel.distanceMoved > allowedTouchSlop) { + logger?.cancelingLongPressDueToTouchSlop( + motionEventModel.distanceMoved, + allowedTouchSlop, + ) + cancelScheduledLongPress() + } + false + } + + is MotionEventModel.Up -> { + logger?.onUpEvent( + motionEventModel.distanceMoved, + allowedTouchSlop, + motionEventModel.gestureDuration, + ) cancelScheduledLongPress() + if ( + motionEventModel.distanceMoved <= allowedTouchSlop && + motionEventModel.gestureDuration < longPressDuration() + ) { + logger?.dispatchingSingleTap() + dispatchSingleTap(lastEventDownCoordinate.x, lastEventDownCoordinate.y) + } + false } - false - } - is MotionEventModel.Up -> { - logger?.onUpEvent(event.distanceMoved, allowedTouchSlop, event.gestureDuration) - cancelScheduledLongPress() - if ( - event.distanceMoved <= allowedTouchSlop && - event.gestureDuration < longPressDuration() - ) { - logger?.dispatchingSingleTap() - dispatchSingleTap(lastEventDownCoordinate.x, lastEventDownCoordinate.y) + + is MotionEventModel.Cancel -> { + logger?.motionEventCancelled() + cancelScheduledLongPress() + false } - false - } - is MotionEventModel.Cancel -> { - logger?.motionEventCancelled() - cancelScheduledLongPress() - false + + else -> false } - else -> false } + + return false } private fun scheduleLongPress(x: Int, y: Int) { @@ -134,4 +194,30 @@ class TouchHandlingViewInteractionHandler( onSingleTapDetected(x, y) } + + private fun MotionEvent.toModel(): MotionEventModel { + return when (actionMasked) { + MotionEvent.ACTION_DOWN -> MotionEventModel.Down(x = x.toInt(), y = y.toInt()) + MotionEvent.ACTION_MOVE -> MotionEventModel.Move(distanceMoved = distanceMoved()) + MotionEvent.ACTION_UP -> + MotionEventModel.Up( + distanceMoved = distanceMoved(), + gestureDuration = gestureDuration(), + ) + MotionEvent.ACTION_CANCEL -> MotionEventModel.Cancel + else -> MotionEventModel.Other + } + } + + private fun MotionEvent.distanceMoved(): Float { + return if (historySize > 0) { + sqrt((x - getHistoricalX(0)).pow(2) + (y - getHistoricalY(0)).pow(2)) + } else { + 0f + } + } + + private fun MotionEvent.gestureDuration(): Long { + return eventTime - downTime + } } diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSuppressionStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSuppressionStartable.kt new file mode 100644 index 000000000000..6a611ec5b647 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSuppressionStartable.kt @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2025 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.communal + +import com.android.systemui.CoreStartable +import com.android.systemui.communal.data.model.SuppressionReason +import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.log.dagger.CommunalTableLog +import com.android.systemui.log.table.TableLogBuffer +import com.android.systemui.log.table.logDiffsForTable +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach + +@SysUISingleton +class CommunalSuppressionStartable +@Inject +constructor( + @Application private val applicationScope: CoroutineScope, + @Background private val bgDispatcher: CoroutineDispatcher, + private val suppressionFlows: Set<@JvmSuppressWildcards Flow<SuppressionReason?>>, + private val communalSettingsInteractor: CommunalSettingsInteractor, + @CommunalTableLog private val tableLogBuffer: TableLogBuffer, +) : CoreStartable { + override fun start() { + getSuppressionReasons() + .onEach { reasons -> communalSettingsInteractor.setSuppressionReasons(reasons) } + .logDiffsForTable( + tableLogBuffer = tableLogBuffer, + columnName = "suppressionReasons", + initialValue = emptyList(), + ) + .flowOn(bgDispatcher) + .launchIn(applicationScope) + } + + private fun getSuppressionReasons(): Flow<List<SuppressionReason>> { + if (!communalSettingsInteractor.isCommunalFlagEnabled()) { + return flowOf(listOf(SuppressionReason.ReasonFlagDisabled)) + } + return combine(suppressionFlows) { reasons -> reasons.filterNotNull() } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt index bb3be531aa8a..a31c0bd35453 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt @@ -29,6 +29,7 @@ import com.android.systemui.communal.data.repository.CommunalSmartspaceRepositor import com.android.systemui.communal.data.repository.CommunalTutorialRepositoryModule import com.android.systemui.communal.data.repository.CommunalWidgetRepositoryModule import com.android.systemui.communal.domain.interactor.CommunalSceneTransitionInteractor +import com.android.systemui.communal.domain.suppression.dagger.CommunalSuppressionModule import com.android.systemui.communal.shared.log.CommunalMetricsLogger import com.android.systemui.communal.shared.log.CommunalStatsLogProxyImpl import com.android.systemui.communal.shared.model.CommunalScenes @@ -70,6 +71,7 @@ import kotlinx.coroutines.CoroutineScope CommunalSmartspaceRepositoryModule::class, CommunalStartableModule::class, GlanceableHubWidgetManagerModule::class, + CommunalSuppressionModule::class, ] ) interface CommunalModule { diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt index 7358aa7b3fcd..a4f75e81b6ae 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt @@ -22,6 +22,7 @@ import com.android.systemui.communal.CommunalDreamStartable import com.android.systemui.communal.CommunalMetricsStartable import com.android.systemui.communal.CommunalOngoingContentStartable import com.android.systemui.communal.CommunalSceneStartable +import com.android.systemui.communal.CommunalSuppressionStartable import com.android.systemui.communal.DevicePosturingListener import com.android.systemui.communal.log.CommunalLoggerStartable import com.android.systemui.communal.widgets.CommunalAppWidgetHostStartable @@ -73,4 +74,9 @@ interface CommunalStartableModule { @IntoMap @ClassKey(DevicePosturingListener::class) fun bindDevicePosturingistener(impl: DevicePosturingListener): CoreStartable + + @Binds + @IntoMap + @ClassKey(CommunalSuppressionStartable::class) + fun bindCommunalSuppressionStartable(impl: CommunalSuppressionStartable): CoreStartable } diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalEnabledState.kt b/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalEnabledState.kt deleted file mode 100644 index 83a5bdb14ebd..000000000000 --- a/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalEnabledState.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.communal.data.model - -import com.android.systemui.log.table.Diffable -import com.android.systemui.log.table.TableRowLogger -import java.util.EnumSet - -/** Reasons that communal is disabled, primarily for logging. */ -enum class DisabledReason(val loggingString: String) { - /** Communal should be disabled due to invalid current user */ - DISABLED_REASON_INVALID_USER("invalidUser"), - /** Communal should be disabled due to the flag being off */ - DISABLED_REASON_FLAG("flag"), - /** Communal should be disabled because the user has turned off the setting */ - DISABLED_REASON_USER_SETTING("userSetting"), - /** Communal is disabled by the device policy app */ - DISABLED_REASON_DEVICE_POLICY("devicePolicy"), -} - -/** - * Model representing the reasons communal hub should be disabled. Allows logging reasons separately - * for debugging. - */ -@JvmInline -value class CommunalEnabledState( - private val disabledReasons: EnumSet<DisabledReason> = - EnumSet.noneOf(DisabledReason::class.java) -) : Diffable<CommunalEnabledState>, Set<DisabledReason> by disabledReasons { - - /** Creates [CommunalEnabledState] with a single reason for being disabled */ - constructor(reason: DisabledReason) : this(EnumSet.of(reason)) - - /** Checks if there are any reasons communal should be disabled. If none, returns true. */ - val enabled: Boolean - get() = isEmpty() - - override fun logDiffs(prevVal: CommunalEnabledState, row: TableRowLogger) { - for (reason in DisabledReason.entries) { - val newVal = contains(reason) - if (newVal != prevVal.contains(reason)) { - row.logChange( - columnName = reason.loggingString, - value = newVal, - ) - } - } - } - - override fun logFull(row: TableRowLogger) { - for (reason in DisabledReason.entries) { - row.logChange(columnName = reason.loggingString, value = contains(reason)) - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalFeature.kt b/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalFeature.kt new file mode 100644 index 000000000000..5fb1c4e84eef --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalFeature.kt @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2025 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.communal.data.model + +import android.annotation.IntDef + +@Retention(AnnotationRetention.SOURCE) +@IntDef( + flag = true, + prefix = ["FEATURE_"], + value = [FEATURE_AUTO_OPEN, FEATURE_MANUAL_OPEN, FEATURE_ENABLED, FEATURE_ALL], +) +annotation class CommunalFeature + +/** If we should automatically open the hub */ +const val FEATURE_AUTO_OPEN: Int = 1 + +/** If the user is allowed to manually open the hub */ +const val FEATURE_MANUAL_OPEN: Int = 1 shl 1 + +/** + * If the hub should be considered enabled. If not, it may be cleaned up entirely to reduce memory + * footprint. + */ +const val FEATURE_ENABLED: Int = 1 shl 2 + +const val FEATURE_ALL: Int = FEATURE_ENABLED or FEATURE_MANUAL_OPEN or FEATURE_AUTO_OPEN diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/model/SuppressionReason.kt b/packages/SystemUI/src/com/android/systemui/communal/data/model/SuppressionReason.kt new file mode 100644 index 000000000000..de05bed7ef57 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/data/model/SuppressionReason.kt @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2025 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.communal.data.model + +sealed interface SuppressionReason { + @CommunalFeature val suppressedFeatures: Int + + /** Whether this reason suppresses a particular feature. */ + fun isSuppressed(@CommunalFeature feature: Int): Boolean { + return (suppressedFeatures and feature) != 0 + } + + /** Suppress hub automatically opening due to Android Auto projection */ + data object ReasonCarProjection : SuppressionReason { + override val suppressedFeatures: Int = FEATURE_AUTO_OPEN + } + + /** Suppress hub due to the "When to dream" conditions not being met */ + data class ReasonWhenToAutoShow(override val suppressedFeatures: Int) : SuppressionReason + + /** Suppress hub due to device policy */ + data object ReasonDevicePolicy : SuppressionReason { + override val suppressedFeatures: Int = FEATURE_ALL + } + + /** Suppress hub due to the user disabling the setting */ + data object ReasonSettingDisabled : SuppressionReason { + override val suppressedFeatures: Int = FEATURE_ALL + } + + /** Suppress hub due to the user being locked */ + data object ReasonUserLocked : SuppressionReason { + override val suppressedFeatures: Int = FEATURE_ALL + } + + /** Suppress hub due the a secondary user being active */ + data object ReasonSecondaryUser : SuppressionReason { + override val suppressedFeatures: Int = FEATURE_ALL + } + + /** Suppress hub due to the flag being disabled */ + data object ReasonFlagDisabled : SuppressionReason { + override val suppressedFeatures: Int = FEATURE_ALL + } + + /** Suppress hub due to an unknown reason, used as initial state and in tests */ + data class ReasonUnknown(override val suppressedFeatures: Int = FEATURE_ALL) : + SuppressionReason +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CarProjectionRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CarProjectionRepository.kt new file mode 100644 index 000000000000..4fe641a78d4b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CarProjectionRepository.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2025 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.communal.data.repository + +import android.app.UiModeManager +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.util.kotlin.emitOnStart +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.asExecutor +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.withContext + +interface CarProjectionRepository { + /** Whether car projection is active. */ + val projectionActive: Flow<Boolean> + + /** + * Checks the system for the current car projection state. + * + * @return True if projection is active, false otherwise. + */ + suspend fun isProjectionActive(): Boolean +} + +@SysUISingleton +class CarProjectionRepositoryImpl +@Inject +constructor( + private val uiModeManager: UiModeManager, + @Background private val bgDispatcher: CoroutineDispatcher, +) : CarProjectionRepository { + override val projectionActive: Flow<Boolean> = + conflatedCallbackFlow { + val listener = + UiModeManager.OnProjectionStateChangedListener { _, _ -> trySend(Unit) } + uiModeManager.addOnProjectionStateChangedListener( + UiModeManager.PROJECTION_TYPE_AUTOMOTIVE, + bgDispatcher.asExecutor(), + listener, + ) + awaitClose { uiModeManager.removeOnProjectionStateChangedListener(listener) } + } + .emitOnStart() + .map { isProjectionActive() } + .flowOn(bgDispatcher) + + override suspend fun isProjectionActive(): Boolean = + withContext(bgDispatcher) { + (uiModeManager.activeProjectionTypes and UiModeManager.PROJECTION_TYPE_AUTOMOTIVE) != 0 + } +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepositoryModule.kt index 7f137f3b976b..0d590db97860 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepositoryModule.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepositoryModule.kt @@ -22,4 +22,6 @@ import dagger.Module @Module interface CommunalRepositoryModule { @Binds fun communalRepository(impl: CommunalSceneRepositoryImpl): CommunalSceneRepository + + @Binds fun carProjectionRepository(impl: CarProjectionRepositoryImpl): CarProjectionRepository } diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt index 4c291a0c5a2e..6f688d172843 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt @@ -26,12 +26,9 @@ import android.provider.Settings import com.android.systemui.Flags.communalHub import com.android.systemui.Flags.glanceableHubV2 import com.android.systemui.broadcast.BroadcastDispatcher -import com.android.systemui.communal.data.model.CommunalEnabledState -import com.android.systemui.communal.data.model.DisabledReason -import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_DEVICE_POLICY -import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_FLAG -import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_INVALID_USER -import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_USER_SETTING +import com.android.systemui.communal.data.model.CommunalFeature +import com.android.systemui.communal.data.model.FEATURE_ALL +import com.android.systemui.communal.data.model.SuppressionReason import com.android.systemui.communal.data.repository.CommunalSettingsRepositoryModule.Companion.DEFAULT_BACKGROUND_TYPE import com.android.systemui.communal.shared.model.CommunalBackgroundType import com.android.systemui.communal.shared.model.WhenToDream @@ -43,22 +40,23 @@ import com.android.systemui.flags.Flags import com.android.systemui.util.kotlin.emitOnStart import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.settings.SettingsProxyExt.observerFlow -import java.util.EnumSet import javax.inject.Inject import javax.inject.Named import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onStart interface CommunalSettingsRepository { - /** A [CommunalEnabledState] for the specified user. */ - fun getEnabledState(user: UserInfo): Flow<CommunalEnabledState> + /** Whether a particular feature is enabled */ + fun isEnabled(@CommunalFeature feature: Int): Flow<Boolean> - fun getScreensaverEnabledState(user: UserInfo): Flow<Boolean> + /** + * Suppresses the hub with the given reasons. If there are no reasons, the hub will not be + * suppressed. + */ + fun setSuppressionReasons(reasons: List<SuppressionReason>) /** * Returns a [WhenToDream] for the specified user, indicating what state the device should be in @@ -66,6 +64,9 @@ interface CommunalSettingsRepository { */ fun getWhenToDreamState(user: UserInfo): Flow<WhenToDream> + /** Returns whether glanceable hub is enabled by the current user. */ + fun getSettingEnabledByUser(user: UserInfo): Flow<Boolean> + /** * Returns true if any glanceable hub functionality should be enabled via configs and flags. * @@ -123,6 +124,19 @@ constructor( resources.getBoolean(com.android.internal.R.bool.config_dreamsActivatedOnPosturedByDefault) } + private val _suppressionReasons = + MutableStateFlow<List<SuppressionReason>>( + // Suppress hub by default until we get an initial update. + listOf(SuppressionReason.ReasonUnknown(FEATURE_ALL)) + ) + + override fun isEnabled(@CommunalFeature feature: Int): Flow<Boolean> = + _suppressionReasons.map { reasons -> reasons.none { it.isSuppressed(feature) } } + + override fun setSuppressionReasons(reasons: List<SuppressionReason>) { + _suppressionReasons.value = reasons + } + override fun getFlagEnabled(): Boolean { return if (getV2FlagEnabled()) { true @@ -138,44 +152,6 @@ constructor( glanceableHubV2() } - override fun getEnabledState(user: UserInfo): Flow<CommunalEnabledState> { - if (!user.isMain) { - return flowOf(CommunalEnabledState(DISABLED_REASON_INVALID_USER)) - } - if (!getFlagEnabled()) { - return flowOf(CommunalEnabledState(DISABLED_REASON_FLAG)) - } - return combine( - getEnabledByUser(user).mapToReason(DISABLED_REASON_USER_SETTING), - getAllowedByDevicePolicy(user).mapToReason(DISABLED_REASON_DEVICE_POLICY), - ) { reasons -> - reasons.filterNotNull() - } - .map { reasons -> - if (reasons.isEmpty()) { - EnumSet.noneOf(DisabledReason::class.java) - } else { - EnumSet.copyOf(reasons) - } - } - .map { reasons -> CommunalEnabledState(reasons) } - .flowOn(bgDispatcher) - } - - override fun getScreensaverEnabledState(user: UserInfo): Flow<Boolean> = - secureSettings - .observerFlow(userId = user.id, names = arrayOf(Settings.Secure.SCREENSAVER_ENABLED)) - // Force an update - .onStart { emit(Unit) } - .map { - secureSettings.getIntForUser( - Settings.Secure.SCREENSAVER_ENABLED, - SCREENSAVER_ENABLED_SETTING_DEFAULT, - user.id, - ) == 1 - } - .flowOn(bgDispatcher) - override fun getWhenToDreamState(user: UserInfo): Flow<WhenToDream> = secureSettings .observerFlow( @@ -247,11 +223,11 @@ constructor( ?: defaultBackgroundType } - private fun getEnabledByUser(user: UserInfo): Flow<Boolean> = + override fun getSettingEnabledByUser(user: UserInfo): Flow<Boolean> = secureSettings .observerFlow(userId = user.id, names = arrayOf(Settings.Secure.GLANCEABLE_HUB_ENABLED)) // Force an update - .onStart { emit(Unit) } + .emitOnStart() .map { secureSettings.getIntForUser( Settings.Secure.GLANCEABLE_HUB_ENABLED, @@ -259,17 +235,13 @@ constructor( user.id, ) == 1 } + .flowOn(bgDispatcher) companion object { const val GLANCEABLE_HUB_BACKGROUND_SETTING = "glanceable_hub_background" private const val ENABLED_SETTING_DEFAULT = 1 - private const val SCREENSAVER_ENABLED_SETTING_DEFAULT = 0 } } private fun DevicePolicyManager.areKeyguardWidgetsAllowed(userId: Int): Boolean = (getKeyguardDisabledFeatures(null, userId) and KEYGUARD_DISABLE_WIDGETS_ALL) == 0 - -private fun Flow<Boolean>.mapToReason(reason: DisabledReason) = map { enabled -> - if (enabled) null else reason -} diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CarProjectionInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CarProjectionInteractor.kt new file mode 100644 index 000000000000..17b61e1c6fdf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CarProjectionInteractor.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2025 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.communal.domain.interactor + +import com.android.systemui.communal.data.repository.CarProjectionRepository +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject + +@SysUISingleton +class CarProjectionInteractor @Inject constructor(repository: CarProjectionRepository) { + /** Whether car projection is active. */ + val projectionActive = repository.projectionActive +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractor.kt new file mode 100644 index 000000000000..51df3338a18e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractor.kt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2025 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.communal.domain.interactor + +import com.android.systemui.common.domain.interactor.BatteryInteractor +import com.android.systemui.communal.dagger.CommunalModule.Companion.SWIPE_TO_HUB +import com.android.systemui.communal.data.model.FEATURE_AUTO_OPEN +import com.android.systemui.communal.data.model.FEATURE_MANUAL_OPEN +import com.android.systemui.communal.data.model.SuppressionReason +import com.android.systemui.communal.posturing.domain.interactor.PosturingInteractor +import com.android.systemui.communal.shared.model.WhenToDream +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dock.DockManager +import com.android.systemui.dock.retrieveIsDocked +import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf +import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated +import javax.inject.Inject +import javax.inject.Named +import kotlin.coroutines.CoroutineContext +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map + +@SysUISingleton +class CommunalAutoOpenInteractor +@Inject +constructor( + communalSettingsInteractor: CommunalSettingsInteractor, + @Background private val backgroundContext: CoroutineContext, + private val batteryInteractor: BatteryInteractor, + private val posturingInteractor: PosturingInteractor, + private val dockManager: DockManager, + @Named(SWIPE_TO_HUB) private val allowSwipeAlways: Boolean, +) { + val shouldAutoOpen: Flow<Boolean> = + communalSettingsInteractor.whenToDream + .flatMapLatestConflated { whenToDream -> + when (whenToDream) { + WhenToDream.WHILE_CHARGING -> batteryInteractor.isDevicePluggedIn + WhenToDream.WHILE_DOCKED -> { + allOf(batteryInteractor.isDevicePluggedIn, dockManager.retrieveIsDocked()) + } + WhenToDream.WHILE_POSTURED -> { + allOf(batteryInteractor.isDevicePluggedIn, posturingInteractor.postured) + } + WhenToDream.NEVER -> flowOf(false) + } + } + .flowOn(backgroundContext) + + val suppressionReason: Flow<SuppressionReason?> = + shouldAutoOpen.map { conditionMet -> + if (conditionMet) { + null + } else { + var suppressedFeatures = FEATURE_AUTO_OPEN + if (!allowSwipeAlways) { + suppressedFeatures = suppressedFeatures or FEATURE_MANUAL_OPEN + } + SuppressionReason.ReasonWhenToAutoShow(suppressedFeatures) + } + } +} 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 564628d3f52f..684c52ad45f3 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 @@ -30,13 +30,11 @@ import com.android.compose.animation.scene.TransitionKey import com.android.systemui.Flags.communalResponsiveGrid import com.android.systemui.Flags.glanceableHubBlurredBackground import com.android.systemui.broadcast.BroadcastDispatcher -import com.android.systemui.common.domain.interactor.BatteryInteractor import com.android.systemui.communal.data.repository.CommunalMediaRepository import com.android.systemui.communal.data.repository.CommunalSmartspaceRepository import com.android.systemui.communal.data.repository.CommunalWidgetRepository import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.domain.model.CommunalContentModel.WidgetContent -import com.android.systemui.communal.posturing.domain.interactor.PosturingInteractor import com.android.systemui.communal.shared.model.CommunalBackgroundType import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.shared.model.CommunalContentSize.FixedSize.FULL @@ -45,14 +43,11 @@ import com.android.systemui.communal.shared.model.CommunalContentSize.FixedSize. import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.communal.shared.model.CommunalWidgetContentModel import com.android.systemui.communal.shared.model.EditModeState -import com.android.systemui.communal.shared.model.WhenToDream import com.android.systemui.communal.widgets.EditWidgetsActivityStarter import com.android.systemui.communal.widgets.WidgetConfigurator import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background -import com.android.systemui.dock.DockManager -import com.android.systemui.dock.retrieveIsDocked import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.Edge @@ -69,11 +64,8 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.phone.ManagedProfileController -import com.android.systemui.user.domain.interactor.UserLockedInteractor import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf -import com.android.systemui.util.kotlin.BooleanFlowOperators.not import com.android.systemui.util.kotlin.emitOnStart -import com.android.systemui.util.kotlin.isDevicePluggedIn import javax.inject.Inject import kotlin.time.Duration.Companion.minutes import kotlinx.coroutines.CoroutineDispatcher @@ -125,10 +117,6 @@ constructor( @CommunalLog logBuffer: LogBuffer, @CommunalTableLog tableLogBuffer: TableLogBuffer, private val managedProfileController: ManagedProfileController, - private val batteryInteractor: BatteryInteractor, - private val dockManager: DockManager, - private val posturingInteractor: PosturingInteractor, - private val userLockedInteractor: UserLockedInteractor, ) { private val logger = Logger(logBuffer, "CommunalInteractor") @@ -162,11 +150,7 @@ constructor( /** Whether communal features are enabled and available. */ val isCommunalAvailable: Flow<Boolean> = - allOf( - communalSettingsInteractor.isCommunalEnabled, - userLockedInteractor.isUserUnlocked(userManager.mainUser), - keyguardInteractor.isKeyguardShowing, - ) + allOf(communalSettingsInteractor.isCommunalEnabled, keyguardInteractor.isKeyguardShowing) .distinctUntilChanged() .onEach { available -> logger.i({ "Communal is ${if (bool1) "" else "un"}available" }) { @@ -184,37 +168,6 @@ constructor( replay = 1, ) - /** - * Whether communal hub should be shown automatically, depending on the user's [WhenToDream] - * state. - */ - val shouldShowCommunal: StateFlow<Boolean> = - allOf( - isCommunalAvailable, - communalSettingsInteractor.whenToDream - .flatMapLatest { whenToDream -> - when (whenToDream) { - WhenToDream.NEVER -> flowOf(false) - - WhenToDream.WHILE_CHARGING -> batteryInteractor.isDevicePluggedIn - - WhenToDream.WHILE_DOCKED -> - allOf( - batteryInteractor.isDevicePluggedIn, - dockManager.retrieveIsDocked(), - ) - - WhenToDream.WHILE_POSTURED -> - allOf( - batteryInteractor.isDevicePluggedIn, - posturingInteractor.postured, - ) - } - } - .flowOn(bgDispatcher), - ) - .stateIn(scope = bgScope, started = SharingStarted.Eagerly, initialValue = false) - private val _isDisclaimerDismissed = MutableStateFlow(false) val isDisclaimerDismissed: Flow<Boolean> = _isDisclaimerDismissed.asStateFlow() diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt index a0b1261df346..0d7a2d9707d7 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt @@ -17,18 +17,19 @@ package com.android.systemui.communal.domain.interactor import android.content.pm.UserInfo -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow -import com.android.systemui.communal.data.model.CommunalEnabledState +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow +import com.android.systemui.communal.data.model.FEATURE_AUTO_OPEN +import com.android.systemui.communal.data.model.FEATURE_ENABLED +import com.android.systemui.communal.data.model.FEATURE_MANUAL_OPEN +import com.android.systemui.communal.data.model.SuppressionReason import com.android.systemui.communal.data.repository.CommunalSettingsRepository import com.android.systemui.communal.shared.model.CommunalBackgroundType import com.android.systemui.communal.shared.model.WhenToDream import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background -import com.android.systemui.log.dagger.CommunalTableLog -import com.android.systemui.log.table.TableLogBuffer -import com.android.systemui.log.table.logDiffsForTable import com.android.systemui.settings.UserTracker import com.android.systemui.user.domain.interactor.SelectedUserInteractor +import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated import java.util.concurrent.Executor import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher @@ -53,33 +54,43 @@ constructor( private val repository: CommunalSettingsRepository, userInteractor: SelectedUserInteractor, private val userTracker: UserTracker, - @CommunalTableLog tableLogBuffer: TableLogBuffer, ) { - /** Whether or not communal is enabled for the currently selected user. */ + /** Whether communal is enabled at all. */ val isCommunalEnabled: StateFlow<Boolean> = - userInteractor.selectedUserInfo - .flatMapLatest { user -> repository.getEnabledState(user) } - .logDiffsForTable( - tableLogBuffer = tableLogBuffer, - columnPrefix = "disabledReason", - initialValue = CommunalEnabledState(), - ) - .map { model -> model.enabled } - // Start this eagerly since the value is accessed synchronously in many places. + repository + .isEnabled(FEATURE_ENABLED) .stateIn(scope = bgScope, started = SharingStarted.Eagerly, initialValue = false) - /** Whether or not screensaver (dreams) is enabled for the currently selected user. */ - val isScreensaverEnabled: Flow<Boolean> = - userInteractor.selectedUserInfo.flatMapLatest { user -> - repository.getScreensaverEnabledState(user) - } + /** Whether manually opening the hub is enabled */ + val manualOpenEnabled: StateFlow<Boolean> = + repository + .isEnabled(FEATURE_MANUAL_OPEN) + .stateIn(scope = bgScope, started = SharingStarted.Eagerly, initialValue = false) + + /** Whether auto-opening the hub is enabled */ + val autoOpenEnabled: StateFlow<Boolean> = + repository + .isEnabled(FEATURE_AUTO_OPEN) + .stateIn(scope = bgScope, started = SharingStarted.Eagerly, initialValue = false) /** When to dream for the currently selected user. */ val whenToDream: Flow<WhenToDream> = - userInteractor.selectedUserInfo.flatMapLatest { user -> + userInteractor.selectedUserInfo.flatMapLatestConflated { user -> repository.getWhenToDreamState(user) } + /** Whether communal hub is allowed by device policy for the current user */ + val allowedForCurrentUserByDevicePolicy: Flow<Boolean> = + userInteractor.selectedUserInfo.flatMapLatestConflated { user -> + repository.getAllowedByDevicePolicy(user) + } + + /** Whether the hub is enabled for the current user */ + val settingEnabledForCurrentUser: Flow<Boolean> = + userInteractor.selectedUserInfo.flatMapLatestConflated { user -> + repository.getSettingEnabledByUser(user) + } + /** * Returns true if any glanceable hub functionality should be enabled via configs and flags. * @@ -109,6 +120,14 @@ constructor( */ fun isV2FlagEnabled(): Boolean = repository.getV2FlagEnabled() + /** + * Suppresses the hub with the given reasons. If there are no reasons, the hub will not be + * suppressed. + */ + fun setSuppressionReasons(reasons: List<SuppressionReason>) { + repository.setSuppressionReasons(reasons) + } + /** The type of background to use for the hub. Used to experiment with different backgrounds */ val communalBackground: Flow<CommunalBackgroundType> = userInteractor.selectedUserInfo diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/suppression/FlowExt.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/suppression/FlowExt.kt new file mode 100644 index 000000000000..a10e90f09cc2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/suppression/FlowExt.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2025 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.communal.domain.suppression + +import com.android.systemui.communal.data.model.SuppressionReason +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +fun Flow<Boolean>.mapToReasonIfNotAllowed(reason: SuppressionReason): Flow<SuppressionReason?> = + this.map { allowed -> if (allowed) null else reason } diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/suppression/dagger/CommunalSuppressionModule.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/suppression/dagger/CommunalSuppressionModule.kt new file mode 100644 index 000000000000..c62d77eee287 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/suppression/dagger/CommunalSuppressionModule.kt @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2025 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.communal.domain.suppression.dagger + +import com.android.systemui.Flags.glanceableHubV2 +import com.android.systemui.communal.data.model.SuppressionReason +import com.android.systemui.communal.domain.interactor.CarProjectionInteractor +import com.android.systemui.communal.domain.interactor.CommunalAutoOpenInteractor +import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor +import com.android.systemui.communal.domain.suppression.mapToReasonIfNotAllowed +import com.android.systemui.user.domain.interactor.SelectedUserInteractor +import com.android.systemui.user.domain.interactor.UserLockedInteractor +import com.android.systemui.util.kotlin.BooleanFlowOperators.not +import dagger.Module +import dagger.Provides +import dagger.multibindings.IntoSet +import dagger.multibindings.Multibinds +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map + +@Module +interface CommunalSuppressionModule { + /** + * A set of reasons why communal may be suppressed. Ensures that this can be injected even if + * it's empty. + */ + @Multibinds fun suppressorSet(): Set<Flow<SuppressionReason?>> + + companion object { + @Provides + @IntoSet + fun provideCarProjectionSuppressor( + interactor: CarProjectionInteractor + ): Flow<SuppressionReason?> { + if (!glanceableHubV2()) { + return flowOf(null) + } + return not(interactor.projectionActive) + .mapToReasonIfNotAllowed(SuppressionReason.ReasonCarProjection) + } + + @Provides + @IntoSet + fun provideDevicePolicySuppressor( + interactor: CommunalSettingsInteractor + ): Flow<SuppressionReason?> { + return interactor.allowedForCurrentUserByDevicePolicy.mapToReasonIfNotAllowed( + SuppressionReason.ReasonDevicePolicy + ) + } + + @Provides + @IntoSet + fun provideSettingDisabledSuppressor( + interactor: CommunalSettingsInteractor + ): Flow<SuppressionReason?> { + return interactor.settingEnabledForCurrentUser.mapToReasonIfNotAllowed( + SuppressionReason.ReasonSettingDisabled + ) + } + + @Provides + @IntoSet + fun bindUserLockedSuppressor(interactor: UserLockedInteractor): Flow<SuppressionReason?> { + return interactor.currentUserUnlocked.mapToReasonIfNotAllowed( + SuppressionReason.ReasonUserLocked + ) + } + + @Provides + @IntoSet + fun provideAutoOpenSuppressor( + interactor: CommunalAutoOpenInteractor + ): Flow<SuppressionReason?> { + return interactor.suppressionReason + } + + @Provides + @IntoSet + fun provideMainUserSuppressor( + interactor: SelectedUserInteractor + ): Flow<SuppressionReason?> { + return interactor.selectedUserInfo + .map { it.isMain } + .mapToReasonIfNotAllowed(SuppressionReason.ReasonSecondaryUser) + } + } +} 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 62a98d7a48ea..857fa5cac3e2 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 @@ -369,12 +369,10 @@ constructor( val swipeToHubEnabled: Flow<Boolean> by lazy { val inAllowedDeviceState = - if (swipeToHub) { - MutableStateFlow(true) - } else if (v2FlagEnabled()) { - communalInteractor.shouldShowCommunal + if (v2FlagEnabled()) { + communalSettingsInteractor.manualOpenEnabled } else { - MutableStateFlow(false) + MutableStateFlow(swipeToHub) } if (v2FlagEnabled()) { diff --git a/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsRepositoryImpl.kt index 6f579a3986c8..d7ffbb2e76b8 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsRepositoryImpl.kt @@ -18,7 +18,7 @@ package com.android.systemui.controls.settings import android.provider.Settings -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt index 69378b475938..449a995b782a 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt @@ -27,7 +27,7 @@ import com.android.systemui.Dumpable import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt index 675f00a89d23..b7315cc994a8 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt @@ -1,7 +1,7 @@ package com.android.systemui.deviceentry.data.repository import com.android.internal.widget.LockPatternUtils -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt index 29044d017d2d..f4db2cc71b38 100644 --- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt @@ -27,7 +27,7 @@ import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFI import android.hardware.devicestate.DeviceStateManager import android.hardware.devicestate.feature.flags.Flags as DeviceStateManagerFlags import com.android.internal.R -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState import java.util.concurrent.Executor diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayMetricsRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayMetricsRepository.kt index cef45dcae43e..3c554b9ff66b 100644 --- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayMetricsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayMetricsRepository.kt @@ -19,7 +19,7 @@ package com.android.systemui.display.data.repository import android.content.Context import android.content.res.Configuration import android.util.DisplayMetrics -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.log.LogBuffer diff --git a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt index a7c078f235b4..36b75c6fc6b8 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt @@ -61,7 +61,7 @@ constructor( fun startTransitionFromDream() { val showGlanceableHub = if (communalSettingsInteractor.isV2FlagEnabled()) { - communalInteractor.shouldShowCommunal.value + communalSettingsInteractor.autoOpenEnabled.value } else { communalInteractor.isCommunalEnabled.value && !keyguardUpdateMonitor.isEncryptedOrLockdown(userTracker.userId) diff --git a/packages/SystemUI/src/com/android/systemui/flags/PluggedInCondition.kt b/packages/SystemUI/src/com/android/systemui/flags/PluggedInCondition.kt index dc08570447a5..e5920924a4be 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/PluggedInCondition.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/PluggedInCondition.kt @@ -16,7 +16,7 @@ package com.android.systemui.flags -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.statusbar.policy.BatteryController import dagger.Lazy import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepository.kt index 922bc15c0633..4e7164ff12d7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepository.kt @@ -21,7 +21,7 @@ import android.hardware.input.InputManager.StickyModifierStateListener import android.hardware.input.StickyModifierState import android.provider.Settings import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.keyboard.stickykeys.StickyKeysLogger diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt index 07ed194dd68f..40861929add7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt @@ -30,7 +30,7 @@ import com.android.settingslib.notification.modes.EnableDndDialogFactory import com.android.settingslib.notification.modes.EnableDndDialogMetricsLogger import com.android.systemui.animation.Expandable import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt index e2642a0964c1..683c11a88b89 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt @@ -20,7 +20,7 @@ package com.android.systemui.keyguard.data.quickaffordance import android.content.Context import com.android.systemui.animation.Expandable import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt index 3555f06ce96f..a1dafb1438ca 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt @@ -24,7 +24,7 @@ import androidx.annotation.DrawableRes import com.android.systemui.res.R import com.android.systemui.animation.Expandable import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.controls.ControlsServiceInfo diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt index ad79177fdd76..01ff0e1344c6 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt @@ -23,7 +23,7 @@ import android.content.SharedPreferences import com.android.systemui.backup.BackupHelper import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.res.R import com.android.systemui.settings.UserFileManager diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt index 1c9bc9f39663..10fc4c2a02ff 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt @@ -23,7 +23,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.animation.Expandable -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt index d12c42a754f0..7c33e29bf25a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt @@ -21,7 +21,7 @@ import android.content.Context import com.android.systemui.res.R import com.android.systemui.animation.Expandable import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt index 760adbf58d93..56ea26e88b23 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt @@ -26,7 +26,7 @@ import android.service.quickaccesswallet.WalletCard import android.util.Log import com.android.systemui.animation.Expandable import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt index 0f5f31302670..30476b991baf 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt @@ -35,7 +35,7 @@ import com.android.systemui.biometrics.data.repository.FingerprintPropertyReposi import com.android.systemui.biometrics.shared.model.SensorStrength import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt index 4d999df69588..396f60645f00 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt @@ -24,7 +24,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.biometrics.AuthController import com.android.systemui.biometrics.shared.model.AuthenticationReason import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DevicePostureRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DevicePostureRepository.kt index 7c430920cb46..59e6a08c4511 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DevicePostureRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DevicePostureRepository.kt @@ -17,7 +17,7 @@ package com.android.systemui.keyguard.data.repository import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.shared.model.DevicePosture diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt index affcd33b7170..cd0efdae337d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt @@ -24,7 +24,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.biometrics.AuthController import com.android.systemui.biometrics.data.repository.FacePropertyRepository import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt index c5a6fa199c58..63a0286832d0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt @@ -20,7 +20,7 @@ import android.app.trust.TrustManager import com.android.keyguard.TrustGrantFlags import com.android.keyguard.logging.TrustRepositoryLogger import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt index ef06a85bd0d9..f53421d539fe 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt @@ -20,7 +20,6 @@ import android.animation.ValueAnimator import android.util.Log import com.android.app.animation.Interpolators import com.android.app.tracing.coroutines.launchTraced as launch -import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.communal.shared.model.CommunalScenes @@ -60,7 +59,6 @@ constructor( private val wakeToGoneInteractor: KeyguardWakeDirectlyToGoneInteractor, private val communalSettingsInteractor: CommunalSettingsInteractor, private val communalSceneInteractor: CommunalSceneInteractor, - private val communalInteractor: CommunalInteractor, ) : TransitionInteractor( fromState = KeyguardState.AOD, @@ -103,14 +101,14 @@ constructor( ) .collect { ( - _, + detailedWakefulness, startedStep, canWakeDirectlyToGone, ) -> val isKeyguardOccludedLegacy = keyguardInteractor.isKeyguardOccluded.value val biometricUnlockMode = keyguardInteractor.biometricUnlockState.value.mode val primaryBouncerShowing = keyguardInteractor.primaryBouncerShowing.value - val shouldShowCommunal = communalInteractor.shouldShowCommunal.value + val autoOpenCommunal = communalSettingsInteractor.autoOpenEnabled.value if (!maybeHandleInsecurePowerGesture()) { val shouldTransitionToLockscreen = @@ -137,8 +135,12 @@ constructor( (!KeyguardWmStateRefactor.isEnabled && canDismissLockscreen()) || (KeyguardWmStateRefactor.isEnabled && canWakeDirectlyToGone) + // Avoid transitioning to communal automatically if the device is waking + // up due to motion. val shouldTransitionToCommunal = - communalSettingsInteractor.isV2FlagEnabled() && shouldShowCommunal + communalSettingsInteractor.isV2FlagEnabled() && + autoOpenCommunal && + !detailedWakefulness.isAwakeFromMotionOrLift() if (shouldTransitionToGone) { // TODO(b/360368320): Adapt for scene framework 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 6f5f662d6fa3..4aaa1fab4c65 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 @@ -34,8 +34,9 @@ import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepositor import com.android.systemui.keyguard.shared.model.BiometricUnlockMode.Companion.isWakeAndUnlock import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.power.shared.model.WakefulnessModel import com.android.systemui.scene.shared.flag.SceneContainerFlag -import com.android.systemui.util.kotlin.Utils.Companion.sample +import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds @@ -121,9 +122,10 @@ constructor( private fun shouldTransitionToCommunal( shouldShowCommunal: Boolean, isCommunalAvailable: Boolean, + wakefulness: WakefulnessModel, ) = if (communalSettingsInteractor.isV2FlagEnabled()) { - shouldShowCommunal + shouldShowCommunal && !wakefulness.isAwakeFromMotionOrLift() } else { isCommunalAvailable && dreamManager.canStartDreaming(false) } @@ -148,14 +150,14 @@ constructor( } scope.launch { - powerInteractor.isAwake + powerInteractor.detailedWakefulness .debounce(50L) - .filterRelevantKeyguardStateAnd { isAwake -> isAwake } - .sample( + .filterRelevantKeyguardStateAnd { wakefulness -> wakefulness.isAwake() } + .sampleCombine( communalInteractor.isCommunalAvailable, - communalInteractor.shouldShowCommunal, + communalSettingsInteractor.autoOpenEnabled, ) - .collect { (_, isCommunalAvailable, shouldShowCommunal) -> + .collect { (detailedWakefulness, isCommunalAvailable, shouldShowCommunal) -> val isKeyguardOccludedLegacy = keyguardInteractor.isKeyguardOccluded.value val primaryBouncerShowing = keyguardInteractor.primaryBouncerShowing.value val isKeyguardGoingAway = keyguardInteractor.isKeyguardGoingAway.value @@ -186,7 +188,11 @@ constructor( } else if (isKeyguardOccludedLegacy) { startTransitionTo(KeyguardState.OCCLUDED) } else if ( - shouldTransitionToCommunal(shouldShowCommunal, isCommunalAvailable) + shouldTransitionToCommunal( + shouldShowCommunal, + isCommunalAvailable, + detailedWakefulness, + ) ) { if (!SceneContainerFlag.isEnabled) { transitionToGlanceableHub() @@ -208,8 +214,8 @@ constructor( scope.launch { powerInteractor.detailedWakefulness .filterRelevantKeyguardStateAnd { it.isAwake() } - .sample( - communalInteractor.shouldShowCommunal, + .sampleCombine( + communalSettingsInteractor.autoOpenEnabled, communalInteractor.isCommunalAvailable, keyguardInteractor.biometricUnlockState, wakeToGoneInteractor.canWakeDirectlyToGone, @@ -217,7 +223,7 @@ constructor( ) .collect { ( - _, + detailedWakefulness, shouldShowCommunal, isCommunalAvailable, biometricUnlockState, @@ -245,7 +251,11 @@ constructor( ) } } else if ( - shouldTransitionToCommunal(shouldShowCommunal, isCommunalAvailable) + shouldTransitionToCommunal( + shouldShowCommunal, + isCommunalAvailable, + detailedWakefulness, + ) ) { if (!SceneContainerFlag.isEnabled) { transitionToGlanceableHub() diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt index 0fb98ffa4a30..3b1b6fcc45f2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt @@ -115,7 +115,7 @@ constructor( powerInteractor.isAwake .debounce(50L) .filterRelevantKeyguardStateAnd { isAwake -> isAwake } - .sample(communalInteractor.shouldShowCommunal) + .sample(communalSettingsInteractor.autoOpenEnabled) .collect { shouldShowCommunal -> if (shouldShowCommunal) { // This case handles tapping the power button to transition through diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt index a01dc02bbd9f..f8c7a86687dd 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt @@ -20,7 +20,6 @@ import android.animation.ValueAnimator import android.util.MathUtils import com.android.app.animation.Interpolators import com.android.app.tracing.coroutines.launchTraced as launch -import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.communal.shared.model.CommunalScenes @@ -69,7 +68,6 @@ constructor( private val shadeRepository: ShadeRepository, powerInteractor: PowerInteractor, private val communalSettingsInteractor: CommunalSettingsInteractor, - private val communalInteractor: CommunalInteractor, private val communalSceneInteractor: CommunalSceneInteractor, private val swipeToDismissInteractor: SwipeToDismissInteractor, keyguardOcclusionInteractor: KeyguardOcclusionInteractor, @@ -355,7 +353,7 @@ constructor( private fun listenForLockscreenToGlanceableHubV2() { scope.launch { - communalInteractor.shouldShowCommunal + communalSettingsInteractor.autoOpenEnabled .filterRelevantKeyguardStateAnd { shouldShow -> shouldShow } .collect { communalSceneInteractor.changeScene( diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt index 705eaa22aa9a..55534c4f1444 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt @@ -20,11 +20,14 @@ package com.android.systemui.keyguard.domain.interactor import android.content.Context import android.content.Intent import android.content.IntentFilter +import android.os.PowerManager +import android.provider.Settings import android.view.accessibility.AccessibilityManager import androidx.annotation.VisibleForTesting import com.android.app.tracing.coroutines.launchTraced as launch import com.android.internal.logging.UiEvent import com.android.internal.logging.UiEventLogger +import com.android.systemui.Flags.doubleTapToSleep import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application @@ -36,10 +39,13 @@ import com.android.systemui.res.R import com.android.systemui.shade.PulsingGestureListener import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper +import com.android.systemui.util.settings.repository.UserAwareSecureSettingsRepository +import com.android.systemui.util.time.SystemClock import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -66,10 +72,13 @@ constructor( private val accessibilityManager: AccessibilityManagerWrapper, private val pulsingGestureListener: PulsingGestureListener, private val faceAuthInteractor: DeviceEntryFaceAuthInteractor, + private val secureSettingsRepository: UserAwareSecureSettingsRepository, + private val powerManager: PowerManager, + private val systemClock: SystemClock, ) { /** Whether the long-press handling feature should be enabled. */ val isLongPressHandlingEnabled: StateFlow<Boolean> = - if (isFeatureEnabled()) { + if (isLongPressFeatureEnabled()) { combine( transitionInteractor.isFinishedIn(KeyguardState.LOCKSCREEN), repository.isQuickSettingsVisible, @@ -85,6 +94,30 @@ constructor( initialValue = false, ) + /** Whether the double tap handling handling feature should be enabled. */ + val isDoubleTapHandlingEnabled: StateFlow<Boolean> = + if (isDoubleTapFeatureEnabled()) { + combine( + transitionInteractor.transitionValue(KeyguardState.LOCKSCREEN), + repository.isQuickSettingsVisible, + isDoubleTapSettingEnabled(), + ) { + isFullyTransitionedToLockScreen, + isQuickSettingsVisible, + isDoubleTapSettingEnabled -> + isFullyTransitionedToLockScreen == 1f && + !isQuickSettingsVisible && + isDoubleTapSettingEnabled + } + } else { + flowOf(false) + } + .stateIn( + scope = scope, + started = SharingStarted.WhileSubscribed(), + initialValue = false, + ) + private val _isMenuVisible = MutableStateFlow(false) /** Model for whether the menu should be shown. */ val isMenuVisible: StateFlow<Boolean> = @@ -116,7 +149,7 @@ constructor( private var delayedHideMenuJob: Job? = null init { - if (isFeatureEnabled()) { + if (isLongPressFeatureEnabled()) { broadcastDispatcher .broadcastFlow(IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) .onEach { hideMenu() } @@ -175,17 +208,30 @@ constructor( /** Notifies that the lockscreen has been double clicked. */ fun onDoubleClick() { - pulsingGestureListener.onDoubleTapEvent() + if (isDoubleTapHandlingEnabled.value) { + powerManager.goToSleep(systemClock.uptimeMillis()) + } else { + pulsingGestureListener.onDoubleTapEvent() + } + } + + private fun isDoubleTapSettingEnabled(): Flow<Boolean> { + return secureSettingsRepository.boolSetting(Settings.Secure.DOUBLE_TAP_TO_SLEEP) } private fun showSettings() { _shouldOpenSettings.value = true } - private fun isFeatureEnabled(): Boolean { + private fun isLongPressFeatureEnabled(): Boolean { return context.resources.getBoolean(R.bool.long_press_keyguard_customize_lockscreen_enabled) } + private fun isDoubleTapFeatureEnabled(): Boolean { + return doubleTapToSleep() && + context.resources.getBoolean(com.android.internal.R.bool.config_supportDoubleTapSleep) + } + /** Updates application state to ask to show the menu. */ private fun showMenu() { _isMenuVisible.value = true diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt index 17e14c3e83da..70a827d5e45b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt @@ -48,7 +48,7 @@ object DeviceEntryIconViewBinder { /** * Updates UI for: * - device entry containing view (parent view for the below views) - * - long-press handling view (transparent, no UI) + * - touch handling view (transparent, no UI) * - foreground icon view (lock/unlock/fingerprint) * - background view (optional) */ 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 e81d5354ec6e..5ef2d6fd3256 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 @@ -29,6 +29,7 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.plugins.clocks.VRectF import com.android.systemui.res.R import com.android.systemui.shared.R as sharedR import kotlinx.coroutines.DisposableHandle @@ -135,7 +136,7 @@ object KeyguardSmartspaceViewBinder { } } - if (clockBounds == null) return@collect + if (clockBounds == VRectF.ZERO) return@collect if (isLargeClock) { val largeDateHeight = keyguardRootView diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardTouchViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardTouchViewBinder.kt index 195413a80f4b..485e1ce5b2f7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardTouchViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardTouchViewBinder.kt @@ -75,6 +75,13 @@ object KeyguardTouchViewBinder { onSingleTap(x, y) } + + override fun onDoubleTapDetected(view: View) { + if (falsingManager.isFalseDoubleTap()) { + return + } + viewModel.onDoubleClick() + } } view.repeatWhenAttached { @@ -90,9 +97,20 @@ object KeyguardTouchViewBinder { } } } + launch("$TAG#viewModel.isDoubleTapHandlingEnabled") { + viewModel.isDoubleTapHandlingEnabled.collect { isEnabled -> + view.setDoublePressHandlingEnabled(isEnabled) + view.contentDescription = + if (isEnabled) { + view.resources.getString(R.string.accessibility_desc_lock_screen) + } else { + null + } + } + } } } } - private const val TAG = "KeyguardLongPressViewBinder" + private const val TAG = "KeyguardTouchViewBinder" } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardTouchHandlingViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardTouchHandlingViewModel.kt index 1d2edc6d406b..d4e7af48adfe 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardTouchHandlingViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardTouchHandlingViewModel.kt @@ -33,6 +33,9 @@ constructor( /** Whether the long-press handling feature should be enabled. */ val isLongPressHandlingEnabled: Flow<Boolean> = interactor.isLongPressHandlingEnabled + /** Whether the double tap handling feature should be enabled. */ + val isDoubleTapHandlingEnabled: Flow<Boolean> = interactor.isDoubleTapHandlingEnabled + /** Notifies that the user has long-pressed on the lock screen. * * @param isA11yAction: Whether the action was performed as an a11y action diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java index e7c2a454e16c..b71d8c995e51 100644 --- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java +++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java @@ -17,6 +17,7 @@ package com.android.systemui.media; import android.annotation.Nullable; +import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager.NameNotFoundException; @@ -126,6 +127,8 @@ public class RingtonePlayer implements CoreStartable { Log.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid=" + Binder.getCallingUid() + ")"); } + enforceUriUserId(uri); + Client client; synchronized (mClients) { client = mClients.get(token); @@ -207,6 +210,7 @@ public class RingtonePlayer implements CoreStartable { @Override public String getTitle(Uri uri) { + enforceUriUserId(uri); final UserHandle user = Binder.getCallingUserHandle(); return Ringtone.getTitle(getContextForUser(user), uri, false /*followSettingsUri*/, false /*allowRemote*/); @@ -214,6 +218,7 @@ public class RingtonePlayer implements CoreStartable { @Override public ParcelFileDescriptor openRingtone(Uri uri) { + enforceUriUserId(uri); final UserHandle user = Binder.getCallingUserHandle(); final ContentResolver resolver = getContextForUser(user).getContentResolver(); @@ -241,6 +246,28 @@ public class RingtonePlayer implements CoreStartable { } }; + /** + * Must be called from the Binder calling thread. + * Ensures caller is from the same userId as the content they're trying to access. + * @param uri the URI to check + * @throws SecurityException when in a non-system call and userId in uri differs from the + * caller's userId + */ + private void enforceUriUserId(Uri uri) throws SecurityException { + final int uriUserId = ContentProvider.getUserIdFromUri(uri, UserHandle.myUserId()); + // for a non-system call, verify the URI to play belongs to the same user as the caller + if (UserHandle.isApp(Binder.getCallingUid()) && (UserHandle.myUserId() != uriUserId)) { + final String errorMessage = "Illegal access to uri=" + uri + + " content associated with user=" + uriUserId + + ", current userID: " + UserHandle.myUserId(); + if (android.media.audio.Flags.ringtoneUserUriCheck()) { + throw new SecurityException(errorMessage); + } else { + Log.e(TAG, errorMessage, new Exception()); + } + } + } + private Context getContextForUser(UserHandle user) { try { return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user); diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt index 49b53c2d78ae..dfb32e66dae5 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt @@ -37,6 +37,7 @@ import com.android.settingslib.media.LocalMediaManager import com.android.settingslib.media.MediaDevice import com.android.settingslib.media.PhoneMediaDevice import com.android.settingslib.media.flags.Flags +import com.android.systemui.Flags.mediaControlsDeviceManagerBackgroundExecution import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.media.controls.shared.MediaControlDrawables @@ -94,8 +95,39 @@ constructor( data: MediaData, immediately: Boolean, receivedSmartspaceCardLatency: Int, - isSsReactivated: Boolean + isSsReactivated: Boolean, ) { + if (mediaControlsDeviceManagerBackgroundExecution()) { + bgExecutor.execute { onMediaLoaded(key, oldKey, data) } + } else { + onMediaLoaded(key, oldKey, data) + } + } + + override fun onMediaDataRemoved(key: String, userInitiated: Boolean) { + if (mediaControlsDeviceManagerBackgroundExecution()) { + bgExecutor.execute { onMediaRemoved(key, userInitiated) } + } else { + onMediaRemoved(key, userInitiated) + } + } + + fun dump(pw: PrintWriter) { + with(pw) { + println("MediaDeviceManager state:") + entries.forEach { (key, entry) -> + println(" key=$key") + entry.dump(pw) + } + } + } + + @MainThread + private fun processDevice(key: String, oldKey: String?, device: MediaDeviceData?) { + listeners.forEach { it.onMediaDeviceChanged(key, oldKey, device) } + } + + private fun onMediaLoaded(key: String, oldKey: String?, data: MediaData) { if (oldKey != null && oldKey != key) { val oldEntry = entries.remove(oldKey) oldEntry?.stop() @@ -104,9 +136,13 @@ constructor( if (entry == null || entry.token != data.token) { entry?.stop() if (data.device != null) { - // If we were already provided device info (e.g. from RCN), keep that and don't - // listen for updates, but process once to push updates to listeners - processDevice(key, oldKey, data.device) + // If we were already provided device info (e.g. from RCN), keep that and + // don't listen for updates, but process once to push updates to listeners + if (mediaControlsDeviceManagerBackgroundExecution()) { + fgExecutor.execute { processDevice(key, oldKey, data.device) } + } else { + processDevice(key, oldKey, data.device) + } return } val controller = data.token?.let { controllerFactory.create(it) } @@ -120,27 +156,18 @@ constructor( } } - override fun onMediaDataRemoved(key: String, userInitiated: Boolean) { + private fun onMediaRemoved(key: String, userInitiated: Boolean) { val token = entries.remove(key) token?.stop() - token?.let { listeners.forEach { it.onKeyRemoved(key, userInitiated) } } - } - - fun dump(pw: PrintWriter) { - with(pw) { - println("MediaDeviceManager state:") - entries.forEach { (key, entry) -> - println(" key=$key") - entry.dump(pw) + if (mediaControlsDeviceManagerBackgroundExecution()) { + fgExecutor.execute { + token?.let { listeners.forEach { it.onKeyRemoved(key, userInitiated) } } } + } else { + token?.let { listeners.forEach { it.onKeyRemoved(key, userInitiated) } } } } - @MainThread - private fun processDevice(key: String, oldKey: String?, device: MediaDeviceData?) { - listeners.forEach { it.onMediaDeviceChanged(key, oldKey, device) } - } - interface Listener { /** Called when the route has changed for a given notification. */ fun onMediaDeviceChanged(key: String, oldKey: String?, data: MediaDeviceData?) @@ -260,7 +287,7 @@ constructor( override fun onAboutToConnectDeviceAdded( deviceAddress: String, deviceName: String, - deviceIcon: Drawable? + deviceIcon: Drawable?, ) { aboutToConnectDeviceOverride = AboutToConnectDevice( @@ -270,8 +297,8 @@ constructor( /* enabled */ enabled = true, /* icon */ deviceIcon, /* name */ deviceName, - /* showBroadcastButton */ showBroadcastButton = false - ) + /* showBroadcastButton */ showBroadcastButton = false, + ), ) updateCurrent() } @@ -292,7 +319,7 @@ constructor( override fun onBroadcastMetadataChanged( broadcastId: Int, - metadata: BluetoothLeBroadcastMetadata + metadata: BluetoothLeBroadcastMetadata, ) { logger.logBroadcastMetadataChanged(broadcastId, metadata.toString()) updateCurrent() @@ -352,14 +379,14 @@ constructor( // route. connectedDevice?.copy( name = it.name ?: connectedDevice.name, - icon = icon + icon = icon, ) } ?: MediaDeviceData( enabled = false, icon = MediaControlDrawables.getHomeDevices(context), name = context.getString(R.string.media_seamless_other_device), - showBroadcastButton = false + showBroadcastButton = false, ) logger.logRemoteDevice(routingSession?.name, connectedDevice) } else { @@ -398,7 +425,7 @@ constructor( device?.iconWithoutBackground, name, id = device?.id, - showBroadcastButton = false + showBroadcastButton = false, ) } } @@ -415,7 +442,7 @@ constructor( icon = iconWithoutBackground, name = name, id = id, - showBroadcastButton = false + showBroadcastButton = false, ) private fun getLeAudioBroadcastDeviceData(): MediaDeviceData { @@ -425,7 +452,7 @@ constructor( icon = MediaControlDrawables.getLeAudioSharing(context), name = context.getString(R.string.audio_sharing_description), intent = null, - showBroadcastButton = false + showBroadcastButton = false, ) } else { MediaDeviceData( @@ -433,7 +460,7 @@ constructor( icon = MediaControlDrawables.getAntenna(context), name = broadcastDescription, intent = null, - showBroadcastButton = true + showBroadcastButton = true, ) } } @@ -449,7 +476,7 @@ constructor( device, controller, routingSession?.name, - selectedRoutes?.firstOrNull()?.name + selectedRoutes?.firstOrNull()?.name, ) if (controller == null) { @@ -514,7 +541,7 @@ constructor( MediaDataUtils.getAppLabel( context, localMediaManager.packageName, - context.getString(R.string.bt_le_audio_broadcast_dialog_unknown_name) + context.getString(R.string.bt_le_audio_broadcast_dialog_unknown_name), ) val isCurrentBroadcastedApp = TextUtils.equals(mediaApp, currentBroadcastedApp) if (isCurrentBroadcastedApp) { @@ -538,5 +565,5 @@ constructor( */ private data class AboutToConnectDevice( val fullMediaDevice: MediaDevice? = null, - val backupMediaDeviceData: MediaDeviceData? = null + val backupMediaDeviceData: MediaDeviceData? = null, ) diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaViewHolder.kt index 0e8e595f5b06..848d8221e4db 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaViewHolder.kt @@ -26,6 +26,10 @@ import android.widget.SeekBar import android.widget.TextView import androidx.constraintlayout.widget.Barrier import com.android.internal.widget.CachingIconView +import com.android.systemui.FontStyles.GSF_HEADLINE_SMALL +import com.android.systemui.FontStyles.GSF_LABEL_LARGE +import com.android.systemui.FontStyles.GSF_LABEL_MEDIUM +import com.android.systemui.FontStyles.GSF_TITLE_MEDIUM import com.android.systemui.res.R import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffectView import com.android.systemui.surfaceeffects.ripple.MultiRippleView @@ -177,9 +181,9 @@ class MediaViewHolder constructor(itemView: View) { R.id.touch_ripple_view, ) - val headlineSmallTF: Typeface = Typeface.create("gsf-headline-small", Typeface.NORMAL) - val titleMediumTF: Typeface = Typeface.create("gsf-title-medium", Typeface.NORMAL) - val labelMediumTF: Typeface = Typeface.create("gsf-label-medium", Typeface.NORMAL) - val labelLargeTF: Typeface = Typeface.create("gsf-label-large", Typeface.NORMAL) + val headlineSmallTF: Typeface = Typeface.create(GSF_HEADLINE_SMALL, Typeface.NORMAL) + val titleMediumTF: Typeface = Typeface.create(GSF_TITLE_MEDIUM, Typeface.NORMAL) + val labelMediumTF: Typeface = Typeface.create(GSF_LABEL_MEDIUM, Typeface.NORMAL) + val labelLargeTF: Typeface = Typeface.create(GSF_LABEL_LARGE, Typeface.NORMAL) } } diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java index 795e811db2bc..6ab4a52dc919 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java @@ -68,7 +68,6 @@ public class MediaOutputAdapterLegacy extends MediaOutputAdapterBase { private final Executor mMainExecutor; private final Executor mBackgroundExecutor; View mHolderView; - private boolean mIsInitVolumeFirstTime; public MediaOutputAdapterLegacy( MediaSwitchingController controller, @@ -78,7 +77,6 @@ public class MediaOutputAdapterLegacy extends MediaOutputAdapterBase { super(controller); mMainExecutor = mainExecutor; mBackgroundExecutor = backgroundExecutor; - mIsInitVolumeFirstTime = true; } @Override @@ -261,10 +259,9 @@ public class MediaOutputAdapterLegacy extends MediaOutputAdapterBase { updateSeekbarProgressBackground(); } } - boolean isCurrentSeekbarInvisible = mSeekBar.getVisibility() == View.GONE; mSeekBar.setVisibility(showSeekBar ? View.VISIBLE : View.GONE); if (showSeekBar) { - initSeekbar(device, isCurrentSeekbarInvisible); + initSeekbar(device); updateContainerContentA11yImportance(false /* isImportant */); mSeekBar.setContentDescription(contentDescription); } else { @@ -274,9 +271,8 @@ public class MediaOutputAdapterLegacy extends MediaOutputAdapterBase { void updateGroupSeekBar(String contentDescription) { updateSeekbarProgressBackground(); - boolean isCurrentSeekbarInvisible = mSeekBar.getVisibility() == View.GONE; mSeekBar.setVisibility(View.VISIBLE); - initGroupSeekbar(isCurrentSeekbarInvisible); + initGroupSeekbar(); updateContainerContentA11yImportance(false /* isImportant */); mSeekBar.setContentDescription(contentDescription); } @@ -364,31 +360,21 @@ public class MediaOutputAdapterLegacy extends MediaOutputAdapterBase { mActiveRadius, 0, 0}); } - private void initializeSeekbarVolume( - @Nullable MediaDevice device, int currentVolume, - boolean isCurrentSeekbarInvisible) { + private void initializeSeekbarVolume(@Nullable MediaDevice device, int currentVolume) { if (!isDragging()) { if (mSeekBar.getVolume() != currentVolume && (mLatestUpdateVolume == -1 || currentVolume == mLatestUpdateVolume)) { // Update only if volume of device and value of volume bar doesn't match. // Check if response volume match with the latest request, to ignore obsolete // response - if (isCurrentSeekbarInvisible && !mIsInitVolumeFirstTime) { + if (!mVolumeAnimator.isStarted()) { if (currentVolume == 0) { updateMutedVolumeIcon(device); } else { updateUnmutedVolumeIcon(device); } - } else { - if (!mVolumeAnimator.isStarted()) { - if (currentVolume == 0) { - updateMutedVolumeIcon(device); - } else { - updateUnmutedVolumeIcon(device); - } - mSeekBar.setVolume(currentVolume); - mLatestUpdateVolume = -1; - } + mSeekBar.setVolume(currentVolume); + mLatestUpdateVolume = -1; } } else if (currentVolume == 0) { mSeekBar.resetVolume(); @@ -398,12 +384,9 @@ public class MediaOutputAdapterLegacy extends MediaOutputAdapterBase { mLatestUpdateVolume = -1; } } - if (mIsInitVolumeFirstTime) { - mIsInitVolumeFirstTime = false; - } } - void initSeekbar(@NonNull MediaDevice device, boolean isCurrentSeekbarInvisible) { + void initSeekbar(@NonNull MediaDevice device) { SeekBarVolumeControl volumeControl = new SeekBarVolumeControl() { @Override public int getVolume() { @@ -432,7 +415,7 @@ public class MediaOutputAdapterLegacy extends MediaOutputAdapterBase { } mSeekBar.setMaxVolume(device.getMaxVolume()); final int currentVolume = device.getCurrentVolume(); - initializeSeekbarVolume(device, currentVolume, isCurrentSeekbarInvisible); + initializeSeekbarVolume(device, currentVolume); mSeekBar.setOnSeekBarChangeListener(new MediaSeekBarChangedListener( device, volumeControl) { @@ -445,7 +428,7 @@ public class MediaOutputAdapterLegacy extends MediaOutputAdapterBase { } // Initializes the seekbar for a group of devices. - void initGroupSeekbar(boolean isCurrentSeekbarInvisible) { + void initGroupSeekbar() { SeekBarVolumeControl volumeControl = new SeekBarVolumeControl() { @Override public int getVolume() { @@ -472,7 +455,7 @@ public class MediaOutputAdapterLegacy extends MediaOutputAdapterBase { mSeekBar.setMaxVolume(mController.getSessionVolumeMax()); final int currentVolume = mController.getSessionVolume(); - initializeSeekbarVolume(null, currentVolume, isCurrentSeekbarInvisible); + initializeSeekbarVolume(null, currentVolume); mSeekBar.setOnSeekBarChangeListener(new MediaSeekBarChangedListener( null, volumeControl) { @Override diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java index 9e6fa48d6f98..f79693138e24 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java @@ -145,7 +145,7 @@ public class MediaSwitchingController @VisibleForTesting final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>(); final List<MediaDevice> mCachedMediaDevices = new CopyOnWriteArrayList<>(); - private final List<MediaItem> mOutputMediaItemList = new CopyOnWriteArrayList<>(); + private final OutputMediaItemListProxy mOutputMediaItemListProxy; private final List<MediaItem> mInputMediaItemList = new CopyOnWriteArrayList<>(); private final AudioManager mAudioManager; private final PowerExemptionManager mPowerExemptionManager; @@ -226,6 +226,7 @@ public class MediaSwitchingController InfoMediaManager.createInstance(mContext, packageName, userHandle, lbm, token); mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, packageName); mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName); + mOutputMediaItemListProxy = new OutputMediaItemListProxy(); mDialogTransitionAnimator = dialogTransitionAnimator; mNearbyMediaDevicesManager = nearbyMediaDevicesManager; mMediaOutputColorSchemeLegacy = MediaOutputColorSchemeLegacy.fromSystemColors(mContext); @@ -245,7 +246,7 @@ public class MediaSwitchingController protected void start(@NonNull Callback cb) { synchronized (mMediaDevicesLock) { mCachedMediaDevices.clear(); - mOutputMediaItemList.clear(); + mOutputMediaItemListProxy.clear(); } mNearbyDeviceInfoMap.clear(); if (mNearbyMediaDevicesManager != null) { @@ -291,7 +292,7 @@ public class MediaSwitchingController mLocalMediaManager.stopScan(); synchronized (mMediaDevicesLock) { mCachedMediaDevices.clear(); - mOutputMediaItemList.clear(); + mOutputMediaItemListProxy.clear(); } if (mNearbyMediaDevicesManager != null) { mNearbyMediaDevicesManager.unregisterNearbyDevicesCallback(this); @@ -333,7 +334,7 @@ public class MediaSwitchingController @Override public void onDeviceListUpdate(List<MediaDevice> devices) { - boolean isListEmpty = mOutputMediaItemList.isEmpty(); + boolean isListEmpty = mOutputMediaItemListProxy.isEmpty(); if (isListEmpty || !mIsRefreshing) { buildMediaItems(devices); mCallback.onDeviceListChanged(); @@ -347,11 +348,12 @@ public class MediaSwitchingController } @Override - public void onSelectedDeviceStateChanged(MediaDevice device, - @LocalMediaManager.MediaDeviceState int state) { + public void onSelectedDeviceStateChanged( + MediaDevice device, @LocalMediaManager.MediaDeviceState int state) { mCallback.onRouteChanged(); mMetricLogger.logOutputItemSuccess( - device.toString(), new ArrayList<>(mOutputMediaItemList)); + device.toString(), + new ArrayList<>(mOutputMediaItemListProxy.getOutputMediaItemList())); } @Override @@ -362,7 +364,8 @@ public class MediaSwitchingController @Override public void onRequestFailed(int reason) { mCallback.onRouteChanged(); - mMetricLogger.logOutputItemFailure(new ArrayList<>(mOutputMediaItemList), reason); + mMetricLogger.logOutputItemFailure( + new ArrayList<>(mOutputMediaItemListProxy.getOutputMediaItemList()), reason); } /** @@ -381,7 +384,7 @@ public class MediaSwitchingController } try { synchronized (mMediaDevicesLock) { - mOutputMediaItemList.removeIf((MediaItem::isMutingExpectedDevice)); + mOutputMediaItemListProxy.removeMutingExpectedDevices(); } mAudioManager.cancelMuteAwaitConnection(mAudioManager.getMutingExpectedDevice()); } catch (Exception e) { @@ -574,14 +577,14 @@ public class MediaSwitchingController private void buildMediaItems(List<MediaDevice> devices) { synchronized (mMediaDevicesLock) { - List<MediaItem> updatedMediaItems = buildMediaItems(mOutputMediaItemList, devices); - mOutputMediaItemList.clear(); - mOutputMediaItemList.addAll(updatedMediaItems); + List<MediaItem> updatedMediaItems = + buildMediaItems(mOutputMediaItemListProxy.getOutputMediaItemList(), devices); + mOutputMediaItemListProxy.clearAndAddAll(updatedMediaItems); } } - protected List<MediaItem> buildMediaItems(List<MediaItem> oldMediaItems, - List<MediaDevice> devices) { + protected List<MediaItem> buildMediaItems( + List<MediaItem> oldMediaItems, List<MediaDevice> devices) { synchronized (mMediaDevicesLock) { if (!mLocalMediaManager.isPreferenceRouteListingExist()) { attachRangeInfo(devices); @@ -689,7 +692,8 @@ public class MediaSwitchingController * list. */ @GuardedBy("mMediaDevicesLock") - private List<MediaItem> categorizeMediaItemsLocked(MediaDevice connectedMediaDevice, + private List<MediaItem> categorizeMediaItemsLocked( + MediaDevice connectedMediaDevice, List<MediaDevice> devices, boolean needToHandleMutingExpectedDevice) { List<MediaItem> finalMediaItems = new ArrayList<>(); @@ -748,6 +752,14 @@ public class MediaSwitchingController } private void attachConnectNewDeviceItemIfNeeded(List<MediaItem> mediaItems) { + MediaItem connectNewDeviceItem = getConnectNewDeviceItem(); + if (connectNewDeviceItem != null) { + mediaItems.add(connectNewDeviceItem); + } + } + + @Nullable + private MediaItem getConnectNewDeviceItem() { boolean isSelectedDeviceNotAGroup = getSelectedMediaDevice().size() == 1; if (enableInputRouting()) { // When input routing is enabled, there are expected to be at least 2 total selected @@ -756,9 +768,9 @@ public class MediaSwitchingController } // Attach "Connect a device" item only when current output is not remote and not a group - if (!isCurrentConnectedDeviceRemote() && isSelectedDeviceNotAGroup) { - mediaItems.add(MediaItem.createPairNewDeviceMediaItem()); - } + return (!isCurrentConnectedDeviceRemote() && isSelectedDeviceNotAGroup) + ? MediaItem.createPairNewDeviceMediaItem() + : null; } private void attachRangeInfo(List<MediaDevice> devices) { @@ -847,13 +859,13 @@ public class MediaSwitchingController mediaItems.add( MediaItem.createGroupDividerMediaItem( mContext.getString(R.string.media_output_group_title))); - mediaItems.addAll(mOutputMediaItemList); + mediaItems.addAll(mOutputMediaItemListProxy.getOutputMediaItemList()); } public List<MediaItem> getMediaItemList() { // If input routing is not enabled, only return output media items. if (!enableInputRouting()) { - return mOutputMediaItemList; + return mOutputMediaItemListProxy.getOutputMediaItemList(); } // If input routing is enabled, return both output and input media items. @@ -959,7 +971,7 @@ public class MediaSwitchingController public boolean isAnyDeviceTransferring() { synchronized (mMediaDevicesLock) { - for (MediaItem mediaItem : mOutputMediaItemList) { + for (MediaItem mediaItem : mOutputMediaItemListProxy.getOutputMediaItemList()) { if (mediaItem.getMediaDevice().isPresent() && mediaItem.getMediaDevice().get().getState() == LocalMediaManager.MediaDeviceState.STATE_CONNECTING) { @@ -999,8 +1011,11 @@ public class MediaSwitchingController startActivity(launchIntent, controller); } - void launchLeBroadcastNotifyDialog(View mediaOutputDialog, BroadcastSender broadcastSender, - BroadcastNotifyDialog action, final DialogInterface.OnClickListener listener) { + void launchLeBroadcastNotifyDialog( + View mediaOutputDialog, + BroadcastSender broadcastSender, + BroadcastNotifyDialog action, + final DialogInterface.OnClickListener listener) { final AlertDialog.Builder builder = new AlertDialog.Builder(mContext); switch (action) { case ACTION_FIRST_LAUNCH: @@ -1230,8 +1245,8 @@ public class MediaSwitchingController return !sourceList.isEmpty(); } - boolean addSourceIntoSinkDeviceWithBluetoothLeAssistant(BluetoothDevice sink, - BluetoothLeBroadcastMetadata metadata, boolean isGroupOp) { + boolean addSourceIntoSinkDeviceWithBluetoothLeAssistant( + BluetoothDevice sink, BluetoothLeBroadcastMetadata metadata, boolean isGroupOp) { LocalBluetoothLeBroadcastAssistant assistant = mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile(); if (assistant == null) { diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/OutputMediaItemListProxy.java b/packages/SystemUI/src/com/android/systemui/media/dialog/OutputMediaItemListProxy.java new file mode 100644 index 000000000000..1c9c0b102cb7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/OutputMediaItemListProxy.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 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.media.dialog; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +/** A proxy of holding the list of Output Switcher's output media items. */ +public class OutputMediaItemListProxy { + private final List<MediaItem> mOutputMediaItemList; + + public OutputMediaItemListProxy() { + mOutputMediaItemList = new CopyOnWriteArrayList<>(); + } + + /** Returns the list of output media items. */ + public List<MediaItem> getOutputMediaItemList() { + return mOutputMediaItemList; + } + + /** Updates the list of output media items with the given list. */ + public void clearAndAddAll(List<MediaItem> updatedMediaItems) { + mOutputMediaItemList.clear(); + mOutputMediaItemList.addAll(updatedMediaItems); + } + + /** Removes the media items with muting expected devices. */ + public void removeMutingExpectedDevices() { + mOutputMediaItemList.removeIf((MediaItem::isMutingExpectedDevice)); + } + + /** Clears the output media item list. */ + public void clear() { + mOutputMediaItemList.clear(); + } + + /** Returns whether the output media item list is empty. */ + public boolean isEmpty() { + return mOutputMediaItemList.isEmpty(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/DismissibleHorizontalPager.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/DismissibleHorizontalPager.kt index fea5b3267562..8df916fe6969 100644 --- a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/DismissibleHorizontalPager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/DismissibleHorizontalPager.kt @@ -82,6 +82,7 @@ fun DismissibleHorizontalPager( modifier: Modifier = Modifier, key: ((Int) -> Any)? = null, pageSpacing: Dp = 0.dp, + isFalseTouchDetected: Boolean, indicator: @Composable BoxScope.() -> Unit, pageContent: @Composable PagerScope.(page: Int) -> Unit, ) { @@ -142,7 +143,7 @@ fun DismissibleHorizontalPager( Box(modifier = modifier) { HorizontalPager( state = state.pagerState, - userScrollEnabled = state.isScrollingEnabled, + userScrollEnabled = state.isScrollingEnabled && !isFalseTouchDetected, key = key, pageSpacing = pageSpacing, pageContent = pageContent, diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/Media.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/Media.kt index 9eb55a8eff2e..8751aa31f237 100644 --- a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/Media.kt +++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/Media.kt @@ -36,6 +36,8 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable +import androidx.compose.foundation.gestures.awaitEachGesture +import androidx.compose.foundation.gestures.awaitFirstDown import androidx.compose.foundation.hoverable import androidx.compose.foundation.indication import androidx.compose.foundation.interaction.DragInteraction @@ -72,7 +74,9 @@ import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.key import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -89,10 +93,13 @@ import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.drawscope.clipRect import androidx.compose.ui.graphics.drawscope.translate import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.input.pointer.PointerEventPass import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.Layout import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.semantics.clearAndSetSemantics +import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Dp @@ -202,6 +209,8 @@ private fun CardCarouselContent( ) { viewModel.cards.size } + var isFalseTouchDetected: Boolean by + remember(behavior.isCarouselScrollFalseTouch) { mutableStateOf(false) } val roundedCornerShape = RoundedCornerShape(32.dp) @@ -229,7 +238,16 @@ private fun CardCarouselContent( ) } }, - modifier = modifier.padding(8.dp).clip(roundedCornerShape), + isFalseTouchDetected = isFalseTouchDetected, + modifier = + modifier.padding(8.dp).clip(roundedCornerShape).pointerInput(behavior) { + if (behavior.isCarouselScrollFalseTouch != null) { + awaitEachGesture { + awaitFirstDown(false, PointerEventPass.Initial) + isFalseTouchDetected = behavior.isCarouselScrollFalseTouch.invoke() + } + } + }, ) { index -> Card( viewModel = viewModel.cards[index], @@ -662,7 +680,10 @@ private fun ContentScope.Navigation( modifier = Modifier.fillMaxWidth(), ) }, - modifier = Modifier.fillMaxWidth(), + modifier = + Modifier.fillMaxWidth().clearAndSetSemantics { + contentDescription = viewModel.contentDescription + }, ) } } @@ -1084,7 +1105,12 @@ data class MediaUiBehavior( val isCarouselDismissible: Boolean = true, val isCarouselScrollingEnabled: Boolean = true, val carouselVisibility: MediaCarouselVisibility = MediaCarouselVisibility.WhenNotEmpty, - val isFalsingProtectionNeeded: Boolean = false, + /** + * If provided, this callback will be consulted at the beginning of each carousel scroll gesture + * to see if the falsing system thinks that it's a false touch. If it then returns `true`, the + * scroll will be canceled. + */ + val isCarouselScrollFalseTouch: (() -> Boolean)? = null, ) @Stable diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaNavigationViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaNavigationViewModel.kt index c34c7337290f..ca7334341c87 100644 --- a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaNavigationViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaNavigationViewModel.kt @@ -59,6 +59,8 @@ sealed interface MediaNavigationViewModel { * the seek bar). The position/progress should be committed. */ val onScrubFinished: () -> Unit, + /** Accessibility string to attach to the seekbar UI element. */ + val contentDescription: String, ) : MediaNavigationViewModel /** The seek bar should be hidden. */ diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaViewModel.kt index b4f3d2724e75..15951165a19e 100644 --- a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaViewModel.kt @@ -17,6 +17,9 @@ package com.android.systemui.media.remedia.ui.viewmodel import android.content.Context +import android.icu.text.MeasureFormat +import android.icu.util.Measure +import android.icu.util.MeasureUnit import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf @@ -24,6 +27,8 @@ import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.graphics.ImageBitmap +import com.android.systemui.classifier.Classifier +import com.android.systemui.classifier.domain.interactor.runIfNotFalseTap import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.lifecycle.ExclusiveActivatable @@ -31,11 +36,14 @@ import com.android.systemui.media.remedia.domain.interactor.MediaInteractor import com.android.systemui.media.remedia.domain.model.MediaActionModel import com.android.systemui.media.remedia.shared.model.MediaColorScheme import com.android.systemui.media.remedia.shared.model.MediaSessionState +import com.android.systemui.plugins.FalsingManager import com.android.systemui.res.R import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import java.util.Locale import kotlin.math.roundToLong +import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.awaitCancellation /** Models UI state for a media element. */ @@ -43,6 +51,7 @@ class MediaViewModel @AssistedInject constructor( private val interactor: MediaInteractor, + private val falsingSystem: FalsingSystem, @Assisted private val context: Context, @Assisted private val carouselVisibility: MediaCarouselVisibility, ) : ExclusiveActivatable() { @@ -106,12 +115,20 @@ constructor( seekProgress = progress }, onScrubFinished = { - interactor.seek( - sessionKey = session.key, - to = (seekProgress * session.durationMs).roundToLong(), - ) + if (!falsingSystem.isFalseTouch(Classifier.MEDIA_SEEKBAR)) { + interactor.seek( + sessionKey = session.key, + to = (seekProgress * session.durationMs).roundToLong(), + ) + } isScrubbing = false }, + contentDescription = + context.getString( + R.string.controls_media_seekbar_description, + formatTimeContentDescription(session.positionMs), + formatTimeContentDescription(session.durationMs), + ), ) } else { MediaNavigationViewModel.Hidden @@ -139,20 +156,36 @@ constructor( R.string.controls_media_dismiss_button ), onClick = { - interactor.hide(session.key) - isGutsVisible = false + falsingSystem.runIfNotFalseTap( + FalsingManager.LOW_PENALTY + ) { + interactor.hide(session.key) + isGutsVisible = false + } }, ) } else { MediaGutsButtonViewModel( text = context.getString(R.string.cancel), - onClick = { isGutsVisible = false }, + onClick = { + falsingSystem.runIfNotFalseTap( + FalsingManager.LOW_PENALTY + ) { + isGutsVisible = false + } + }, ) }, secondaryAction = MediaGutsButtonViewModel( text = context.getString(R.string.cancel), - onClick = { isGutsVisible = false }, + onClick = { + falsingSystem.runIfNotFalseTap( + FalsingManager.LOW_PENALTY + ) { + isGutsVisible = false + } + }, ) .takeIf { session.canBeHidden }, settingsButton = @@ -165,7 +198,11 @@ constructor( res = R.string.controls_media_settings_button ), ), - onClick = { interactor.openMediaSettings() }, + onClick = { + falsingSystem.runIfNotFalseTap(FalsingManager.LOW_PENALTY) { + interactor.openMediaSettings() + } + }, ), onLongClick = { isGutsVisible = false }, ) @@ -178,7 +215,12 @@ constructor( icon = session.outputDevice.icon, text = session.outputDevice.name, onClick = { - // TODO(b/397989775): tell the UI to show the output switcher. + falsingSystem.runIfNotFalseTap( + FalsingManager.MODERATE_PENALTY + ) { + // TODO(b/397989775): tell the UI to show the output + // switcher. + } }, ) ) @@ -189,12 +231,16 @@ constructor( return MediaSecondaryActionViewModel.Action( icon = session.outputDevice.icon, onClick = { - // TODO(b/397989775): tell the UI to show the output switcher. + falsingSystem.runIfNotFalseTap(FalsingManager.MODERATE_PENALTY) { + // TODO(b/397989775): tell the UI to show the output switcher. + } }, ) } - override val onClick = session.onClick + override val onClick = { + falsingSystem.runIfNotFalseTap(FalsingManager.LOW_PENALTY) { session.onClick() } + } override val onClickLabel = context.getString(R.string.controls_media_playing_item_description) override val onLongClick = { isGutsVisible = true } @@ -230,7 +276,14 @@ constructor( MediaPlayPauseActionViewModel( state = mediaSessionState, icon = icon, - onClick = onClick ?: {}, + onClick = + onClick?.let { + { + falsingSystem.runIfNotFalseTap(FalsingManager.MODERATE_PENALTY) { + it() + } + } + }, ) is MediaActionModel.None, is MediaActionModel.ReserveSpace -> null @@ -240,14 +293,72 @@ constructor( private fun MediaActionModel.toSecondaryActionViewModel(): MediaSecondaryActionViewModel { return when (this) { is MediaActionModel.Action -> - MediaSecondaryActionViewModel.Action(icon = icon, onClick = onClick) + MediaSecondaryActionViewModel.Action( + icon = icon, + onClick = + onClick?.let { + { + falsingSystem.runIfNotFalseTap(FalsingManager.MODERATE_PENALTY) { + it() + } + } + }, + ) is MediaActionModel.ReserveSpace -> MediaSecondaryActionViewModel.ReserveSpace is MediaActionModel.None -> MediaSecondaryActionViewModel.None } } + /** + * Returns a time string suitable for content description, e.g. "12 minutes 34 seconds" + * + * Follows same logic as Chronometer#formatDuration + */ + private fun formatTimeContentDescription(milliseconds: Long): String { + var seconds = milliseconds.milliseconds.inWholeSeconds + + val hours = + if (seconds >= OneHourInSec) { + seconds / OneHourInSec + } else { + 0 + } + seconds -= hours * OneHourInSec + + val minutes = + if (seconds >= OneMinuteInSec) { + seconds / OneMinuteInSec + } else { + 0 + } + seconds -= minutes * OneMinuteInSec + + val measures = arrayListOf<Measure>() + if (hours > 0) { + measures.add(Measure(hours, MeasureUnit.HOUR)) + } + if (minutes > 0) { + measures.add(Measure(minutes, MeasureUnit.MINUTE)) + } + measures.add(Measure(seconds, MeasureUnit.SECOND)) + + return MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE) + .formatMeasures(*measures.toTypedArray()) + } + + interface FalsingSystem { + fun runIfNotFalseTap(@FalsingManager.Penalty penalty: Int, block: () -> Unit) + + fun isFalseTouch(@Classifier.InteractionType interactionType: Int): Boolean + } + @AssistedFactory interface Factory { fun create(context: Context, carouselVisibility: MediaCarouselVisibility): MediaViewModel } + + companion object { + private const val OneMinuteInSec = 60 + private const val OneHourInSec = OneMinuteInSec * 60 + } } diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepository.kt index 4ff54d4eae65..42d27619f60f 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepository.kt @@ -26,7 +26,7 @@ import android.os.IBinder import android.util.Log import android.view.Display import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background diff --git a/packages/SystemUI/src/com/android/systemui/model/SysUIStateChange.kt b/packages/SystemUI/src/com/android/systemui/model/SysUIStateChange.kt index aaed606f8fb2..cec846e84f01 100644 --- a/packages/SystemUI/src/com/android/systemui/model/SysUIStateChange.kt +++ b/packages/SystemUI/src/com/android/systemui/model/SysUIStateChange.kt @@ -43,8 +43,6 @@ class StateChange { return this } - fun hasChanges() = flagsToSet != 0L || flagsToClear != 0L - /** * Applies all changed flags to [sysUiState]. * @@ -83,6 +81,7 @@ class StateChange { iterateBits(flagsToSet or flagsToClear) { bit -> sysUiState.setFlag(bit, false) } } + /** Resets all the pending changes. */ fun clear() { flagsToSet = 0 flagsToClear = 0 diff --git a/packages/SystemUI/src/com/android/systemui/model/SysUiState.kt b/packages/SystemUI/src/com/android/systemui/model/SysUiState.kt index e99ee7ddb919..71cb74543485 100644 --- a/packages/SystemUI/src/com/android/systemui/model/SysUiState.kt +++ b/packages/SystemUI/src/com/android/systemui/model/SysUiState.kt @@ -22,6 +22,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.display.data.repository.PerDisplayInstanceProviderWithTeardown import com.android.systemui.dump.DumpManager import com.android.systemui.model.SysUiState.SysUiStateCallback +import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround import com.android.systemui.shared.system.QuickStepContract import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags import dagger.assisted.Assisted @@ -29,6 +30,7 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import dalvik.annotation.optimization.NeverCompile import java.io.PrintWriter +import java.lang.Long.bitCount import javax.inject.Inject /** Contains sysUi state flags and notifies registered listeners whenever changes happen. */ @@ -111,8 +113,7 @@ constructor( get() = _flags private var _flags: Long = 0 - private var flagsToSet: Long = 0 - private var flagsToClear: Long = 0 + private val stateChange = StateChange() /** * Add listener to be notified of changes made to SysUI state. The callback will also be called @@ -132,13 +133,11 @@ constructor( /** Methods to this call can be chained together before calling [.commitUpdate]. */ override fun setFlag(@SystemUiStateFlags flag: Long, enabled: Boolean): SysUiState { - val toSet = flagWithOptionalOverrides(flag, enabled, displayId, sceneContainerPlugin) - - if (toSet) { - flagsToSet = flagsToSet or flag - } else { - flagsToClear = flagsToClear or flag + if (ShadeWindowGoesAround.isEnabled && bitCount(flag) > 1) { + error("Flags should be a single bit.") } + val toSet = flagWithOptionalOverrides(flag, enabled, displayId, sceneContainerPlugin) + stateChange.setFlag(flag, toSet) return this } @@ -147,27 +146,19 @@ constructor( ReplaceWith("commitUpdate()"), ) override fun commitUpdate(displayId: Int) { - // TODO b/398011576 - handle updates for different displays. commitUpdate() } override fun commitUpdate() { - updateFlags() - flagsToSet = 0 - flagsToClear = 0 - } - - private fun updateFlags() { - var newState = flags - newState = newState or flagsToSet - newState = newState and flagsToClear.inv() + val newState = stateChange.applyTo(flags) notifyAndSetSystemUiStateChanged(newState, flags) + stateChange.clear() } /** Notify all those who are registered that the state has changed. */ private fun notifyAndSetSystemUiStateChanged(newFlags: Long, oldFlags: Long) { if (SysUiState.DEBUG) { - Log.d(TAG, "SysUiState changed: old=$oldFlags new=$newFlags") + Log.d(TAG, "SysUiState changed for displayId=$displayId: old=$oldFlags new=$newFlags") } if (newFlags != oldFlags) { _flags = newFlags @@ -185,6 +176,8 @@ constructor( pw.println(QuickStepContract.isBackGestureDisabled(flags, false /* forTrackpad */)) pw.print(" assistantGestureDisabled=") pw.println(QuickStepContract.isAssistantGestureDisabled(flags)) + pw.print(" pendingStateChanges=") + pw.println(stateChange.toString()) } override fun destroy() { diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt index d8fc52bcc55a..8dc27bf4ac3e 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt @@ -162,10 +162,6 @@ constructor( ): Boolean { return this@NoteTaskInitializer.handleKeyGestureEvent(event) } - - override fun isKeyGestureSupported(gestureType: Int): Boolean { - return this@NoteTaskInitializer.isKeyGestureSupported(gestureType) - } } /** @@ -225,10 +221,6 @@ constructor( return true } - private fun isKeyGestureSupported(gestureType: Int): Boolean { - return gestureType == KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES - } - companion object { val MULTI_PRESS_TIMEOUT = ViewConfiguration.getMultiPressTimeout().toLong() val LONG_PRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout().toLong() diff --git a/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt index 43bd6aa37b5a..faa77e51ec24 100644 --- a/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt @@ -24,7 +24,7 @@ import android.content.IntentFilter import android.os.PowerManager import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.power.shared.model.DozeScreenStateModel diff --git a/packages/SystemUI/src/com/android/systemui/power/shared/model/WakefulnessModel.kt b/packages/SystemUI/src/com/android/systemui/power/shared/model/WakefulnessModel.kt index 297c6af5a4a7..f368c53c5b39 100644 --- a/packages/SystemUI/src/com/android/systemui/power/shared/model/WakefulnessModel.kt +++ b/packages/SystemUI/src/com/android/systemui/power/shared/model/WakefulnessModel.kt @@ -61,6 +61,11 @@ data class WakefulnessModel( (lastWakeReason == WakeSleepReason.TAP || lastWakeReason == WakeSleepReason.GESTURE) } + fun isAwakeFromMotionOrLift(): Boolean { + return isAwake() && + (lastWakeReason == WakeSleepReason.MOTION || lastWakeReason == WakeSleepReason.LIFT) + } + override fun logDiffs(prevVal: WakefulnessModel, row: TableRowLogger) { row.logChange(columnName = "wakefulness", value = toString()) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt index 8920c86282da..a4386dee7264 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt @@ -421,7 +421,7 @@ constructor( } override fun isCustomizing(): Boolean { - return viewModel.containerViewModel.editModeViewModel.isEditing.value + return viewModel.isEditing } override fun closeCustomizer() { @@ -657,7 +657,8 @@ constructor( */ !alwaysCompose || (viewModel.isQsVisibleAndAnyShadeExpanded && - viewModel.expansionState.progress < 1f) + viewModel.expansionState.progress < 1f && + !viewModel.isEditing) }, ) } @@ -784,7 +785,8 @@ constructor( */ !alwaysCompose || (viewModel.isQsVisibleAndAnyShadeExpanded && - viewModel.expansionState.progress > 0f) + viewModel.expansionState.progress > 0f && + !viewModel.isEditing) }, ) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt index 767acc5fa76a..b61fa9cfe264 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt @@ -35,7 +35,6 @@ import com.android.systemui.animation.ShadeInterpolation import com.android.systemui.classifier.Classifier import com.android.systemui.classifier.domain.interactor.FalsingInteractor import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor -import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.Edge @@ -307,6 +306,12 @@ constructor( val animateTilesExpansion: Boolean get() = inFirstPage && !mediaSuddenlyAppearingInLandscape + val isEditing by + hydrator.hydratedStateOf( + traceName = "isEditing", + source = containerViewModel.editModeViewModel.isEditing, + ) + private val inFirstPage: Boolean get() = inFirstPageViewModel.inFirstPage diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/data/repository/ForegroundServicesRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/data/repository/ForegroundServicesRepository.kt index bd9d70c13572..eb99fec7a0a8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/footer/data/repository/ForegroundServicesRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/footer/data/repository/ForegroundServicesRepository.kt @@ -17,7 +17,7 @@ package com.android.systemui.qs.footer.data.repository import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.qs.FgsManagerController import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt index 865ae9a37d87..22971a9eb703 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt @@ -85,6 +85,15 @@ constructor( val pagerState = rememberPagerState(0) { pages.size } + LaunchedEffect(listening, pagerState) { + snapshotFlow { listening() } + .collect { + if (!listening()) { + pagerState.scrollToPage(0) + } + } + } + // Used to track if this is currently in the first page or not, for animations LaunchedEffect(key1 = pagerState) { snapshotFlow { pagerState.currentPage == 0 }.collect { viewModel.inFirstPage = it } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileDetails.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileDetails.kt index 701f44e9981c..d40ecc9565ae 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileDetails.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileDetails.kt @@ -61,6 +61,9 @@ fun TileDetails(modifier: Modifier = Modifier, detailsViewModel: DetailsViewMode DisposableEffect(Unit) { onDispose { detailsViewModel.closeDetailedView() } } + val title = tileDetailedViewModel.title + val subTitle = tileDetailedViewModel.subTitle + Column( modifier = modifier @@ -90,7 +93,7 @@ fun TileDetails(modifier: Modifier = Modifier, detailsViewModel: DetailsViewMode ) } Text( - text = tileDetailedViewModel.getTitle(), + text = title, modifier = Modifier.align(Alignment.CenterVertically), textAlign = TextAlign.Center, style = MaterialTheme.typography.titleLarge, @@ -110,7 +113,7 @@ fun TileDetails(modifier: Modifier = Modifier, detailsViewModel: DetailsViewMode } } Text( - text = tileDetailedViewModel.getSubTitle(), + text = subTitle, modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center, style = MaterialTheme.typography.titleSmall, diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt index 99f52c28a137..3ae90d2f976b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt @@ -16,14 +16,20 @@ package com.android.systemui.qs.panels.ui.compose.toolbar +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.shape.CornerSize +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import com.android.systemui.compose.modifiers.sysuiResTag +import com.android.systemui.development.ui.compose.BuildNumber import com.android.systemui.qs.footer.ui.compose.IconButton import com.android.systemui.qs.panels.ui.viewmodel.toolbar.ToolbarViewModel +import com.android.systemui.qs.ui.compose.borderOnFocus @Composable fun Toolbar(viewModel: ToolbarViewModel, modifier: Modifier = Modifier) { @@ -44,7 +50,18 @@ fun Toolbar(viewModel: ToolbarViewModel, modifier: Modifier = Modifier) { Modifier.sysuiResTag("settings_button_container"), ) - Spacer(modifier = Modifier.weight(1f)) + Box(modifier = Modifier.weight(1f), contentAlignment = Alignment.Center) { + BuildNumber( + viewModelFactory = viewModel.buildNumberViewModelFactory, + textColor = MaterialTheme.colorScheme.onSurface, + modifier = + Modifier.borderOnFocus( + color = MaterialTheme.colorScheme.secondary, + cornerSize = CornerSize(1.dp), + ) + .wrapContentSize(), + ) + } IconButton( { viewModel.powerButtonViewModel }, diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModel.kt index e54bfa29d2db..10d7871b8ea2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModel.kt @@ -24,6 +24,7 @@ import androidx.compose.runtime.setValue import com.android.systemui.animation.Expandable import com.android.systemui.classifier.domain.interactor.FalsingInteractor import com.android.systemui.classifier.domain.interactor.runIfNotFalseTap +import com.android.systemui.development.ui.viewmodel.BuildNumberViewModel import com.android.systemui.globalactions.GlobalActionsDialogLite import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.Hydrator @@ -46,6 +47,7 @@ class ToolbarViewModel @AssistedInject constructor( editModeButtonViewModelFactory: EditModeButtonViewModel.Factory, + val buildNumberViewModelFactory: BuildNumberViewModel.Factory, private val footerActionsInteractor: FooterActionsInteractor, private val globalActionsDialogLiteProvider: Provider<GlobalActionsDialogLite>, private val falsingInteractor: FalsingInteractor, diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredRepository.kt index 1cd5d100ec00..e3a8ffd0f480 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredRepository.kt @@ -6,7 +6,7 @@ import android.os.UserHandle import android.provider.Settings import android.util.Log import com.android.systemui.broadcast.BroadcastDispatcher -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.common.shared.model.PackageChangeModel.Empty.user import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddable.kt index 88a49ee109aa..53d2554f0e82 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddable.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddable.kt @@ -16,7 +16,7 @@ package com.android.systemui.qs.pipeline.domain.autoaddable -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking import com.android.systemui.qs.pipeline.domain.model.AutoAddable diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddable.kt index 76bfad936116..a3b4c71c7641 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddable.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddable.kt @@ -16,7 +16,7 @@ package com.android.systemui.qs.pipeline.domain.autoaddable -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddable.kt index e9c91ca0db12..66af6d8b3e18 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddable.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddable.kt @@ -19,7 +19,7 @@ package com.android.systemui.qs.pipeline.domain.autoaddable import android.content.Context import android.hardware.display.ColorDisplayManager import android.hardware.display.NightDisplayListener -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.NightDisplayListenerModule import com.android.systemui.dagger.SysUISingleton import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddable.kt index 88d7f06dfada..ff3fd3781181 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddable.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddable.kt @@ -21,7 +21,7 @@ import android.content.pm.PackageManager import android.content.res.Resources import android.text.TextUtils import com.android.systemui.res.R -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddable.kt index 3f619c08261d..c66c9dc9ba6a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddable.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddable.kt @@ -18,7 +18,7 @@ package com.android.systemui.qs.pipeline.domain.autoaddable import android.content.pm.UserInfo import android.os.UserHandle -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.qs.pipeline.data.restoreprocessors.WorkTileRestoreProcessor import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java index c6fc868b3dc8..0db05c1355ab 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java @@ -92,6 +92,7 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy private static final long DEFAULT_STALE_TIMEOUT = 10 * DateUtils.MINUTE_IN_MILLIS; protected static final Object ARG_SHOW_TRANSIENT_ENABLING = new Object(); + protected static final Object ARG_SHOW_TRANSIENT_DISABLING = new Object(); private static final int READY_STATE_NOT_READY = 0; private static final int READY_STATE_READYING = 1; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SubtitleArrayMapping.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SubtitleArrayMapping.kt index 61a8fa3d2a6e..cd0b70e5e988 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SubtitleArrayMapping.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SubtitleArrayMapping.kt @@ -27,6 +27,7 @@ object SubtitleArrayMapping { subtitleIdsMap["cell"] = R.array.tile_states_cell subtitleIdsMap["battery"] = R.array.tile_states_battery subtitleIdsMap["dnd"] = R.array.tile_states_dnd + subtitleIdsMap["modes_dnd"] = R.array.tile_states_modes_dnd subtitleIdsMap["flashlight"] = R.array.tile_states_flashlight subtitleIdsMap["rotation"] = R.array.tile_states_rotation subtitleIdsMap["bt"] = R.array.tile_states_bt diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index 4b1c90f0c2ce..9aeaa22c549e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -56,6 +56,7 @@ import com.android.systemui.plugins.qs.TileDetailsViewModel; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QsEventLogger; +import com.android.systemui.qs.flags.QsInCompose; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.res.R; @@ -196,11 +197,18 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { protected void handleUpdateState(BooleanState state, Object arg) { checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_BLUETOOTH); final boolean transientEnabling = arg == ARG_SHOW_TRANSIENT_ENABLING; - final boolean enabled = transientEnabling || mController.isBluetoothEnabled(); + final boolean transientDisabling = + QsInCompose.isEnabled() && arg == ARG_SHOW_TRANSIENT_DISABLING; + final boolean enabled = + transientEnabling || (mController.isBluetoothEnabled() && !transientDisabling); final boolean connected = mController.isBluetoothConnected(); final boolean connecting = mController.isBluetoothConnecting(); - state.isTransient = transientEnabling || connecting || - mController.getBluetoothState() == BluetoothAdapter.STATE_TURNING_ON; + state.isTransient = transientEnabling || transientDisabling || connecting + || mController.getBluetoothState() == BluetoothAdapter.STATE_TURNING_ON; + if (QsInCompose.isEnabled()) { + state.isTransient = state.isTransient + || mController.getBluetoothState() == BluetoothAdapter.STATE_TURNING_OFF; + } if (!enabled || !connected || state.isTransient) { stopListeningToStaleDeviceMetadata(); } @@ -208,7 +216,8 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { state.value = enabled; state.label = mContext.getString(R.string.quick_settings_bluetooth_label); state.secondaryLabel = TextUtils.emptyIfNull( - getSecondaryLabel(enabled, connecting, connected, state.isTransient)); + getSecondaryLabel(enabled, connecting, connected, + state.isTransient && transientEnabling)); state.contentDescription = mContext.getString( R.string.accessibility_quick_settings_bluetooth); state.stateDescription = ""; @@ -241,8 +250,13 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { private void toggleBluetooth() { final boolean isEnabled = mState.value; - // Immediately enter transient enabling state when turning bluetooth on. - refreshState(isEnabled ? null : ARG_SHOW_TRANSIENT_ENABLING); + if (QsInCompose.isEnabled()) { + // Immediately enter transient enabling state when toggling bluetooth state. + refreshState(isEnabled ? ARG_SHOW_TRANSIENT_DISABLING : ARG_SHOW_TRANSIENT_ENABLING); + } else { + // Immediately enter transient enabling state when turning bluetooth on. + refreshState(isEnabled ? ARG_SHOW_TRANSIENT_DISABLING : null); + } mController.setBluetoothEnabled(!isEnabled); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesDndTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesDndTile.kt new file mode 100644 index 000000000000..52b02066c35a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesDndTile.kt @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2025 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.tiles + +import android.content.Intent +import android.os.Handler +import android.os.Looper +import androidx.annotation.DrawableRes +import androidx.annotation.VisibleForTesting +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.coroutineScope +import androidx.lifecycle.repeatOnLifecycle +import com.android.app.tracing.coroutines.launchTraced as launch +import com.android.internal.logging.MetricsLogger +import com.android.systemui.animation.Expandable +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.modes.shared.ModesUi +import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.plugins.FalsingManager +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.asQSTileIcon +import com.android.systemui.qs.logging.QSLogger +import com.android.systemui.qs.tileimpl.QSTileImpl +import com.android.systemui.qs.tiles.impl.modes.domain.interactor.ModesDndTileDataInteractor +import com.android.systemui.qs.tiles.impl.modes.domain.interactor.ModesDndTileUserActionInteractor +import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesDndTileModel +import com.android.systemui.qs.tiles.impl.modes.ui.ModesDndTileMapper +import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProvider +import com.android.systemui.qs.tiles.viewmodel.QSTileState +import com.android.systemui.res.R +import javax.inject.Inject +import kotlinx.coroutines.runBlocking + +/** + * Standalone tile used to control the DND Mode. Contrast to [ModesTile] (the tile that opens a + * dialog showing the list of all modes) and [DndTile] (the tile used to toggle interruption + * filtering in the pre-MODES_UI world). + */ +class ModesDndTile +@Inject +constructor( + host: QSHost, + uiEventLogger: QsEventLogger, + @Background backgroundLooper: Looper, + @Main mainHandler: Handler, + falsingManager: FalsingManager, + metricsLogger: MetricsLogger, + statusBarStateController: StatusBarStateController, + activityStarter: ActivityStarter, + qsLogger: QSLogger, + qsTileConfigProvider: QSTileConfigProvider, + private val dataInteractor: ModesDndTileDataInteractor, + private val tileMapper: ModesDndTileMapper, + private val userActionInteractor: ModesDndTileUserActionInteractor, +) : + QSTileImpl<BooleanState>( + host, + uiEventLogger, + backgroundLooper, + mainHandler, + falsingManager, + metricsLogger, + statusBarStateController, + activityStarter, + qsLogger, + ) { + + private lateinit var tileState: QSTileState + private val config = qsTileConfigProvider.getConfig(TILE_SPEC) + + init { + lifecycle.coroutineScope.launch { + lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) { + dataInteractor.tileData().collect { refreshState(it) } + } + } + } + + override fun isAvailable(): Boolean = ModesUi.isEnabled && android.app.Flags.modesUiDndTile() + + override fun getTileLabel(): CharSequence = + mContext.getString(R.string.quick_settings_dnd_label) + + override fun newTileState(): BooleanState = BooleanState() + + override fun handleClick(expandable: Expandable?) = runBlocking { + userActionInteractor.handleClick() + } + + override fun getLongClickIntent(): Intent? = userActionInteractor.getSettingsIntent() + + @VisibleForTesting + public override fun handleUpdateState(state: BooleanState?, arg: Any?) { + val model = arg as? ModesDndTileModel ?: dataInteractor.getCurrentTileModel() + + tileState = tileMapper.map(config, model) + state?.apply { + value = model.isActivated + this.state = tileState.activationState.legacyState + icon = + tileState.icon?.asQSTileIcon() + ?: maybeLoadResourceIcon(iconResId(model.isActivated)) + label = tileLabel + secondaryLabel = tileState.secondaryLabel + contentDescription = tileState.contentDescription + expandedAccessibilityClassName = tileState.expandedAccessibilityClassName + } + } + + @DrawableRes + private fun iconResId(activated: Boolean): Int = + if (activated) R.drawable.qs_dnd_icon_on else R.drawable.qs_dnd_icon_off + + companion object { + const val TILE_SPEC = "modes_dnd" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailsContent.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailsContent.kt index 7d396c58630e..8ffba1e5f3dd 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailsContent.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailsContent.kt @@ -19,26 +19,14 @@ package com.android.systemui.qs.tiles.dialog import android.view.LayoutInflater import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.viewinterop.AndroidView import com.android.systemui.res.R @Composable fun InternetDetailsContent(viewModel: InternetDetailsViewModel) { val coroutineScope = rememberCoroutineScope() - val context = LocalContext.current - - val internetDetailsContentManager = remember { - viewModel.contentManagerFactory.create( - canConfigMobileData = viewModel.getCanConfigMobileData(), - canConfigWifi = viewModel.getCanConfigWifi(), - coroutineScope = coroutineScope, - context = context, - ) - } AndroidView( modifier = Modifier.fillMaxSize(), @@ -46,11 +34,11 @@ fun InternetDetailsContent(viewModel: InternetDetailsViewModel) { // Inflate with the existing dialog xml layout and bind it with the manager val view = LayoutInflater.from(context).inflate(R.layout.internet_connectivity_dialog, null) - internetDetailsContentManager.bind(view) + viewModel.internetDetailsContentManager.bind(view, coroutineScope) view // TODO: b/377388104 - Polish the internet details view UI }, - onRelease = { internetDetailsContentManager.unBind() }, + onRelease = { viewModel.internetDetailsContentManager.unBind() }, ) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailsContentManager.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailsContentManager.kt index 659488bdd0d3..d8e1755e6cca 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailsContentManager.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailsContentManager.kt @@ -43,6 +43,9 @@ import android.widget.Switch import android.widget.TextView import androidx.annotation.MainThread import androidx.annotation.WorkerThread +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleRegistry @@ -79,8 +82,6 @@ constructor( private val internetDetailsContentController: InternetDetailsContentController, @Assisted(CAN_CONFIG_MOBILE_DATA) private val canConfigMobileData: Boolean, @Assisted(CAN_CONFIG_WIFI) private val canConfigWifi: Boolean, - @Assisted private val coroutineScope: CoroutineScope, - @Assisted private var context: Context, private val uiEventLogger: UiEventLogger, @Main private val handler: Handler, @Background private val backgroundExecutor: Executor, @@ -121,26 +122,29 @@ constructor( private lateinit var shareWifiButton: Button private lateinit var airplaneModeButton: Button private var alertDialog: AlertDialog? = null - - private val canChangeWifiState = - WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(context) + private var canChangeWifiState = false private var wifiNetworkHeight = 0 private var backgroundOn: Drawable? = null private var backgroundOff: Drawable? = null private var clickJob: Job? = null private var defaultDataSubId = internetDetailsContentController.defaultDataSubscriptionId - @VisibleForTesting - internal var adapter = InternetAdapter(internetDetailsContentController, coroutineScope) + @VisibleForTesting internal lateinit var adapter: InternetAdapter @VisibleForTesting internal var wifiEntriesCount: Int = 0 @VisibleForTesting internal var hasMoreWifiEntries: Boolean = false + private lateinit var context: Context + private lateinit var coroutineScope: CoroutineScope + + var title by mutableStateOf("") + private set + + var subTitle by mutableStateOf("") + private set @AssistedFactory interface Factory { fun create( @Assisted(CAN_CONFIG_MOBILE_DATA) canConfigMobileData: Boolean, @Assisted(CAN_CONFIG_WIFI) canConfigWifi: Boolean, - coroutineScope: CoroutineScope, - context: Context, ): InternetDetailsContentManager } @@ -152,12 +156,16 @@ constructor( * * @param contentView The view to which the content manager should be bound. */ - fun bind(contentView: View) { + fun bind(contentView: View, coroutineScope: CoroutineScope) { if (DEBUG) { Log.d(TAG, "Bind InternetDetailsContentManager") } this.contentView = contentView + context = contentView.context + this.coroutineScope = coroutineScope + adapter = InternetAdapter(internetDetailsContentController, coroutineScope) + canChangeWifiState = WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(context) initializeLifecycle() initializeViews() @@ -323,11 +331,11 @@ constructor( } } - fun getTitleText(): String { + private fun getTitleText(): String { return internetDetailsContentController.getDialogTitleText().toString() } - fun getSubtitleText(): String { + private fun getSubtitleText(): String { return internetDetailsContentController.getSubtitleText(isProgressBarVisible).toString() } @@ -336,6 +344,13 @@ constructor( Log.d(TAG, "updateDetailsUI ") } + if (!::context.isInitialized) { + return + } + + title = getTitleText() + subTitle = getSubtitleText() + airplaneModeButton.visibility = if (internetContent.isAirplaneModeEnabled) View.VISIBLE else View.GONE diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailsViewModel.kt index 6709fd2bb508..fb63bea4fb9f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailsViewModel.kt @@ -28,38 +28,27 @@ class InternetDetailsViewModel @AssistedInject constructor( private val accessPointController: AccessPointController, - val contentManagerFactory: InternetDetailsContentManager.Factory, + private val contentManagerFactory: InternetDetailsContentManager.Factory, private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler, -) : TileDetailsViewModel() { - override fun clickOnSettingsButton() { - qsTileIntentUserActionHandler.handle( - /* expandable= */ null, - Intent(Settings.ACTION_WIFI_SETTINGS), +) : TileDetailsViewModel { + val internetDetailsContentManager by lazy { + contentManagerFactory.create( + canConfigMobileData = accessPointController.canConfigMobileData(), + canConfigWifi = accessPointController.canConfigWifi(), ) } - override fun getTitle(): String { - // TODO: b/377388104 make title and sub title mutable states of string - // by internetDetailsContentManager.getTitleText() - // TODO: test title change between airplane mode and not airplane mode - // TODO: b/377388104 Update the placeholder text - return "Internet" - } + override val title: String + get() = internetDetailsContentManager.title - override fun getSubTitle(): String { - // TODO: b/377388104 make title and sub title mutable states of string - // by internetDetailsContentManager.getSubtitleText() - // TODO: test subtitle change between airplane mode and not airplane mode - // TODO: b/377388104 Update the placeholder text - return "Tab a network to connect" - } + override val subTitle: String + get() = internetDetailsContentManager.subTitle - fun getCanConfigMobileData(): Boolean { - return accessPointController.canConfigMobileData() - } - - fun getCanConfigWifi(): Boolean { - return accessPointController.canConfigWifi() + override fun clickOnSettingsButton() { + qsTileIntentUserActionHandler.handle( + /* expandable= */ null, + Intent(Settings.ACTION_WIFI_SETTINGS), + ) } @AssistedFactory diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ModesDetailsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ModesDetailsViewModel.kt index 9a39c3c095ef..4f7e03bd3bc3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ModesDetailsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ModesDetailsViewModel.kt @@ -23,18 +23,14 @@ import com.android.systemui.statusbar.policy.ui.dialog.viewmodel.ModesDialogView class ModesDetailsViewModel( private val onSettingsClick: () -> Unit, val viewModel: ModesDialogViewModel, -) : TileDetailsViewModel() { +) : TileDetailsViewModel { override fun clickOnSettingsButton() { onSettingsClick() } - override fun getTitle(): String { - // TODO(b/388321032): Replace this string with a string in a translatable xml file. - return "Modes" - } + // TODO(b/388321032): Replace this string with a string in a translatable xml file. + override val title = "Modes" - override fun getSubTitle(): String { - // TODO(b/388321032): Replace this string with a string in a translatable xml file. - return "Silences interruptions from people and apps in different circumstances" - } + // TODO(b/388321032): Replace this string with a string in a translatable xml file. + override val subTitle = "Silences interruptions from people and apps in different circumstances" } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ScreenRecordDetailsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ScreenRecordDetailsViewModel.kt index c84ddb6fdb36..59f209edb546 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ScreenRecordDetailsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ScreenRecordDetailsViewModel.kt @@ -23,19 +23,15 @@ import com.android.systemui.screenrecord.RecordingController class ScreenRecordDetailsViewModel( val recordingController: RecordingController, val onStartRecordingClicked: Runnable, -) : TileDetailsViewModel() { +) : TileDetailsViewModel { override fun clickOnSettingsButton() { // No settings button in this tile. } - override fun getTitle(): String { - // TODO(b/388321032): Replace this string with a string in a translatable xml file, - return "Screen recording" - } + // TODO(b/388321032): Replace this string with a string in a translatable xml file, + override val title = "Screen recording" - override fun getSubTitle(): String { - // No sub-title in this tile. - return "" - } + // No sub-title in this tile. + override val subTitle = "" } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileDataInteractor.kt index 1544804c3291..38eb5947bd71 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileDataInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileDataInteractor.kt @@ -17,7 +17,7 @@ package com.android.systemui.qs.tiles.impl.flashlight.domain.interactor import android.os.UserHandle -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor import com.android.systemui.qs.tiles.impl.flashlight.domain.model.FlashlightTileModel diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesDndTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesDndTileDataInteractor.kt new file mode 100644 index 000000000000..b1ae3ba4381a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesDndTileDataInteractor.kt @@ -0,0 +1,73 @@ +/* + * 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.tiles.impl.modes.domain.interactor + +import android.content.Context +import android.os.UserHandle +import com.android.app.tracing.coroutines.flow.flowName +import com.android.settingslib.notification.modes.ZenMode +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.modes.shared.ModesUi +import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger +import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor +import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesDndTileModel +import com.android.systemui.shade.ShadeDisplayAware +import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map + +class ModesDndTileDataInteractor +@Inject +constructor( + @ShadeDisplayAware val context: Context, + val zenModeInteractor: ZenModeInteractor, + @Background val bgDispatcher: CoroutineDispatcher, +) : QSTileDataInteractor<ModesDndTileModel> { + + override fun tileData( + user: UserHandle, + triggers: Flow<DataUpdateTrigger>, + ): Flow<ModesDndTileModel> = tileData() + + /** + * An adapted version of the base class' [tileData] method for use in an old-style tile. + * + * TODO(b/299909989): Remove after the transition. + */ + fun tileData() = + zenModeInteractor.dndMode + .filterNotNull() + .map { dndMode -> buildTileData(dndMode) } + .flowName("tileData") + .flowOn(bgDispatcher) + .distinctUntilChanged() + + fun getCurrentTileModel() = buildTileData(zenModeInteractor.getDndMode()) + + private fun buildTileData(dndMode: ZenMode): ModesDndTileModel { + return ModesDndTileModel(isActivated = dndMode.isActive) + } + + override fun availability(user: UserHandle): Flow<Boolean> = + flowOf(ModesUi.isEnabled && android.app.Flags.modesUiDndTile()) +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesDndTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesDndTileUserActionInteractor.kt new file mode 100644 index 000000000000..e8fcea070ede --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesDndTileUserActionInteractor.kt @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2025 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.tiles.impl.modes.domain.interactor + +import android.content.Intent +import android.provider.Settings.ACTION_AUTOMATIC_ZEN_RULE_SETTINGS +import android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID +import android.util.Log +import com.android.systemui.animation.Expandable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.qs.shared.QSSettingsPackageRepository +import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler +import com.android.systemui.qs.tiles.base.interactor.QSTileInput +import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor +import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesDndTileModel +import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction +import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor +import com.android.systemui.statusbar.policy.ui.dialog.ModesDialogDelegate +import com.android.systemui.statusbar.policy.ui.dialog.ModesDialogEventLogger +import javax.inject.Inject +import kotlin.coroutines.CoroutineContext +import kotlinx.coroutines.withContext + +@SysUISingleton +class ModesDndTileUserActionInteractor +@Inject +constructor( + @Main private val mainContext: CoroutineContext, + private val qsTileIntentUserInputHandler: QSTileIntentUserInputHandler, + // TODO(b/353896370): The domain layer should not have to depend on the UI layer. + private val dialogDelegate: ModesDialogDelegate, + private val zenModeInteractor: ZenModeInteractor, + private val dialogEventLogger: ModesDialogEventLogger, + private val settingsPackageRepository: QSSettingsPackageRepository, +) : QSTileUserActionInteractor<ModesDndTileModel> { + + override suspend fun handleInput(input: QSTileInput<ModesDndTileModel>) { + with(input) { + when (action) { + is QSTileUserAction.Click, + is QSTileUserAction.ToggleClick -> { + handleClick() + } + is QSTileUserAction.LongClick -> { + handleLongClick(action.expandable) + } + } + } + } + + suspend fun handleClick() { + val dnd = zenModeInteractor.dndMode.value + if (dnd == null) { + Log.wtf(TAG, "No DND!?") + return + } + + if (!dnd.isActive) { + if (zenModeInteractor.shouldAskForZenDuration(dnd)) { + dialogEventLogger.logOpenDurationDialog(dnd) + withContext(mainContext) { + // NOTE: The dialog handles turning on the mode itself. + val dialog = dialogDelegate.makeDndDurationDialog() + dialog.show() + } + } else { + dialogEventLogger.logModeOn(dnd) + zenModeInteractor.activateMode(dnd) + } + } else { + dialogEventLogger.logModeOff(dnd) + zenModeInteractor.deactivateMode(dnd) + } + } + + private fun handleLongClick(expandable: Expandable?) { + val intent = getSettingsIntent() + if (intent != null) { + qsTileIntentUserInputHandler.handle(expandable, intent) + } + } + + fun getSettingsIntent(): Intent? { + val dnd = zenModeInteractor.dndMode.value + if (dnd == null) { + Log.wtf(TAG, "No DND!?") + return null + } + + return Intent(ACTION_AUTOMATIC_ZEN_RULE_SETTINGS) + .putExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID, dnd.id) + .setPackage(settingsPackageRepository.getSettingsPackageName()) + } + + companion object { + const val TAG = "ModesDndTileUserActionInteractor" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesDndTileModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesDndTileModel.kt new file mode 100644 index 000000000000..eab798897aa3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesDndTileModel.kt @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2025 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.tiles.impl.modes.domain.model + +data class ModesDndTileModel(val isActivated: Boolean) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesDndTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesDndTileMapper.kt new file mode 100644 index 000000000000..4869b6f74554 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesDndTileMapper.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2025 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.tiles.impl.modes.ui + +import android.content.res.Resources +import android.widget.Switch +import com.android.systemui.common.shared.model.Icon +import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper +import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesDndTileModel +import com.android.systemui.qs.tiles.viewmodel.QSTileConfig +import com.android.systemui.qs.tiles.viewmodel.QSTileState +import com.android.systemui.res.R +import com.android.systemui.shade.ShadeDisplayAware +import javax.inject.Inject + +class ModesDndTileMapper +@Inject +constructor(@ShadeDisplayAware private val resources: Resources, val theme: Resources.Theme) : + QSTileDataToStateMapper<ModesDndTileModel> { + override fun map(config: QSTileConfig, data: ModesDndTileModel): QSTileState = + QSTileState.build(resources, theme, config.uiConfig) { + val iconResource = + if (data.isActivated) R.drawable.qs_dnd_icon_on else R.drawable.qs_dnd_icon_off + icon = + Icon.Loaded( + resources.getDrawable(iconResource, theme), + res = iconResource, + contentDescription = null, + ) + + activationState = + if (data.isActivated) { + QSTileState.ActivationState.ACTIVE + } else { + QSTileState.ActivationState.INACTIVE + } + label = resources.getString(R.string.quick_settings_dnd_label) + secondaryLabel = + resources.getString( + if (data.isActivated) R.string.zen_mode_on else R.string.zen_mode_off + ) + contentDescription = label + supportedActions = + setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK) + expandedAccessibilityClass = Switch::class + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/sensorprivacy/SensorPrivacyToggleTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/sensorprivacy/SensorPrivacyToggleTileDataInteractor.kt index 7117629622e6..a8e9c5663f39 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/sensorprivacy/SensorPrivacyToggleTileDataInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/sensorprivacy/SensorPrivacyToggleTileDataInteractor.kt @@ -22,7 +22,7 @@ import android.hardware.SensorPrivacyManager.Sensors.Sensor import android.os.UserHandle import android.provider.DeviceConfig import android.util.Log -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt index 7bb831baec20..3ad0867192d3 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt @@ -33,7 +33,7 @@ import com.android.systemui.bouncer.domain.interactor.SimBouncerInteractor import com.android.systemui.bouncer.shared.logging.BouncerUiEvent import com.android.systemui.classifier.FalsingCollector import com.android.systemui.classifier.FalsingCollectorActual -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.DisplayId diff --git a/packages/SystemUI/src/com/android/systemui/security/data/repository/SecurityRepository.kt b/packages/SystemUI/src/com/android/systemui/security/data/repository/SecurityRepository.kt index 7e967f436ecb..0b039fecc19e 100644 --- a/packages/SystemUI/src/com/android/systemui/security/data/repository/SecurityRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/security/data/repository/SecurityRepository.kt @@ -17,7 +17,7 @@ package com.android.systemui.security.data.repository import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.security.data.model.SecurityModel diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt index 3be2f1b7b957..362b5db012e1 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt @@ -17,6 +17,7 @@ package com.android.systemui.shade import android.content.Context +import android.content.res.Configuration import android.graphics.Rect import android.os.PowerManager import android.os.SystemClock @@ -25,11 +26,13 @@ import android.view.GestureDetector import android.view.MotionEvent import android.view.View import android.view.ViewGroup +import android.view.WindowInsets import android.widget.FrameLayout import androidx.activity.OnBackPressedDispatcher import androidx.activity.OnBackPressedDispatcherOwner import androidx.activity.setViewTreeOnBackPressedDispatcherOwner import androidx.compose.ui.platform.ComposeView +import androidx.core.view.updateMargins import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.LifecycleObserver @@ -101,7 +104,10 @@ constructor( ) : LifecycleOwner { private val logger = Logger(logBuffer, TAG) - private class CommunalWrapper(context: Context) : FrameLayout(context) { + private class CommunalWrapper( + context: Context, + private val communalSettingsInteractor: CommunalSettingsInteractor, + ) : FrameLayout(context) { private val consumers: MutableSet<Consumer<Boolean>> = ArraySet() override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) { @@ -121,6 +127,24 @@ constructor( consumers.clear() } } + + override fun onApplyWindowInsets(windowInsets: WindowInsets): WindowInsets { + if ( + !communalSettingsInteractor.isV2FlagEnabled() || + resources.configuration.orientation != Configuration.ORIENTATION_LANDSCAPE + ) { + return super.onApplyWindowInsets(windowInsets) + } + val type = WindowInsets.Type.displayCutout() + val insets = windowInsets.getInsets(type) + + // Reset horizontal margins added by window insets, so hub can be edge to edge. + if (insets.left > 0 || insets.right > 0) { + val lp = layoutParams as LayoutParams + lp.updateMargins(0, lp.topMargin, 0, lp.bottomMargin) + } + return WindowInsets.CONSUMED + } } /** The container view for the hub. This will not be initialized until [initView] is called. */ @@ -443,7 +467,8 @@ constructor( collectFlow(containerView, keyguardInteractor.isDreaming, { isDreaming = it }) collectFlow(containerView, communalViewModel.swipeToHubEnabled, { swipeToHubEnabled = it }) - communalContainerWrapper = CommunalWrapper(containerView.context) + communalContainerWrapper = + CommunalWrapper(containerView.context, communalSettingsInteractor) communalContainerWrapper?.addView(communalContainerView) logger.d("Hub container initialized") return communalContainerWrapper!! diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java index fa17b4fad592..8d7cc922c38b 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java @@ -498,17 +498,18 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW } private boolean isExpanded(NotificationShadeWindowState state) { + boolean visForBlur = !Flags.disableBlurredShadeVisible() && state.backgroundBlurRadius > 0; boolean isExpanded = !state.forceWindowCollapsed && (state.isKeyguardShowingAndNotOccluded() || state.panelVisible || state.keyguardFadingAway || state.bouncerShowing || state.headsUpNotificationShowing || state.scrimsVisibility != ScrimController.TRANSPARENT) - || state.backgroundBlurRadius > 0 + || visForBlur || state.launchingActivityFromNotification; mLogger.logIsExpanded(isExpanded, state.forceWindowCollapsed, state.isKeyguardShowingAndNotOccluded(), state.panelVisible, state.keyguardFadingAway, state.bouncerShowing, state.headsUpNotificationShowing, state.scrimsVisibility != ScrimController.TRANSPARENT, - state.backgroundBlurRadius > 0, state.launchingActivityFromNotification); + visForBlur, state.launchingActivityFromNotification); return isExpanded; } diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/PrivacyChipRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/PrivacyChipRepository.kt index 91c92cc8cd2f..ce74cb7d54d2 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/PrivacyChipRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/PrivacyChipRepository.kt @@ -20,7 +20,7 @@ import android.content.IntentFilter import android.os.UserHandle import android.safetycenter.SafetyCenterManager import com.android.systemui.broadcast.BroadcastDispatcher -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 657c86b10f16..e66b21866902 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -1088,14 +1088,18 @@ public class KeyguardIndicationController { if (!TextUtils.equals(mTopIndicationView.getText(), newIndication)) { mWakeLock.setAcquired(true); + final KeyguardIndication.Builder builder = new KeyguardIndication.Builder() + .setMessage(newIndication) + .setTextColor(ColorStateList.valueOf( + useMisalignmentColor + ? mContext.getColor(R.color.misalignment_text_color) + : Color.WHITE)); + if (mBiometricMessage != null && newIndication == mBiometricMessage) { + builder.setForceAccessibilityLiveRegionAssertive(); + } + mTopIndicationView.switchIndication(newIndication, - new KeyguardIndication.Builder() - .setMessage(newIndication) - .setTextColor(ColorStateList.valueOf( - useMisalignmentColor - ? mContext.getColor(R.color.misalignment_text_color) - : Color.WHITE)) - .build(), + builder.build(), true, () -> mWakeLock.setAcquired(false)); } return; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java index 3180a06ae787..fdcd39d1d616 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java @@ -34,7 +34,7 @@ public interface NotificationLockscreenUserManager { value = { REDACTION_TYPE_NONE, REDACTION_TYPE_PUBLIC, - REDACTION_TYPE_SENSITIVE_CONTENT}) + REDACTION_TYPE_OTP}) @interface RedactionType {} /** @@ -52,7 +52,7 @@ public interface NotificationLockscreenUserManager { * Indicates that a notification should have its main content redacted, due to detected * sensitive content, such as a One-Time Password */ - int REDACTION_TYPE_SENSITIVE_CONTENT = 1 << 1; + int REDACTION_TYPE_OTP = 1 << 1; /** * @param userId user Id diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index ec04edb0f810..339f898be251 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -795,7 +795,7 @@ public class NotificationLockscreenUserManagerImpl implements } if (shouldShowSensitiveContentRedactedView(ent)) { - return REDACTION_TYPE_SENSITIVE_CONTENT; + return REDACTION_TYPE_OTP; } return REDACTION_TYPE_NONE; } @@ -920,7 +920,7 @@ public class NotificationLockscreenUserManagerImpl implements // notification's "when" time, or the notification entry creation time private long getEarliestNotificationTime(NotificationEntry notif) { long notifWhenWallClock = notif.getSbn().getNotification().getWhen(); - long creationTimeDelta = SystemClock.elapsedRealtime() - notif.getCreationTime(); + long creationTimeDelta = SystemClock.uptimeMillis() - notif.getCreationTime(); long creationTimeWallClock = System.currentTimeMillis() - creationTimeDelta; return Math.min(notifWhenWallClock, creationTimeWallClock); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java index 0d34bdc7e477..041ed6504634 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java @@ -59,11 +59,13 @@ import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.statusbar.dagger.CentralSurfacesDependenciesModule; import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.RemoteInputControllerLogger; +import com.android.systemui.statusbar.notification.collection.EntryAdapter; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import com.android.systemui.statusbar.phone.ExpandHeadsUpOnInlineReply; import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.statusbar.policy.RemoteInputView; @@ -134,20 +136,21 @@ public class NotificationRemoteInputManager implements CoreStartable { view.getTag(com.android.internal.R.id.notification_action_index_tag); final ExpandableNotificationRow row = getNotificationRowForParent(view.getParent()); - final NotificationEntry entry = getNotificationForParent(view.getParent()); - mLogger.logInitialClick( - row != null ? row.getLoggingKey() : null, actionIndex, pendingIntent); + if (row == null) { + return false; + } + mLogger.logInitialClick(row.getLoggingKey(), actionIndex, pendingIntent); if (handleRemoteInput(view, pendingIntent)) { - mLogger.logRemoteInputWasHandled( - row != null ? row.getLoggingKey() : null, actionIndex); + mLogger.logRemoteInputWasHandled(row.getLoggingKey(), actionIndex); return true; } if (DEBUG) { Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent); } - logActionClick(view, entry, pendingIntent); + Notification.Action action = getActionFromView(view, row, pendingIntent); + logActionClick(view, row.getKey(), action); // The intent we are sending is for the application, which // won't have permission to immediately start an activity after // the user switches to home. We know it is safe to do at this @@ -156,33 +159,47 @@ public class NotificationRemoteInputManager implements CoreStartable { ActivityManager.getService().resumeAppSwitches(); } catch (RemoteException e) { } - Notification.Action action = getActionFromView(view, entry, pendingIntent); return mCallback.handleRemoteViewClick(view, pendingIntent, action == null ? false : action.isAuthenticationRequired(), actionIndex, () -> { Pair<Intent, ActivityOptions> options = response.getLaunchOptions(view); mLogger.logStartingIntentWithDefaultHandler( - row != null ? row.getLoggingKey() : null, pendingIntent, actionIndex); + row.getLoggingKey(), pendingIntent, actionIndex); boolean started = RemoteViews.startPendingIntent(view, pendingIntent, options); - if (started) releaseNotificationIfKeptForRemoteInputHistory(entry); + if (started) { + if (NotificationBundleUi.isEnabled()) { + releaseNotificationIfKeptForRemoteInputHistory(row.getEntryAdapter()); + } else { + releaseNotificationIfKeptForRemoteInputHistory(row.getEntry()); + } + } return started; }); } private @Nullable Notification.Action getActionFromView(View view, - NotificationEntry entry, PendingIntent actionIntent) { + ExpandableNotificationRow row, PendingIntent actionIntent) { Integer actionIndex = (Integer) view.getTag(com.android.internal.R.id.notification_action_index_tag); if (actionIndex == null) { return null; } - if (entry == null) { + StatusBarNotification statusBarNotification = null; + if (NotificationBundleUi.isEnabled()) { + if (row.getEntryAdapter() != null) { + statusBarNotification = row.getEntryAdapter().getSbn(); + } + } else { + if (row.getEntry() != null) { + statusBarNotification = row.getEntry().getSbn(); + } + } + if (statusBarNotification == null) { Log.w(TAG, "Couldn't determine notification for click."); return null; } // Notification may be updated before this function is executed, and thus play safe // here and verify that the action object is still the one that where the click happens. - StatusBarNotification statusBarNotification = entry.getSbn(); Notification.Action[] actions = statusBarNotification.getNotification().actions; if (actions == null || actionIndex >= actions.length) { Log.w(TAG, "statusBarNotification.getNotification().actions is null or invalid"); @@ -199,14 +216,12 @@ public class NotificationRemoteInputManager implements CoreStartable { private void logActionClick( View view, - NotificationEntry entry, - PendingIntent actionIntent) { - Notification.Action action = getActionFromView(view, entry, actionIntent); + String key, + Notification.Action action) { if (action == null) { return; } ViewParent parent = view.getParent(); - String key = entry.getSbn().getKey(); int buttonIndex = -1; // If this is a default template, determine the index of the button. if (view.getId() == com.android.internal.R.id.action0 && @@ -214,20 +229,10 @@ public class NotificationRemoteInputManager implements CoreStartable { ViewGroup actionGroup = (ViewGroup) parent; buttonIndex = actionGroup.indexOfChild(view); } - final NotificationVisibility nv = mVisibilityProvider.obtain(entry, true); + final NotificationVisibility nv = mVisibilityProvider.obtain(key, true); mClickNotifier.onNotificationActionClick(key, buttonIndex, action, nv, false); } - private NotificationEntry getNotificationForParent(ViewParent parent) { - while (parent != null) { - if (parent instanceof ExpandableNotificationRow) { - return ((ExpandableNotificationRow) parent).getEntry(); - } - parent = parent.getParent(); - } - return null; - } - private @Nullable ExpandableNotificationRow getNotificationRowForParent(ViewParent parent) { while (parent != null) { if (parent instanceof ExpandableNotificationRow) { @@ -394,11 +399,21 @@ public class NotificationRemoteInputManager implements CoreStartable { } } + /** + * Use {@link com.android.systemui.statusbar.notification.row.NotificationActionClickManager} + * instead + */ public void addActionPressListener(Consumer<NotificationEntry> listener) { + NotificationBundleUi.assertInLegacyMode(); mActionPressListeners.addIfAbsent(listener); } + /** + * Use {@link com.android.systemui.statusbar.notification.row.NotificationActionClickManager} + * instead + */ public void removeActionPressListener(Consumer<NotificationEntry> listener) { + NotificationBundleUi.assertInLegacyMode(); mActionPressListeners.remove(listener); } @@ -681,12 +696,30 @@ public class NotificationRemoteInputManager implements CoreStartable { * (after unlock, if applicable), and will then wait a short time to allow the app to update the * notification in response to the action. */ + private void releaseNotificationIfKeptForRemoteInputHistory(EntryAdapter entryAdapter) { + if (entryAdapter == null) { + return; + } + if (mRemoteInputListener != null) { + mRemoteInputListener.releaseNotificationIfKeptForRemoteInputHistory( + entryAdapter.getKey()); + } + entryAdapter.onNotificationActionClicked(); + } + + /** + * Checks if the notification is being kept due to the user sending an inline reply, and if + * so, releases that hold. This is called anytime an action on the notification is dispatched + * (after unlock, if applicable), and will then wait a short time to allow the app to update the + * notification in response to the action. + */ private void releaseNotificationIfKeptForRemoteInputHistory(NotificationEntry entry) { + NotificationBundleUi.assertInLegacyMode(); if (entry == null) { return; } if (mRemoteInputListener != null) { - mRemoteInputListener.releaseNotificationIfKeptForRemoteInputHistory(entry); + mRemoteInputListener.releaseNotificationIfKeptForRemoteInputHistory(entry.getKey()); } for (Consumer<NotificationEntry> listener : mActionPressListeners) { listener.accept(entry); @@ -866,7 +899,7 @@ public class NotificationRemoteInputManager implements CoreStartable { boolean isNotificationKeptForRemoteInputHistory(@NonNull String key); /** Called on user interaction to end lifetime extension for history */ - void releaseNotificationIfKeptForRemoteInputHistory(@NonNull NotificationEntry entry); + void releaseNotificationIfKeptForRemoteInputHistory(@NonNull String entryKey); /** Called when the RemoteInputController is attached to the manager */ void setRemoteInputController(@NonNull RemoteInputController remoteInputController); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt index bdfdb8191356..2e83910a2a93 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt @@ -38,13 +38,13 @@ import com.android.systemui.Flags import com.android.systemui.Flags.spatialModelAppPushback import com.android.systemui.animation.ShadeInterpolation import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.shade.ShadeExpansionChangeEvent import com.android.systemui.shade.ShadeExpansionListener -import com.android.systemui.shared.Flags.ambientAod import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK import com.android.systemui.statusbar.phone.DozeParameters @@ -53,6 +53,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.policy.SplitShadeStateController import com.android.systemui.util.WallpaperController +import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor import com.android.systemui.window.domain.interactor.WindowRootViewBlurInteractor import com.android.wm.shell.appzoomout.AppZoomOut import java.io.PrintWriter @@ -78,12 +79,14 @@ constructor( private val keyguardInteractor: KeyguardInteractor, private val choreographer: Choreographer, private val wallpaperController: WallpaperController, + private val wallpaperInteractor: WallpaperInteractor, private val notificationShadeWindowController: NotificationShadeWindowController, private val dozeParameters: DozeParameters, @ShadeDisplayAware private val context: Context, private val splitShadeStateController: SplitShadeStateController, private val windowRootViewBlurInteractor: WindowRootViewBlurInteractor, private val appZoomOutOptional: Optional<AppZoomOut>, + @Application private val applicationScope: CoroutineScope, dumpManager: DumpManager, configurationController: ConfigurationController, ) : ShadeExpansionListener, Dumpable { @@ -113,6 +116,8 @@ constructor( private var prevTimestamp: Long = -1 private var prevShadeDirection = 0 private var prevShadeVelocity = 0f + private var prevDozeAmount: Float = 0f + @VisibleForTesting var wallpaperSupportsAmbientMode: Boolean = false // tracks whether app launch transition is in progress. This involves two independent factors // that control blur, shade expansion and app launch animation from outside sysui. // They can complete out of order, this flag will be reset by the animation that finishes later. @@ -228,8 +233,10 @@ constructor( scheduleUpdate() } - /** Blur radius of the wake-up animation on this frame. */ - private var wakeAndUnlockBlurRadius = 0f + private data class WakeAndUnlockBlurData(val radius: Float, val useZoom: Boolean = true) + + /** Blur radius of the wake and unlock animation on this frame, and whether to zoom out. */ + private var wakeAndUnlockBlurData = WakeAndUnlockBlurData(0f) set(value) { if (field == value) return field = value @@ -256,14 +263,18 @@ constructor( ShadeInterpolation.getNotificationScrimAlpha(qsPanelExpansion) * shadeExpansion combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsExpandedRatio)) combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(transitionToFullShadeProgress)) - var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius) + var shadeRadius = max(combinedBlur, wakeAndUnlockBlurData.radius) if (areBlursDisabledForAppLaunch || blursDisabledForUnlock) { shadeRadius = 0f } var blur = shadeRadius.toInt() - val zoomOut = blurRadiusToZoomOut(blurRadius = shadeRadius) + // If the blur comes from waking up, we don't want to zoom out the background + val zoomOut = + if (shadeRadius != wakeAndUnlockBlurData.radius|| wakeAndUnlockBlurData.useZoom) + blurRadiusToZoomOut(blurRadius = shadeRadius) + else 0f // Make blur be 0 if it is necessary to stop blur effect. if (scrimsVisible) { if (!Flags.notificationShadeBlur()) { @@ -348,14 +359,14 @@ constructor( startDelay = keyguardStateController.keyguardFadingAwayDelay interpolator = Interpolators.FAST_OUT_SLOW_IN addUpdateListener { animation: ValueAnimator -> - wakeAndUnlockBlurRadius = - blurUtils.blurRadiusOfRatio(animation.animatedValue as Float) + wakeAndUnlockBlurData = + WakeAndUnlockBlurData(blurUtils.blurRadiusOfRatio(animation.animatedValue as Float)) } addListener( object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { keyguardAnimator = null - wakeAndUnlockBlurRadius = 0f + wakeAndUnlockBlurData = WakeAndUnlockBlurData(0f) } } ) @@ -391,15 +402,23 @@ constructor( } override fun onDozeAmountChanged(linear: Float, eased: Float) { - wakeAndUnlockBlurRadius = - if (ambientAod()) { - 0f - } else { - blurUtils.blurRadiusOfRatio(eased) - } + prevDozeAmount = eased + updateWakeBlurRadius(prevDozeAmount) } } + private fun updateWakeBlurRadius(ratio: Float) { + wakeAndUnlockBlurData = WakeAndUnlockBlurData(getNewWakeBlurRadius(ratio), false) + } + + private fun getNewWakeBlurRadius(ratio: Float): Float { + return if (!wallpaperSupportsAmbientMode) { + 0f + } else { + blurUtils.blurRadiusOfRatio(ratio) + } + } + init { dumpManager.registerCriticalDumpable(javaClass.name, this) if (WAKE_UP_ANIMATION_ENABLED) { @@ -421,6 +440,16 @@ constructor( } } ) + applicationScope.launch { + wallpaperInteractor.wallpaperSupportsAmbientMode.collect { supported -> + wallpaperSupportsAmbientMode = supported + if (getNewWakeBlurRadius(prevDozeAmount) == wakeAndUnlockBlurData.radius + && !wakeAndUnlockBlurData.useZoom) { + // Update wake and unlock radius only if the previous value comes from wake-up. + updateWakeBlurRadius(prevDozeAmount) + } + } + } initBlurListeners() } @@ -611,7 +640,8 @@ constructor( it.println("shouldApplyShadeBlur: ${shouldApplyShadeBlur()}") it.println("shadeAnimation: ${shadeAnimation.radius}") it.println("brightnessMirrorRadius: ${brightnessMirrorSpring.radius}") - it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius") + it.println("wakeAndUnlockBlurRadius: ${wakeAndUnlockBlurData.radius}") + it.println("wakeAndUnlockBlurUsesZoom: ${wakeAndUnlockBlurData.useZoom}") it.println("blursDisabledForAppLaunch: $blursDisabledForAppLaunch") it.println("appLaunchTransitionIsInProgress: $appLaunchTransitionIsInProgress") it.println("qsPanelExpansion: $qsPanelExpansion") diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS index b2764e1a2302..6cebcd98a0ba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS +++ b/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS @@ -24,6 +24,8 @@ per-file *Blur* = set noparent per-file *Blur* = shanh@google.com, rahulbanerjee@google.com # Not setting noparent here, since *Mode* matches many other classes (e.g., *ViewModel*) per-file *Mode* = file:notification/OWNERS +per-file *SmartReply* = set noparent +per-file *SmartReply* = file:notification/OWNERS per-file *RemoteInput* = set noparent per-file *RemoteInput* = file:notification/OWNERS per-file *EmptyShadeView* = set noparent diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerExt.kt b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerExt.kt index 6148b407d3bf..8fc95092be10 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerExt.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerExt.kt @@ -16,7 +16,7 @@ package com.android.systemui.statusbar -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.plugins.statusbar.StatusBarStateController import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt index aeeb0427d24b..e91e9777d48e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt @@ -14,7 +14,7 @@ package com.android.systemui.statusbar.disableflags.data.repository -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.DisplayId diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java index 4d68f2e6ef1b..f6535730cf77 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java @@ -33,7 +33,8 @@ import androidx.annotation.VisibleForTesting; import com.android.systemui.statusbar.notification.icon.IconPack; import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; - +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import kotlinx.coroutines.flow.MutableStateFlow; @@ -51,10 +52,27 @@ public class BundleEntry extends PipelineEntry { // TODO (b/389839319): implement the row private ExpandableNotificationRow mRow; + private final List<ListEntry> mChildren = new ArrayList<>(); + + private final List<ListEntry> mUnmodifiableChildren = Collections.unmodifiableList(mChildren); + public BundleEntry(String key) { super(key); } + void addChild(ListEntry child) { + mChildren.add(child); + } + + @NonNull + public List<ListEntry> getChildren() { + return mUnmodifiableChildren; + } + + /** + * @return Null because bundles do not have an associated NotificationEntry. + */ + @Nullable @Override public NotificationEntry getRepresentativeEntry() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapter.kt index 64db9df8270c..26c302bf6409 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapter.kt @@ -20,6 +20,7 @@ import android.app.Notification import android.content.Context import android.os.Build import android.service.notification.StatusBarNotification +import android.util.Log import com.android.systemui.statusbar.notification.icon.IconPack import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import kotlinx.coroutines.flow.StateFlow @@ -118,5 +119,13 @@ class BundleEntryAdapter(val entry: BundleEntry) : EntryAdapter { override fun onNotificationBubbleIconClicked() { // do nothing. these cannot be a bubble + Log.wtf(TAG, "onNotificationBubbleIconClicked() called") + } + + override fun onNotificationActionClicked() { + // do nothing. these have no actions + Log.wtf(TAG, "onNotificationActionClicked() called") } } + +private const val TAG = "BundleEntryAdapter" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java index 0e75b6050678..3118ce56ac69 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java @@ -140,5 +140,10 @@ public interface EntryAdapter { * Process a click on a notification bubble icon */ void onNotificationBubbleIconClicked(); + + /** + * Processes a click on a notification action + */ + void onNotificationActionClicked(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactoryImpl.kt index 779c25a3b402..a5169865c3c9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactoryImpl.kt @@ -16,11 +16,11 @@ package com.android.systemui.statusbar.notification.collection -import androidx.annotation.VisibleForTesting import com.android.internal.logging.MetricsLogger import com.android.systemui.statusbar.notification.NotificationActivityStarter import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier +import com.android.systemui.statusbar.notification.row.NotificationActionClickManager import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider import javax.inject.Inject @@ -33,6 +33,7 @@ constructor( private val peopleNotificationIdentifier: PeopleNotificationIdentifier, private val iconStyleProvider: NotificationIconStyleProvider, private val visualStabilityCoordinator: VisualStabilityCoordinator, + private val notificationActionClickManager: NotificationActionClickManager, ) : EntryAdapterFactory { override fun create(entry: PipelineEntry): EntryAdapter { return if (entry is NotificationEntry) { @@ -42,15 +43,11 @@ constructor( peopleNotificationIdentifier, iconStyleProvider, visualStabilityCoordinator, + notificationActionClickManager, entry, ) } else { BundleEntryAdapter((entry as BundleEntry)) } } - - @VisibleForTesting - fun getNotificationActivityStarter() : NotificationActivityStarter { - return notificationActivityStarter - } } 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 3d8ba7f335bd..d031d831bf5a 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 @@ -29,8 +29,6 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICAT import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; -import static com.android.systemui.statusbar.notification.collection.BundleEntry.ROOT_BUNDLES; -import static com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY; import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED; import static java.util.Objects.requireNonNull; @@ -41,7 +39,6 @@ import android.app.Notification; import android.app.Notification.MessagingStyle.Message; import android.app.NotificationChannel; import android.app.NotificationManager.Policy; -import android.app.PendingIntent; import android.app.Person; import android.app.RemoteInput; import android.app.RemoteInputHistoryItem; @@ -68,7 +65,6 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; -import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.headsup.PinnedStatus; import com.android.systemui.statusbar.notification.icon.IconPack; import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel; @@ -81,14 +77,14 @@ import com.android.systemui.statusbar.notification.row.shared.NotificationRowCon import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import com.android.systemui.util.ListenerSet; -import kotlinx.coroutines.flow.MutableStateFlow; -import kotlinx.coroutines.flow.StateFlow; -import kotlinx.coroutines.flow.StateFlowKt; - import java.util.ArrayList; import java.util.List; import java.util.Objects; +import kotlinx.coroutines.flow.MutableStateFlow; +import kotlinx.coroutines.flow.StateFlow; +import kotlinx.coroutines.flow.StateFlowKt; + /** * Represents a notification that the system UI knows about * @@ -497,7 +493,8 @@ public final class NotificationEntry extends ListEntry { public @Nullable List<NotificationEntry> getAttachedNotifChildren() { if (NotificationBundleUi.isEnabled()) { if (isGroupSummary()) { - return ((GroupEntry) getParent()).getChildren(); + GroupEntry parent = (GroupEntry) getParent(); + return parent != null ? new ArrayList<>(parent.getChildren()) : null; } } else { if (row == null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapter.kt index 0ff2dd7c7f43..1168c647c26a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapter.kt @@ -24,6 +24,7 @@ import com.android.systemui.statusbar.notification.collection.coordinator.Visual import com.android.systemui.statusbar.notification.icon.IconPack import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow +import com.android.systemui.statusbar.notification.row.NotificationActionClickManager import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider import kotlinx.coroutines.flow.StateFlow @@ -33,6 +34,7 @@ class NotificationEntryAdapter( private val peopleNotificationIdentifier: PeopleNotificationIdentifier, private val iconStyleProvider: NotificationIconStyleProvider, private val visualStabilityCoordinator: VisualStabilityCoordinator, + private val notificationActionClickManager: NotificationActionClickManager, private val entry: NotificationEntry, ) : EntryAdapter { @@ -142,4 +144,8 @@ class NotificationEntryAdapter( override fun onNotificationBubbleIconClicked() { notificationActivityStarter.onNotificationBubbleIconClicked(entry) } + + override fun onNotificationActionClicked() { + notificationActionClickManager.onNotificationActionClicked(entry) + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt index 5d981b34edd3..a0eab43f854b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt @@ -48,7 +48,9 @@ import com.android.systemui.statusbar.notification.headsup.PinnedStatus import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider import com.android.systemui.statusbar.notification.logKey +import com.android.systemui.statusbar.notification.row.NotificationActionClickManager import com.android.systemui.statusbar.notification.shared.GroupHunAnimationFix +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi import com.android.systemui.statusbar.notification.stack.BUCKET_HEADS_UP import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.time.SystemClock @@ -83,6 +85,7 @@ constructor( private val mHeadsUpViewBinder: HeadsUpViewBinder, private val mVisualInterruptionDecisionProvider: VisualInterruptionDecisionProvider, private val mRemoteInputManager: NotificationRemoteInputManager, + private val notificationActionClickManager: NotificationActionClickManager, private val mLaunchFullScreenIntentProvider: LaunchFullScreenIntentProvider, private val mFlags: NotifPipelineFlags, private val statusBarNotificationChipsInteractor: StatusBarNotificationChipsInteractor, @@ -108,7 +111,11 @@ constructor( pipeline.addOnBeforeFinalizeFilterListener(::onBeforeFinalizeFilter) pipeline.addPromoter(mNotifPromoter) pipeline.addNotificationLifetimeExtender(mLifetimeExtender) - mRemoteInputManager.addActionPressListener(mActionPressListener) + if (NotificationBundleUi.isEnabled) { + notificationActionClickManager.addActionClickListener(mActionPressListener) + } else { + mRemoteInputManager.addActionPressListener(mActionPressListener) + } if (StatusBarNotifChips.isEnabled) { applicationScope.launch { @@ -783,7 +790,7 @@ constructor( */ private val mActionPressListener = Consumer<NotificationEntry> { entry -> - mHeadsUpManager.setUserActionMayIndirectlyRemove(entry) + mHeadsUpManager.setUserActionMayIndirectlyRemove(entry.key) mExecutor.execute { endNotifLifetimeExtensionIfExtended(entry) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java index 3fad8f0510a1..cda535de86c4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java @@ -16,10 +16,13 @@ package com.android.systemui.statusbar.notification.collection.coordinator; +import static android.app.NotificationChannel.SYSTEM_RESERVED_IDS; + import android.annotation.NonNull; import android.annotation.Nullable; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.notification.collection.BundleEntry; import com.android.systemui.statusbar.notification.collection.PipelineEntry; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -98,7 +101,11 @@ public class RankingCoordinator implements Coordinator { NotificationPriorityBucketKt.BUCKET_ALERTING) { @Override public boolean isInSection(PipelineEntry entry) { - return mHighPriorityProvider.isHighPriority(entry); + return mHighPriorityProvider.isHighPriority(entry) + && entry.getRepresentativeEntry() != null + && entry.getRepresentativeEntry().getChannel() != null + && !SYSTEM_RESERVED_IDS.contains( + entry.getRepresentativeEntry().getChannel().getId()); } @Nullable @@ -116,6 +123,9 @@ public class RankingCoordinator implements Coordinator { NotificationPriorityBucketKt.BUCKET_SILENT) { @Override public boolean isInSection(PipelineEntry entry) { + if (entry instanceof BundleEntry) { + return true; + } return !mHighPriorityProvider.isHighPriority(entry) && entry.getRepresentativeEntry() != null && !entry.getRepresentativeEntry().isAmbient(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinator.kt index e7c767f42c12..27c0dcccfe43 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinator.kt @@ -221,20 +221,20 @@ constructor( mSmartReplyHistoryExtender.isExtending(key) } else false - override fun releaseNotificationIfKeptForRemoteInputHistory(entry: NotificationEntry) { - if (DEBUG) Log.d(TAG, "releaseNotificationIfKeptForRemoteInputHistory(entry=${entry.key})") + override fun releaseNotificationIfKeptForRemoteInputHistory(entryKey: String) { + if (DEBUG) Log.d(TAG, "releaseNotificationIfKeptForRemoteInputHistory(entry=${entryKey})") if (!lifetimeExtensionRefactor()) { mRemoteInputHistoryExtender.endLifetimeExtensionAfterDelay( - entry.key, + entryKey, REMOTE_INPUT_EXTENDER_RELEASE_DELAY, ) mSmartReplyHistoryExtender.endLifetimeExtensionAfterDelay( - entry.key, + entryKey, REMOTE_INPUT_EXTENDER_RELEASE_DELAY, ) } mRemoteInputActiveExtender.endLifetimeExtensionAfterDelay( - entry.key, + entryKey, REMOTE_INPUT_EXTENDER_RELEASE_DELAY, ) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java index c2f0806a9cd6..6b32c6a18ec0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.notification.collection.inflation; import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_NONE; -import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_SENSITIVE_CONTENT; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC; @@ -276,7 +275,7 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { if (LockscreenOtpRedaction.isSingleLineViewEnabled()) { if (inflaterParams.isChildInGroup() - && redactionType == REDACTION_TYPE_SENSITIVE_CONTENT) { + && redactionType != REDACTION_TYPE_NONE) { params.requireContentViews(FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE); } else { params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index ef3da9498f70..1e5aa01714be 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -83,6 +83,7 @@ import com.android.systemui.statusbar.notification.logging.dagger.NotificationsL import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor; import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractorImpl; import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel; +import com.android.systemui.statusbar.notification.row.NotificationActionClickManager; import com.android.systemui.statusbar.notification.row.NotificationEntryProcessorFactory; import com.android.systemui.statusbar.notification.row.NotificationEntryProcessorFactoryLooperImpl; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; @@ -346,4 +347,5 @@ public interface NotificationsModule { /** Provides an instance of {@link EntryAdapterFactory} */ @Binds EntryAdapterFactory provideEntryAdapterFactory(EntryAdapterFactoryImpl impl); + } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManager.kt index 9728fcfcd6ba..25ae50c34659 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManager.kt @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification.headsup import android.graphics.Region import com.android.systemui.Dumpable import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.statusbar.notification.collection.EntryAdapter import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import dagger.Binds @@ -155,9 +154,9 @@ interface HeadsUpManager : Dumpable { fun setAnimationStateHandler(handler: AnimationStateHandler) /** - * Set an entry to be expanded and therefore stick in the heads up area if it's pinned until - * it's collapsed again. - */ + * Set an entry to be expanded and therefore stick in the heads up area if it's pinned until + * it's collapsed again. + */ fun setExpanded(key: String, row: ExpandableNotificationRow, expanded: Boolean) /** @@ -199,12 +198,12 @@ interface HeadsUpManager : Dumpable { * Notes that the user took an action on an entry that might indirectly cause the system or the * app to remove the notification. * - * @param entry the entry that might be indirectly removed by the user's action + * @param entry the key of the entry that might be indirectly removed by the user's action * @see * com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator.mActionPressListener * @see .canRemoveImmediately */ - fun setUserActionMayIndirectlyRemove(entry: NotificationEntry) + fun setUserActionMayIndirectlyRemove(entryKey: String) /** * Decides whether a click is invalid for a notification, i.e. it has not been shown long enough @@ -332,7 +331,7 @@ class HeadsUpManagerEmptyImpl @Inject constructor() : HeadsUpManager { override fun setUser(user: Int) {} - override fun setUserActionMayIndirectlyRemove(entry: NotificationEntry) {} + override fun setUserActionMayIndirectlyRemove(entryKey: String) {} override fun shouldSwallowClick(key: String): Boolean = false diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerExt.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerExt.kt index 6525b6f1186b..376735025abd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerExt.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerExt.kt @@ -16,7 +16,7 @@ package com.android.systemui.statusbar.notification.headsup -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.statusbar.notification.collection.NotificationEntry import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java index ca94655318b9..ca83666079ec 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java @@ -1126,8 +1126,8 @@ public class HeadsUpManagerImpl * @see HeadsUpCoordinator.mActionPressListener * @see #canRemoveImmediately(String) */ - public void setUserActionMayIndirectlyRemove(@NonNull NotificationEntry entry) { - HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.getKey()); + public void setUserActionMayIndirectlyRemove(@NonNull String entryKey) { + HeadsUpEntry headsUpEntry = getHeadsUpEntry(entryKey); if (headsUpEntry != null) { headsUpEntry.mUserActionMayIndirectlyRemove = true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index b481455699ef..8da2f768bf71 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -3054,6 +3054,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mUserLocked = userLocked; mPrivateLayout.setUserExpanding(userLocked); + if (android.app.Flags.expandingPublicView()) { + mPublicLayout.setUserExpanding(userLocked); + } // This is intentionally not guarded with mIsSummaryWithChildren since we might have had // children but not anymore. if (mChildrenContainer != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt index d02f636728fc..fe3a856e711e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt @@ -18,7 +18,9 @@ package com.android.systemui.statusbar.notification.row import android.animation.ValueAnimator import android.content.Context +import android.content.res.ColorStateList import android.graphics.Canvas +import android.graphics.Color import android.graphics.ColorFilter import android.graphics.Paint import android.graphics.Path @@ -31,9 +33,27 @@ import android.graphics.RectF import android.graphics.Shader import com.android.systemui.res.R import com.android.wm.shell.shared.animation.Interpolators +import android.graphics.drawable.RippleDrawable +import androidx.core.content.ContextCompat class MagicActionBackgroundDrawable( context: Context, +) : RippleDrawable( + ContextCompat.getColorStateList( + context, + R.color.notification_ripple_untinted_color + ) ?: ColorStateList.valueOf(Color.TRANSPARENT), + createBaseDrawable(context), null +) { + companion object { + private fun createBaseDrawable(context: Context): Drawable { + return BaseBackgroundDrawable(context) + } + } +} + +class BaseBackgroundDrawable( + context: Context, ) : Drawable() { private val cornerRadius = context.resources.getDimension(R.dimen.magic_action_button_corner_radius) @@ -42,6 +62,14 @@ class MagicActionBackgroundDrawable( private val buttonShape = Path() // Color and style + private val bgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + val bgColor = + context.getColor( + com.android.internal.R.color.materialColorSurfaceContainerHigh + ) + color = bgColor + style = Paint.Style.FILL + } private val outlinePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { val outlineColor = context.getColor( @@ -91,6 +119,7 @@ class MagicActionBackgroundDrawable( canvas.save() // Draw background canvas.clipPath(buttonShape) + canvas.drawPath(buttonShape, bgPaint) // Apply gradient to outline canvas.drawPath(buttonShape, outlinePaint) updateGradient(boundsF) @@ -119,11 +148,13 @@ class MagicActionBackgroundDrawable( } override fun setAlpha(alpha: Int) { + bgPaint.alpha = alpha outlinePaint.alpha = alpha invalidateSelf() } override fun setColorFilter(colorFilter: ColorFilter?) { + bgPaint.colorFilter = colorFilter outlinePaint.colorFilter = colorFilter invalidateSelf() } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationActionClickManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationActionClickManager.kt new file mode 100644 index 000000000000..2b451406eaad --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationActionClickManager.kt @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2025 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 com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.util.ListenerSet +import java.util.function.Consumer +import javax.inject.Inject + +/** + * Pipeline components can register consumers here to be informed when a notification action is + * clicked + */ +@SysUISingleton +class NotificationActionClickManager @Inject constructor() { + private val actionClickListeners = ListenerSet<Consumer<NotificationEntry>>() + + fun addActionClickListener(listener: Consumer<NotificationEntry>) { + actionClickListeners.addIfAbsent(listener) + } + + fun removeActionClickListener(listener: Consumer<NotificationEntry>) { + actionClickListeners.remove(listener) + } + + fun onNotificationActionClicked(entry: NotificationEntry) { + for (listener in actionClickListeners) { + listener.accept(entry) + } + } +} 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 3ffc052b5acc..ff4b835eb3c0 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 @@ -17,7 +17,7 @@ package com.android.systemui.statusbar.notification.row; import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; -import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_SENSITIVE_CONTENT; +import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_OTP; import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED; import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_EXPANDED; import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP; @@ -236,7 +236,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder ); } if (LockscreenOtpRedaction.isSingleLineViewEnabled()) { - if (bindParams.redactionType == REDACTION_TYPE_SENSITIVE_CONTENT) { + if (bindParams.redactionType == REDACTION_TYPE_OTP) { result.mPublicInflatedSingleLineViewModel = SingleLineViewInflater.inflateSingleLineViewModel( entry.getSbn().getNotification(), @@ -469,7 +469,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) { logger.logAsyncTaskProgress(row.getLoggingKey(), "creating public remote view"); if (LockscreenOtpRedaction.isEnabled() - && bindParams.redactionType == REDACTION_TYPE_SENSITIVE_CONTENT) { + && bindParams.redactionType == REDACTION_TYPE_OTP) { result.newPublicView = createSensitiveContentMessageNotification( NotificationBundleUi.isEnabled() ? row.getEntryAdapter().getSbn().getNotification() @@ -1355,7 +1355,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder } if (LockscreenOtpRedaction.isSingleLineViewEnabled()) { - if (mBindParams.redactionType == REDACTION_TYPE_SENSITIVE_CONTENT) { + if (mBindParams.redactionType == REDACTION_TYPE_OTP) { result.mPublicInflatedSingleLineViewModel = SingleLineViewInflater.inflateSingleLineViewModel( mEntry.getSbn().getNotification(), diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java index 193203720aa5..b3357d01ab7a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification.row; +import static android.app.Flags.notificationsRedesignTemplates; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Flags; @@ -293,8 +295,8 @@ public class NotificationContentView extends FrameLayout implements Notification useExactly = true; } int spec = MeasureSpec.makeMeasureSpec(size, useExactly - ? MeasureSpec.EXACTLY - : MeasureSpec.AT_MOST); + ? MeasureSpec.EXACTLY + : MeasureSpec.AT_MOST); measureChildWithMargins(mExpandedChild, widthMeasureSpec, 0, spec, 0); maxChildHeight = Math.max(maxChildHeight, mExpandedChild.getMeasuredHeight()); } @@ -719,16 +721,19 @@ public class NotificationContentView extends FrameLayout implements Notification * height, the notification is clipped instead of being further shrunk. */ private int getMinContentHeightHint() { + int actionListHeight = mContext.getResources().getDimensionPixelSize( + notificationsRedesignTemplates() + ? com.android.internal.R.dimen.notification_2025_action_list_height + : com.android.internal.R.dimen.notification_action_list_height); if (mIsChildInGroup && isVisibleOrTransitioning(VISIBLE_TYPE_SINGLELINE)) { - return mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.notification_action_list_height); + return actionListHeight; } // Transition between heads-up & expanded, or pinned. if (mHeadsUpChild != null && mExpandedChild != null) { boolean transitioningBetweenHunAndExpanded = isTransitioningFromTo(VISIBLE_TYPE_HEADSUP, VISIBLE_TYPE_EXPANDED) || - isTransitioningFromTo(VISIBLE_TYPE_EXPANDED, VISIBLE_TYPE_HEADSUP); + isTransitioningFromTo(VISIBLE_TYPE_EXPANDED, VISIBLE_TYPE_HEADSUP); boolean pinned = !isVisibleOrTransitioning(VISIBLE_TYPE_CONTRACTED) && (mIsHeadsUp || mHeadsUpAnimatingAway) && mContainingNotification.canShowHeadsUp(); @@ -756,9 +761,7 @@ public class NotificationContentView extends FrameLayout implements Notification } else if (mExpandedChild != null) { hint = getViewHeight(VISIBLE_TYPE_EXPANDED); } else if (mContractedChild != null) { - hint = getViewHeight(VISIBLE_TYPE_CONTRACTED) - + mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.notification_action_list_height); + hint = getViewHeight(VISIBLE_TYPE_CONTRACTED) + actionListHeight; } else { hint = getMinHeight(); } @@ -1053,8 +1056,8 @@ public class NotificationContentView extends FrameLayout implements Notification // the original type final int visibleType = ( isGroupExpanded() || mContainingNotification.isUserLocked()) - ? calculateVisibleType() - : getVisibleType(); + ? calculateVisibleType() + : getVisibleType(); return getBackgroundColor(visibleType); } @@ -1240,7 +1243,14 @@ public class NotificationContentView extends FrameLayout implements Notification height = mContentHeight; } int expandedVisualType = getVisualTypeForHeight(height); - int collapsedVisualType = mIsChildInGroup && !isGroupExpanded() + final boolean shouldShowSingleLineView = mIsChildInGroup && !isGroupExpanded(); + final boolean isSingleLineViewPresent = mSingleLineView != null; + + if (shouldShowSingleLineView && !isSingleLineViewPresent) { + Log.e(TAG, "calculateVisibleType: SingleLineView is not available!"); + } + + final int collapsedVisualType = shouldShowSingleLineView && isSingleLineViewPresent ? VISIBLE_TYPE_SINGLELINE : getVisualTypeForHeight(mContainingNotification.getCollapsedHeight()); return mTransformationStartVisibleType == collapsedVisualType @@ -1261,7 +1271,13 @@ public class NotificationContentView extends FrameLayout implements Notification if (!noExpandedChild && viewHeight == getViewHeight(VISIBLE_TYPE_EXPANDED)) { return VISIBLE_TYPE_EXPANDED; } - if (!mUserExpanding && mIsChildInGroup && !isGroupExpanded()) { + final boolean shouldShowSingleLineView = mIsChildInGroup && !isGroupExpanded(); + final boolean isSingleLinePresent = mSingleLineView != null; + if (shouldShowSingleLineView && !isSingleLinePresent) { + Log.e(TAG, "getVisualTypeForHeight: singleLineView is not available."); + } + + if (!mUserExpanding && shouldShowSingleLineView && isSingleLinePresent) { return VISIBLE_TYPE_SINGLELINE; } @@ -1276,7 +1292,7 @@ public class NotificationContentView extends FrameLayout implements Notification if (noExpandedChild || (mContractedChild != null && viewHeight <= getViewHeight(VISIBLE_TYPE_CONTRACTED) && (!mIsChildInGroup || isGroupExpanded() - || !mContainingNotification.isExpanded(true /* allowOnKeyguard */)))) { + || !mContainingNotification.isExpanded(true /* allowOnKeyguard */)))) { return VISIBLE_TYPE_CONTRACTED; } else if (!noExpandedChild) { return VISIBLE_TYPE_EXPANDED; @@ -1600,12 +1616,14 @@ public class NotificationContentView extends FrameLayout implements Notification actionContainer.setVisibility(VISIBLE); // Set notification_action_list_margin_target's bottom margin to 0 when showing bubble if (actionListMarginTarget != null) { - ViewGroup.LayoutParams lp = actionListMarginTarget.getLayoutParams(); - if (lp instanceof ViewGroup.MarginLayoutParams) { - final ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) lp; - if (mlp.bottomMargin > 0) { - mlp.setMargins(mlp.leftMargin, mlp.topMargin, mlp.rightMargin, 0); - } + removeBottomMargin(actionListMarginTarget); + } + if (notificationsRedesignTemplates()) { + // Similar treatment for smart reply margin + LinearLayout smartReplyContainer = layout.findViewById( + com.android.internal.R.id.smart_reply_container); + if (smartReplyContainer != null) { + removeBottomMargin(smartReplyContainer); } } } else { @@ -1613,6 +1631,16 @@ public class NotificationContentView extends FrameLayout implements Notification } } + private static void removeBottomMargin(ViewGroup actionListMarginTarget) { + ViewGroup.LayoutParams lp = actionListMarginTarget.getLayoutParams(); + if (lp instanceof MarginLayoutParams) { + final MarginLayoutParams mlp = (MarginLayoutParams) lp; + if (mlp.bottomMargin > 0) { + mlp.setMargins(mlp.leftMargin, mlp.topMargin, mlp.rightMargin, 0); + } + } + } + @MainThread public void setBubblesEnabledForUser(boolean enabled) { mBubblesEnabledForUser = enabled; @@ -1687,7 +1715,7 @@ public class NotificationContentView extends FrameLayout implements Notification : smartReplies.fromAssistant; boolean editBeforeSending = smartReplies != null && mSmartReplyConstants.getEffectiveEditChoicesBeforeSending( - smartReplies.remoteInput.getEditChoicesBeforeSending()); + smartReplies.remoteInput.getEditChoicesBeforeSending()); mSmartReplyController.smartSuggestionsAdded(mNotificationEntry, numSmartReplies, numSmartActions, fromAssistant, editBeforeSending); @@ -2114,8 +2142,8 @@ public class NotificationContentView extends FrameLayout implements Notification public boolean shouldClipToRounding(boolean topRounded, boolean bottomRounded) { boolean needsPaddings = shouldClipToRounding(getVisibleType(), topRounded, bottomRounded); if (mUserExpanding) { - needsPaddings |= shouldClipToRounding(mTransformationStartVisibleType, topRounded, - bottomRounded); + needsPaddings |= shouldClipToRounding(mTransformationStartVisibleType, topRounded, + bottomRounded); } return needsPaddings; } 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 index b1c145e08777..2f94d3220dc8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.notification.row import android.annotation.SuppressLint -import android.app.Flags import android.app.Notification import android.app.Notification.EXTRA_SUMMARIZED_CONTENT import android.app.Notification.MessagingStyle @@ -45,7 +44,7 @@ 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.NotificationLockscreenUserManager.REDACTION_TYPE_SENSITIVE_CONTENT +import com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_OTP import com.android.systemui.statusbar.NotificationRemoteInputManager import com.android.systemui.statusbar.notification.ConversationNotificationProcessor import com.android.systemui.statusbar.notification.InflationException @@ -758,7 +757,7 @@ constructor( entry.logKey, "inflating public single line view model", ) - if (bindParams.redactionType == REDACTION_TYPE_SENSITIVE_CONTENT) { + if (bindParams.redactionType == REDACTION_TYPE_OTP) { SingleLineViewInflater.inflateSingleLineViewModel( notification = entry.sbn.notification, messagingStyle = messagingStyle, @@ -876,7 +875,7 @@ constructor( logger.logAsyncTaskProgress(row.loggingKey, "creating public remote view") if ( LockscreenOtpRedaction.isEnabled && - bindParams.redactionType == REDACTION_TYPE_SENSITIVE_CONTENT + bindParams.redactionType == REDACTION_TYPE_OTP ) { createSensitiveContentMessageNotification( entry.sbn.notification, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java index 8176d2a1be44..99db1dba7e65 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java @@ -53,8 +53,8 @@ import com.android.systemui.statusbar.notification.ImageTransformState; import com.android.systemui.statusbar.notification.TransformState; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.HybridNotificationView; -import com.android.systemui.util.DimensionKt; import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; +import com.android.systemui.util.DimensionKt; import java.util.function.Consumer; @@ -411,7 +411,8 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp @Override public int getExtraMeasureHeight() { int extra = 0; - if (mActions != null) { + if (!notificationsRedesignTemplates() && mActions != null) { + // With the redesign, this should always be 0. extra = mActions.getExtraMeasureHeight(); } if (mRemoteInputHistory != null && mRemoteInputHistory.getVisibility() != View.GONE) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java index 1e249520e8b3..abfb86244390 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java @@ -36,13 +36,14 @@ import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository; +import com.android.systemui.statusbar.notification.headsup.AvalancheController; +import com.android.systemui.statusbar.notification.headsup.NotificationsHunSharedAnimationValues; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.BypassController; import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; -import com.android.systemui.statusbar.notification.headsup.AvalancheController; import java.io.PrintWriter; @@ -424,6 +425,7 @@ public class AmbientState implements Dumpable { /** the bottom-most y position where we can draw pinned HUNs */ public float getHeadsUpBottom() { if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return 0f; + NotificationsHunSharedAnimationValues.assertInLegacyMode(); return mHeadsUpBottom; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index c2c271bd6e81..e6bb1b9f0273 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -64,7 +64,6 @@ import android.util.AttributeSet; import android.util.IndentingPrintWriter; import android.util.Log; import android.util.MathUtils; -import android.util.Pair; import android.view.DisplayCutout; import android.view.InputDevice; import android.view.LayoutInflater; @@ -141,7 +140,6 @@ import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScr import com.android.systemui.statusbar.phone.HeadsUpAppearanceController; import com.android.systemui.statusbar.policy.ScrollAdapter; import com.android.systemui.statusbar.policy.SplitShadeStateController; -import com.android.systemui.statusbar.ui.SystemBarUtilsProxy; import com.android.systemui.util.Assert; import com.android.systemui.util.ColorUtilKt; import com.android.systemui.util.DumpUtilsKt; @@ -6004,6 +6002,7 @@ public class NotificationStackScrollLayout * LockscreenShadeTransitionController resets fraction to 0 * where it remains until the next lockscreen-to-shade transition. */ + @Override public void setFractionToShade(float fraction) { mAmbientState.setFractionToShade(fraction); updateContentHeight(); // Recompute stack height with different section gap. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index bb3abc1fba38..f7f8acf5fda9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -1735,6 +1735,7 @@ public class NotificationStackScrollLayoutController implements Dumpable { * they remain until the next lockscreen-to-shade transition. */ public void setTransitionToFullShadeAmount(float fraction) { + SceneContainerFlag.assertInLegacyMode(); mView.setFractionToShade(fraction); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java index d23a4c6307fc..28218227506c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java @@ -967,9 +967,12 @@ public class StackScrollAlgorithm { childState.setZTranslation(baseZ); } if (isTopEntry && row.isAboveShelf()) { + float headsUpBottom = NotificationsHunSharedAnimationValues.isEnabled() + ? mHeadsUpAnimator.getHeadsUpAppearHeightBottom() + : ambientState.getHeadsUpBottom(); clampHunToMaxTranslation( /* headsUpTop = */ headsUpTranslation, - /* headsUpBottom = */ ambientState.getHeadsUpBottom(), + /* headsUpBottom = */ headsUpBottom, /* viewState = */ childState ); updateCornerRoundnessForPinnedHun(row, ambientState.getStackTop()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt index 9c855e9cd9b7..ac89f3a63fcd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt @@ -107,6 +107,9 @@ interface NotificationScrollView { /** sets the current expand fraction */ fun setExpandFraction(expandFraction: Float) + /** Sets the fraction of the LockScreen -> Shade transition. */ + fun setFractionToShade(fraction: Float) + /** sets the current QS expand fraction */ fun setQsExpandFraction(expandFraction: Float) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt index 653344ae9203..40739b386d20 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt @@ -95,6 +95,11 @@ constructor( view.setExpandFraction(it.coerceIn(0f, 1f)) } } + launch { + viewModel.lockScreenToShadeTransitionProgress.collectTraced { + view.setFractionToShade(it.coerceIn(0f, 1f)) + } + } launch { viewModel.qsExpandFraction.collectTraced { view.setQsExpandFraction(it) } } launch { viewModel.blurRadius(maxBlurRadius).collect(view::setBlurRadius) } launch { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt index c1aa5f12aa99..940b2e541758 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt @@ -207,6 +207,44 @@ constructor( val qsExpandFraction: Flow<Float> = shadeInteractor.qsExpansion.dumpWhileCollecting("qsExpandFraction") + /** + * Fraction of the LockScreen -> Shade transition. 0..1 while the transition in progress, and + * snaps back to 0 when it is Idle. + */ + val lockScreenToShadeTransitionProgress: Flow<Float> = + combine( + shadeInteractor.shadeExpansion, + shadeModeInteractor.shadeMode, + sceneInteractor.transitionState, + ) { shadeExpansion, _, transitionState -> + when (transitionState) { + is Idle -> 0f + is ChangeScene -> + if ( + transitionState.isTransitioning( + from = Scenes.Lockscreen, + to = Scenes.Shade, + ) + ) { + shadeExpansion + } else { + 0f + } + + is Transition.OverlayTransition -> + if ( + transitionState.currentScene == Scenes.Lockscreen && + transitionState.isTransitioning(to = Overlays.NotificationsShade) + ) { + shadeExpansion + } else { + 0f + } + } + } + .distinctUntilChanged() + .dumpWhileCollecting("lockScreenToShadeTransitionProgress") + val isOccluded: Flow<Boolean> = bouncerInteractor.bouncerExpansion .map { it == 1f } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogManagerExt.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogManagerExt.kt index fbc6b9524a6d..372e91f88ae5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogManagerExt.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogManagerExt.kt @@ -17,7 +17,7 @@ package com.android.systemui.statusbar.phone import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt index f82e681de76f..e2fd4bdc45a9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt @@ -19,7 +19,7 @@ package com.android.systemui.statusbar.pipeline.airplane.data.repository import android.net.ConnectivityManager import android.os.Handler import android.provider.Settings.Global -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.log.table.TableLogBuffer diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/ui/composable/UnifiedBattery.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/ui/composable/UnifiedBattery.kt index 732ea6ac6790..5127e8a14796 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/ui/composable/UnifiedBattery.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/ui/composable/UnifiedBattery.kt @@ -101,7 +101,13 @@ fun BatteryCanvas( for (glyph in glyphs) { // Move the glyph to the right spot val verticalOffset = (BatteryFrame.innerHeight - glyph.height) / 2 - inset(horizontalOffset, verticalOffset) { glyph.draw(this, colors) } + inset( + // Never try and inset more than half of the available size - see b/400246091. + minOf(horizontalOffset, size.width / 2), + minOf(verticalOffset, size.height / 2), + ) { + glyph.draw(this, colors) + } horizontalOffset += glyph.width + INTER_GLYPH_PADDING_PX } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherKairos.kt index 1f5b849c56cc..f4076ae34a4f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherKairos.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherKairos.kt @@ -24,7 +24,7 @@ import com.android.systemui.Flags import com.android.systemui.KairosActivatable import com.android.systemui.KairosBuilder import com.android.systemui.activated -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.demomode.DemoMode import com.android.systemui.demomode.DemoModeController diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt index 982f6ec36150..2a6ff3b98ae2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt @@ -28,7 +28,7 @@ import android.telephony.satellite.SatelliteModemStateCallback import android.telephony.satellite.SatelliteProvisionStateCallback import androidx.annotation.VisibleForTesting import com.android.app.tracing.coroutines.launchTraced as launch -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt index 3bae91a0ebe3..c717b180575c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt @@ -262,6 +262,12 @@ constructor( override val popupChips get() = statusBarPopupChips.shownPopupChips + private val isShadeExpandedEnough = + // Keep the status bar visible while the shade is just starting to open, but otherwise + // hide it so that the status bar doesn't draw while it can't be seen. + // See b/394257529#comment24. + shadeInteractor.anyExpansion.map { it >= 0.2 }.distinctUntilChanged() + /** * Whether the display of this statusbar has the shade window (that is hosting shade container * and lockscreen, among other things). @@ -283,7 +289,7 @@ constructor( Overlays.QuickSettingsShade in currentOverlays) } } else { - shadeInteractor.isAnyFullyExpanded + isShadeExpandedEnough } private val isShadeVisibleOnThisDisplay: Flow<Boolean> = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt index f9bba9d624f1..eaceb5e22535 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt @@ -26,7 +26,7 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleRegistry import com.android.internal.annotations.VisibleForTesting import com.android.systemui.Flags.multiuserWifiPickerTrackerSupport -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt index 0a2bbe580b99..14cadd90db4e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt @@ -14,7 +14,7 @@ package com.android.systemui.statusbar.policy import android.content.res.Configuration -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt index 3cb7090ea6d4..a352982f58f2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt @@ -32,6 +32,7 @@ import com.android.systemui.qs.tiles.DndTile import com.android.systemui.qs.tiles.FlashlightTile import com.android.systemui.qs.tiles.LocationTile import com.android.systemui.qs.tiles.MicrophoneToggleTile +import com.android.systemui.qs.tiles.ModesDndTile import com.android.systemui.qs.tiles.ModesTile import com.android.systemui.qs.tiles.UiModeNightTile import com.android.systemui.qs.tiles.WorkModeTile @@ -49,9 +50,13 @@ import com.android.systemui.qs.tiles.impl.location.domain.LocationTileMapper import com.android.systemui.qs.tiles.impl.location.domain.interactor.LocationTileDataInteractor import com.android.systemui.qs.tiles.impl.location.domain.interactor.LocationTileUserActionInteractor import com.android.systemui.qs.tiles.impl.location.domain.model.LocationTileModel +import com.android.systemui.qs.tiles.impl.modes.domain.interactor.ModesDndTileDataInteractor +import com.android.systemui.qs.tiles.impl.modes.domain.interactor.ModesDndTileUserActionInteractor import com.android.systemui.qs.tiles.impl.modes.domain.interactor.ModesTileDataInteractor import com.android.systemui.qs.tiles.impl.modes.domain.interactor.ModesTileUserActionInteractor +import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesDndTileModel import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel +import com.android.systemui.qs.tiles.impl.modes.ui.ModesDndTileMapper import com.android.systemui.qs.tiles.impl.modes.ui.ModesTileMapper import com.android.systemui.qs.tiles.impl.sensorprivacy.SensorPrivacyToggleTileDataInteractor import com.android.systemui.qs.tiles.impl.sensorprivacy.domain.SensorPrivacyToggleTileUserActionInteractor @@ -132,6 +137,7 @@ interface PolicyModule { const val CAMERA_TOGGLE_TILE_SPEC = "cameratoggle" const val MIC_TOGGLE_TILE_SPEC = "mictoggle" const val DND_TILE_SPEC = "dnd" + const val MODES_DND_TILE_SPEC = "modes_dnd" /** Inject DndTile or ModesTile into tileMap in QSModule based on feature flag */ @Provides @@ -146,6 +152,12 @@ interface PolicyModule { return if (ModesUi.isEnabled) modesTile.get() else dndTile.get() } + /** Inject ModesDndTile into tileViewModelMap in QSModule */ + @Provides + @IntoMap + @StringKey(MODES_DND_TILE_SPEC) + fun bindDndModeTile(tile: ModesDndTile): QSTileImpl<*> = tile + /** Inject flashlight config */ @Provides @IntoMap @@ -449,6 +461,37 @@ interface PolicyModule { mapper, ) else StubQSTileViewModel + + @Provides + @IntoMap + @StringKey(MODES_DND_TILE_SPEC) + fun provideDndModeTileConfig(uiEventLogger: QsEventLogger): QSTileConfig = + QSTileConfig( + tileSpec = TileSpec.create(MODES_DND_TILE_SPEC), + uiConfig = + QSTileUIConfig.Resource( + iconRes = R.drawable.qs_dnd_icon_off, + labelRes = R.string.quick_settings_dnd_label, + ), + instanceId = uiEventLogger.getNewInstanceId(), + category = TileCategory.CONNECTIVITY, + ) + + @Provides + @IntoMap + @StringKey(MODES_DND_TILE_SPEC) + fun provideDndModeTileViewModel( + factory: QSTileViewModelFactory.Static<ModesDndTileModel>, + mapper: ModesDndTileMapper, + stateInteractor: ModesDndTileDataInteractor, + userActionInteractor: ModesDndTileUserActionInteractor, + ): QSTileViewModel = + factory.create( + TileSpec.create(MODES_DND_TILE_SPEC), + userActionInteractor, + stateInteractor, + mapper, + ) } /** Inject FlashlightTile into tileMap in QSModule */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepository.kt index 07bbca74e12e..2b9d39a54c44 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepository.kt @@ -15,7 +15,7 @@ */ package com.android.systemui.statusbar.policy.data.repository -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.statusbar.policy.DeviceProvisionedController import dagger.Binds import dagger.Module diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt index e8347df5653f..ed814c6b3785 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt @@ -58,7 +58,7 @@ import kotlinx.coroutines.flow.stateIn * An interactor that performs business logic related to the status and configuration of Zen Mode * (or Do Not Disturb/DND Mode). */ - @SysUISingleton +@SysUISingleton class ZenModeInteractor @Inject constructor( @@ -141,6 +141,18 @@ constructor( return field } + /** + * Returns the current state of the special "manual DND" mode. + * + * This should only be used when there is a strong reason to handle DND specifically (such as + * legacy UI pieces that haven't been updated to use modes more generally, or if the user + * explicitly wants a shortcut to DND). Please prefer using [modes] or [activeModes] in all + * other scenarios. + */ + fun getDndMode(): ZenMode { + return zenModeRepository.getModes().single { it.isManualDnd } + } + /** Flow returning the currently active mode(s), if any. */ val activeModes: Flow<ActiveZenModes> = modes diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt index 2dc17f40a380..c86e00de4246 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt @@ -16,7 +16,7 @@ package com.android.systemui.statusbar.ui.viewmodel -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor diff --git a/packages/SystemUI/src/com/android/systemui/telephony/data/repository/TelephonyRepository.kt b/packages/SystemUI/src/com/android/systemui/telephony/data/repository/TelephonyRepository.kt index b1b6014bfbde..9b88d439f2db 100644 --- a/packages/SystemUI/src/com/android/systemui/telephony/data/repository/TelephonyRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/telephony/data/repository/TelephonyRepository.kt @@ -23,7 +23,7 @@ import android.content.pm.PackageManager import android.telecom.TelecomManager import android.telephony.Annotation import android.telephony.TelephonyCallback -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background diff --git a/packages/SystemUI/src/com/android/systemui/unfold/data/repository/UnfoldTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/unfold/data/repository/UnfoldTransitionRepository.kt index fbbd2b9c5de8..e47d74ec9412 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/data/repository/UnfoldTransitionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/data/repository/UnfoldTransitionRepository.kt @@ -16,7 +16,7 @@ package com.android.systemui.unfold.data.repository import androidx.annotation.FloatRange -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.unfold.UnfoldTransitionProgressProvider import com.android.systemui.unfold.data.repository.UnfoldTransitionStatus.TransitionFinished import com.android.systemui.unfold.data.repository.UnfoldTransitionStatus.TransitionInProgress diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt index c960b5525d96..05b2e0d1423e 100644 --- a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt @@ -33,7 +33,7 @@ import com.android.app.tracing.coroutines.launchTraced as launch import com.android.internal.statusbar.IStatusBarService import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserSwitcherRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserSwitcherRepository.kt index bcbd679b35eb..412161cf98bc 100644 --- a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserSwitcherRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserSwitcherRepository.kt @@ -23,7 +23,7 @@ import android.os.UserManager import android.provider.Settings.Global.USER_SWITCHER_ENABLED import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserLockedInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserLockedInteractor.kt index 3bd8af690763..6657c428a594 100644 --- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserLockedInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserLockedInteractor.kt @@ -20,6 +20,7 @@ import android.os.UserHandle import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.user.data.repository.UserRepository +import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow @@ -31,7 +32,14 @@ class UserLockedInteractor constructor( @Background val backgroundDispatcher: CoroutineDispatcher, val userRepository: UserRepository, + val selectedUserInteractor: SelectedUserInteractor, ) { + /** Whether the current user is unlocked */ + val currentUserUnlocked: Flow<Boolean> = + selectedUserInteractor.selectedUserInfo.flatMapLatestConflated { user -> + isUserUnlocked(user.userHandle) + } + fun isUserUnlocked(userHandle: UserHandle?): Flow<Boolean> = userRepository.isUserUnlocked(userHandle).flowOn(backgroundDispatcher) } diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/data/repository/AnimationStatusRepository.kt b/packages/SystemUI/src/com/android/systemui/util/animation/data/repository/AnimationStatusRepository.kt index 31a8d864de95..9937eeb29151 100644 --- a/packages/SystemUI/src/com/android/systemui/util/animation/data/repository/AnimationStatusRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/util/animation/data/repository/AnimationStatusRepository.kt @@ -19,7 +19,7 @@ import android.content.ContentResolver import android.database.ContentObserver import android.os.Handler import android.provider.Settings -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.unfold.util.ScaleAwareTransitionProgressProvider.Companion.areAnimationsEnabled import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/BatteryControllerExt.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/BatteryControllerExt.kt index 80ccd646f6be..d4eabb9264e6 100644 --- a/packages/SystemUI/src/com/android/systemui/util/kotlin/BatteryControllerExt.kt +++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/BatteryControllerExt.kt @@ -16,7 +16,7 @@ package com.android.systemui.util.kotlin -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.statusbar.policy.BatteryController import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/ManagedProfileControllerExt.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/ManagedProfileControllerExt.kt index 7a2f9b24700f..837bbea9cc3c 100644 --- a/packages/SystemUI/src/com/android/systemui/util/kotlin/ManagedProfileControllerExt.kt +++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/ManagedProfileControllerExt.kt @@ -16,7 +16,7 @@ package com.android.systemui.util.kotlin -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.statusbar.phone.ManagedProfileController import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/ReduceBrightColorsControllerExt.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/ReduceBrightColorsControllerExt.kt index ee00e8b04ef1..02012ede697b 100644 --- a/packages/SystemUI/src/com/android/systemui/util/kotlin/ReduceBrightColorsControllerExt.kt +++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/ReduceBrightColorsControllerExt.kt @@ -16,7 +16,7 @@ package com.android.systemui.util.kotlin -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.qs.ReduceBrightColorsController import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/RotationLockControllerExt.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/RotationLockControllerExt.kt index 22cc8dd7745d..a914c86da0e7 100644 --- a/packages/SystemUI/src/com/android/systemui/util/kotlin/RotationLockControllerExt.kt +++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/RotationLockControllerExt.kt @@ -16,7 +16,7 @@ package com.android.systemui.util.kotlin -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.statusbar.policy.RotationLockController import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/repository/SettingsForUserRepository.kt b/packages/SystemUI/src/com/android/systemui/util/settings/repository/SettingsForUserRepository.kt index 94b3fd244a92..6cdc94251d21 100644 --- a/packages/SystemUI/src/com/android/systemui/util/settings/repository/SettingsForUserRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/util/settings/repository/SettingsForUserRepository.kt @@ -47,6 +47,11 @@ abstract class SettingsForUserRepository( .distinctUntilChanged() .flowOn(backgroundDispatcher) + fun intSettingForUser(userId: Int, name: String, defaultValue: Int = 0): Flow<Int> = + settingObserver(name, userId) { userSettings.getIntForUser(name, defaultValue, userId) } + .distinctUntilChanged() + .flowOn(backgroundDispatcher) + fun <T> settingObserver(name: String, userId: Int, settingsReader: () -> T): Flow<T> { return userSettings .observerFlow(userId, name) @@ -63,4 +68,14 @@ abstract class SettingsForUserRepository( userSettings.getBoolForUser(name, defaultValue, userId) } } + + suspend fun setIntForUser(userId: Int, name: String, value: Int) { + withContext(backgroundContext) { userSettings.putIntForUser(name, value, userId) } + } + + suspend fun getIntForUser(userId: Int, name: String, defaultValue: Int = 0): Int { + return withContext(backgroundContext) { + userSettings.getIntForUser(name, defaultValue, userId) + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsController.kt b/packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsController.kt index 594c5526dca9..7e9ebd218787 100644 --- a/packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsController.kt +++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsController.kt @@ -24,7 +24,7 @@ import android.service.quickaccesswallet.QuickAccessWalletClient import android.service.quickaccesswallet.WalletCard import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.flags.FeatureFlags diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt index 300a7e070b6c..72bc9f690364 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt @@ -36,6 +36,8 @@ import kotlinx.coroutines.flow.flowOf @SysUISingleton class NoopWallpaperRepository @Inject constructor() : WallpaperRepository { override val wallpaperInfo: StateFlow<WallpaperInfo?> = MutableStateFlow(null).asStateFlow() + override val lockscreenWallpaperInfo: StateFlow<WallpaperInfo?> = + MutableStateFlow(null).asStateFlow() override val wallpaperSupportsAmbientMode = flowOf(false) override var rootView: View? = null override val shouldSendFocalArea: StateFlow<Boolean> = MutableStateFlow(false).asStateFlow() diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt index b07342c4c76d..d314f7669421 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt @@ -18,6 +18,8 @@ package com.android.systemui.wallpapers.data.repository import android.app.WallpaperInfo import android.app.WallpaperManager +import android.app.WallpaperManager.FLAG_LOCK +import android.app.WallpaperManager.FLAG_SYSTEM import android.content.Context import android.content.Intent import android.content.IntentFilter @@ -30,9 +32,11 @@ import android.util.Log import android.view.View import com.android.internal.R import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.res.R as SysUIR +import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.shared.Flags.ambientAod import com.android.systemui.shared.Flags.extendedWallpaperEffects import com.android.systemui.user.data.model.SelectedUserModel @@ -63,6 +67,12 @@ interface WallpaperRepository { /** Emits the current user's current wallpaper. */ val wallpaperInfo: StateFlow<WallpaperInfo?> + /** + * Emits the current user's lockscreen wallpaper. This will emit the same value as + * [wallpaperInfo] if the wallpaper is shared between home and lock screen. + */ + val lockscreenWallpaperInfo: StateFlow<WallpaperInfo?> + /** Emits true if the current user's current wallpaper supports ambient mode. */ val wallpaperSupportsAmbientMode: Flow<Boolean> @@ -81,13 +91,14 @@ interface WallpaperRepository { class WallpaperRepositoryImpl @Inject constructor( - @Background scope: CoroutineScope, + @Background private val scope: CoroutineScope, @Background private val bgDispatcher: CoroutineDispatcher, broadcastDispatcher: BroadcastDispatcher, userRepository: UserRepository, private val wallpaperManager: WallpaperManager, private val context: Context, private val secureSettings: SecureSettings, + @ShadeDisplayAware configurationInteractor: ConfigurationInteractor, ) : WallpaperRepository { private val wallpaperChanged: Flow<Unit> = broadcastDispatcher @@ -106,26 +117,19 @@ constructor( // Only update the wallpaper status once the user selection has finished. .filter { it.selectionStatus == SelectionStatus.SELECTION_COMPLETE } - override val wallpaperInfo: StateFlow<WallpaperInfo?> = - if (!wallpaperManager.isWallpaperSupported) { - MutableStateFlow(null).asStateFlow() - } else { - combine(wallpaperChanged, selectedUser, ::Pair) - .mapLatestConflated { (_, selectedUser) -> getWallpaper(selectedUser) } - .stateIn( - scope, - // Always be listening for wallpaper changes. - SharingStarted.Eagerly, - // The initial value is null, but it should get updated pretty quickly because - // the `combine` should immediately kick off a fetch. - initialValue = null, - ) - } - + override val wallpaperInfo: StateFlow<WallpaperInfo?> = getWallpaperInfo(FLAG_SYSTEM) + override val lockscreenWallpaperInfo: StateFlow<WallpaperInfo?> = getWallpaperInfo(FLAG_LOCK) override val wallpaperSupportsAmbientMode: Flow<Boolean> = - secureSettings - .observerFlow(UserHandle.USER_ALL, Settings.Secure.DOZE_ALWAYS_ON_WALLPAPER_ENABLED) - .onStart { emit(Unit) } + combine( + secureSettings + .observerFlow( + UserHandle.USER_ALL, + Settings.Secure.DOZE_ALWAYS_ON_WALLPAPER_ENABLED, + ) + .onStart { emit(Unit) }, + configurationInteractor.onAnyConfigurationChange, + ::Pair, + ) .map { val userEnabled = secureSettings.getInt(Settings.Secure.DOZE_ALWAYS_ON_WALLPAPER_ENABLED, 1) == 1 @@ -172,7 +176,7 @@ constructor( } override val shouldSendFocalArea = - wallpaperInfo + lockscreenWallpaperInfo .map { val focalAreaTarget = context.resources.getString(SysUIR.string.focal_area_target) val shouldSendNotificationLayout = it?.component?.className == focalAreaTarget @@ -184,12 +188,35 @@ constructor( initialValue = extendedWallpaperEffects(), ) - private suspend fun getWallpaper(selectedUser: SelectedUserModel): WallpaperInfo? { + private suspend fun getWallpaper( + selectedUser: SelectedUserModel, + which: Int = FLAG_SYSTEM, + ): WallpaperInfo? { return withContext(bgDispatcher) { - wallpaperManager.getWallpaperInfoForUser(selectedUser.userInfo.id) + if (which == FLAG_LOCK && wallpaperManager.lockScreenWallpaperExists()) { + wallpaperManager.getWallpaperInfo(FLAG_LOCK, selectedUser.userInfo.id) + } else { + wallpaperManager.getWallpaperInfoForUser(selectedUser.userInfo.id) + } } } + private fun getWallpaperInfo(which: Int): StateFlow<WallpaperInfo?> = + if (!wallpaperManager.isWallpaperSupported) { + MutableStateFlow(null).asStateFlow() + } else { + combine(wallpaperChanged, selectedUser, ::Pair) + .mapLatestConflated { (_, selectedUser) -> getWallpaper(selectedUser, which) } + .stateIn( + scope, + // Always be listening for wallpaper changes. + SharingStarted.Eagerly, + // The initial value is null, but it should get updated pretty quickly because + // the `combine` should immediately kick off a fetch. + initialValue = null, + ) + } + companion object { private val TAG = WallpaperRepositoryImpl::class.simpleName private val DEBUG = true diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt index 845be0252581..60345a358bac 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt @@ -24,12 +24,15 @@ import android.widget.LinearLayout import android.window.RemoteTransition import android.window.TransitionFilter import android.window.WindowAnimationState +import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.activity.EmptyTestActivity +import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope -import com.android.systemui.shared.Flags +import com.android.systemui.shared.Flags as SharedFlags import com.android.systemui.testKosmos import com.android.systemui.util.mockito.any import com.android.wm.shell.shared.ShellTransitions @@ -43,7 +46,6 @@ import kotlin.concurrent.thread import kotlin.test.assertEquals import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.advanceUntilIdle -import kotlinx.coroutines.test.runTest import org.junit.After import org.junit.Assert.assertThrows import org.junit.Before @@ -57,8 +59,8 @@ import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.Mockito.`when` -import org.mockito.Spy import org.mockito.junit.MockitoJUnit +import org.mockito.kotlin.spy @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @@ -66,21 +68,23 @@ import org.mockito.junit.MockitoJUnit @RunWithLooper class ActivityTransitionAnimatorTest : SysuiTestCase() { private val kosmos = testKosmos() - private val transitionContainer = LinearLayout(mContext) + private val mainExecutor = context.mainExecutor private val testTransitionAnimator = fakeTransitionAnimator(mainExecutor) private val testShellTransitions = FakeShellTransitions() + + private val Kosmos.underTest by Kosmos.Fixture { activityTransitionAnimator } + @Mock lateinit var callback: ActivityTransitionAnimator.Callback @Mock lateinit var listener: ActivityTransitionAnimator.Listener - @Spy private val controller = TestTransitionAnimatorController(transitionContainer) @Mock lateinit var iCallback: IRemoteAnimationFinishedCallback - private lateinit var underTest: ActivityTransitionAnimator - @get:Rule val rule = MockitoJUnit.rule() + @get:Rule(order = 0) val mockitoRule = MockitoJUnit.rule() + @get:Rule(order = 1) val activityRule = ActivityScenarioRule(EmptyTestActivity::class.java) @Before fun setup() { - underTest = + kosmos.activityTransitionAnimator = ActivityTransitionAnimator( mainExecutor, ActivityTransitionAnimator.TransitionRegister.fromShellTransitions( @@ -89,19 +93,20 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { testTransitionAnimator, testTransitionAnimator, disableWmTimeout = true, + skipReparentTransaction = true, ) - underTest.callback = callback - underTest.addListener(listener) + kosmos.activityTransitionAnimator.callback = callback + kosmos.activityTransitionAnimator.addListener(listener) } @After fun tearDown() { - underTest.removeListener(listener) + kosmos.activityTransitionAnimator.removeListener(listener) } private fun startIntentWithAnimation( - animator: ActivityTransitionAnimator = underTest, - controller: ActivityTransitionAnimator.Controller? = this.controller, + controller: ActivityTransitionAnimator.Controller?, + animator: ActivityTransitionAnimator = kosmos.activityTransitionAnimator, animate: Boolean = true, intentStarter: (RemoteAnimationAdapter?) -> Int, ) { @@ -119,129 +124,152 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @Test fun animationAdapterIsNullIfControllerIsNull() { - var startedIntent = false - var animationAdapter: RemoteAnimationAdapter? = null + kosmos.runTest { + var startedIntent = false + var animationAdapter: RemoteAnimationAdapter? = null - startIntentWithAnimation(controller = null) { adapter -> - startedIntent = true - animationAdapter = adapter + startIntentWithAnimation(controller = null) { adapter -> + startedIntent = true + animationAdapter = adapter - ActivityManager.START_SUCCESS - } + ActivityManager.START_SUCCESS + } - assertTrue(startedIntent) - assertNull(animationAdapter) + assertTrue(startedIntent) + assertNull(animationAdapter) + } } @Test fun animatesIfActivityOpens() { - val willAnimateCaptor = ArgumentCaptor.forClass(Boolean::class.java) - var animationAdapter: RemoteAnimationAdapter? = null - startIntentWithAnimation { adapter -> - animationAdapter = adapter - ActivityManager.START_SUCCESS - } + kosmos.runTest { + val controller = createController() + val willAnimateCaptor = ArgumentCaptor.forClass(Boolean::class.java) + var animationAdapter: RemoteAnimationAdapter? = null + startIntentWithAnimation(controller) { adapter -> + animationAdapter = adapter + ActivityManager.START_SUCCESS + } - assertNotNull(animationAdapter) - waitForIdleSync() - verify(controller).onIntentStarted(willAnimateCaptor.capture()) - assertTrue(willAnimateCaptor.value) + assertNotNull(animationAdapter) + waitForIdleSync() + verify(controller).onIntentStarted(willAnimateCaptor.capture()) + assertTrue(willAnimateCaptor.value) + } } @Test fun doesNotAnimateIfActivityIsAlreadyOpen() { - val willAnimateCaptor = ArgumentCaptor.forClass(Boolean::class.java) - startIntentWithAnimation { ActivityManager.START_DELIVERED_TO_TOP } + kosmos.runTest { + val controller = createController() + val willAnimateCaptor = ArgumentCaptor.forClass(Boolean::class.java) + startIntentWithAnimation(controller) { ActivityManager.START_DELIVERED_TO_TOP } - waitForIdleSync() - verify(controller).onIntentStarted(willAnimateCaptor.capture()) - assertFalse(willAnimateCaptor.value) + waitForIdleSync() + verify(controller).onIntentStarted(willAnimateCaptor.capture()) + assertFalse(willAnimateCaptor.value) + } } @Test fun animatesIfActivityIsAlreadyOpenAndIsOnKeyguard() { - `when`(callback.isOnKeyguard()).thenReturn(true) + kosmos.runTest { + `when`(callback.isOnKeyguard()).thenReturn(true) - val willAnimateCaptor = ArgumentCaptor.forClass(Boolean::class.java) - var animationAdapter: RemoteAnimationAdapter? = null + val controller = createController() + val willAnimateCaptor = ArgumentCaptor.forClass(Boolean::class.java) + var animationAdapter: RemoteAnimationAdapter? = null - startIntentWithAnimation(underTest) { adapter -> - animationAdapter = adapter - ActivityManager.START_DELIVERED_TO_TOP - } + startIntentWithAnimation(controller, underTest) { adapter -> + animationAdapter = adapter + ActivityManager.START_DELIVERED_TO_TOP + } - waitForIdleSync() - verify(controller).onIntentStarted(willAnimateCaptor.capture()) - verify(callback).hideKeyguardWithAnimation(any()) + waitForIdleSync() + verify(controller).onIntentStarted(willAnimateCaptor.capture()) + verify(callback).hideKeyguardWithAnimation(any()) - assertTrue(willAnimateCaptor.value) - assertNull(animationAdapter) + assertTrue(willAnimateCaptor.value) + assertNull(animationAdapter) + } } @Test fun doesNotAnimateIfAnimateIsFalse() { - val willAnimateCaptor = ArgumentCaptor.forClass(Boolean::class.java) - startIntentWithAnimation(animate = false) { ActivityManager.START_SUCCESS } + kosmos.runTest { + val controller = createController() + val willAnimateCaptor = ArgumentCaptor.forClass(Boolean::class.java) + startIntentWithAnimation(controller, animate = false) { ActivityManager.START_SUCCESS } - waitForIdleSync() - verify(controller).onIntentStarted(willAnimateCaptor.capture()) - assertFalse(willAnimateCaptor.value) + waitForIdleSync() + verify(controller).onIntentStarted(willAnimateCaptor.capture()) + assertFalse(willAnimateCaptor.value) + } } - @EnableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY) + @EnableFlags(SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY) @Test fun registersReturnIffCookieIsPresent() { - `when`(callback.isOnKeyguard()).thenReturn(false) + kosmos.runTest { + `when`(callback.isOnKeyguard()).thenReturn(false) - startIntentWithAnimation(underTest, controller) { ActivityManager.START_DELIVERED_TO_TOP } + val controller = createController() + startIntentWithAnimation(controller, underTest) { + ActivityManager.START_DELIVERED_TO_TOP + } - waitForIdleSync() - assertTrue(testShellTransitions.remotes.isEmpty()) - assertTrue(testShellTransitions.remotesForTakeover.isEmpty()) + waitForIdleSync() + assertTrue(testShellTransitions.remotes.isEmpty()) + assertTrue(testShellTransitions.remotesForTakeover.isEmpty()) - val controller = - object : DelegateTransitionAnimatorController(controller) { - override val transitionCookie - get() = ActivityTransitionAnimator.TransitionCookie("testCookie") - } + val controllerWithCookie = + object : DelegateTransitionAnimatorController(controller) { + override val transitionCookie + get() = ActivityTransitionAnimator.TransitionCookie("testCookie") + } - startIntentWithAnimation(underTest, controller) { ActivityManager.START_DELIVERED_TO_TOP } + startIntentWithAnimation(controllerWithCookie, underTest) { + ActivityManager.START_DELIVERED_TO_TOP + } - waitForIdleSync() - assertEquals(1, testShellTransitions.remotes.size) - assertTrue(testShellTransitions.remotesForTakeover.isEmpty()) + waitForIdleSync() + assertEquals(1, testShellTransitions.remotes.size) + assertTrue(testShellTransitions.remotesForTakeover.isEmpty()) + } } @EnableFlags( - Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, - Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun registersLongLivedTransition() { kosmos.runTest { - var factory = controllerFactory() + val controller = createController() + var factory = controllerFactory(controller) underTest.register(factory.cookie, factory, testScope) assertEquals(2, testShellTransitions.remotes.size) - factory = controllerFactory() + factory = controllerFactory(controller) underTest.register(factory.cookie, factory, testScope) assertEquals(4, testShellTransitions.remotes.size) } } @EnableFlags( - Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, - Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun registersLongLivedTransitionOverridingPreviousRegistration() { kosmos.runTest { + val controller = createController() val cookie = ActivityTransitionAnimator.TransitionCookie("test_cookie") - var factory = controllerFactory(cookie) + var factory = controllerFactory(controller, cookie) underTest.register(cookie, factory, testScope) val transitions = testShellTransitions.remotes.values.toList() - factory = controllerFactory(cookie) + factory = controllerFactory(controller, cookie) underTest.register(cookie, factory, testScope) assertEquals(2, testShellTransitions.remotes.size) for (transition in transitions) { @@ -250,23 +278,25 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { } } - @DisableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED) + @DisableFlags(SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED) @Test fun doesNotRegisterLongLivedTransitionIfFlagIsDisabled() { kosmos.runTest { - val factory = controllerFactory(component = null) + val factory = controllerFactory(createController(), component = null) assertThrows(IllegalStateException::class.java) { underTest.register(factory.cookie, factory, testScope) } } } - @EnableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED) + @EnableFlags(SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED) @Test fun doesNotRegisterLongLivedTransitionIfMissingRequiredProperties() { kosmos.runTest { + val controller = createController() + // No ComponentName - var factory = controllerFactory(component = null) + var factory = controllerFactory(controller, component = null) assertThrows(IllegalStateException::class.java) { underTest.register(factory.cookie, factory, testScope) } @@ -280,7 +310,7 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { testTransitionAnimator, disableWmTimeout = true, ) - factory = controllerFactory() + factory = controllerFactory(controller) assertThrows(IllegalStateException::class.java) { activityTransitionAnimator.register(factory.cookie, factory, testScope) } @@ -288,17 +318,18 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { } @EnableFlags( - Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, - Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun unregistersLongLivedTransition() { kosmos.runTest { + val controller = createController() val cookies = arrayOfNulls<ActivityTransitionAnimator.TransitionCookie>(3) for (index in 0 until 3) { cookies[index] = mock(ActivityTransitionAnimator.TransitionCookie::class.java) - val factory = controllerFactory(cookies[index]!!) + val factory = controllerFactory(controller, cookies[index]!!) underTest.register(factory.cookie, factory, testScope) } @@ -315,75 +346,98 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @Test fun doesNotStartIfAnimationIsCancelled() { - val runner = underTest.createEphemeralRunner(controller) - runner.onAnimationCancelled() - runner.onAnimationStart(TRANSIT_NONE, emptyArray(), emptyArray(), emptyArray(), iCallback) + kosmos.runTest { + val controller = createController() + val runner = underTest.createEphemeralRunner(controller) + runner.onAnimationCancelled() + runner.onAnimationStart( + TRANSIT_NONE, + emptyArray(), + emptyArray(), + emptyArray(), + iCallback, + ) - waitForIdleSync() - verify(controller).onTransitionAnimationCancelled() - verify(controller, never()).onTransitionAnimationStart(anyBoolean()) - verify(listener).onTransitionAnimationCancelled() - verify(listener, never()).onTransitionAnimationStart() - assertNull(runner.delegate) + waitForIdleSync() + verify(controller).onTransitionAnimationCancelled() + verify(controller, never()).onTransitionAnimationStart(anyBoolean()) + verify(listener).onTransitionAnimationCancelled() + verify(listener, never()).onTransitionAnimationStart() + assertNull(runner.delegate) + } } @Test fun cancelsIfNoOpeningWindowIsFound() { - val runner = underTest.createEphemeralRunner(controller) - runner.onAnimationStart(TRANSIT_NONE, emptyArray(), emptyArray(), emptyArray(), iCallback) + kosmos.runTest { + val controller = createController() + val runner = underTest.createEphemeralRunner(controller) + runner.onAnimationStart( + TRANSIT_NONE, + emptyArray(), + emptyArray(), + emptyArray(), + iCallback, + ) - waitForIdleSync() - verify(controller).onTransitionAnimationCancelled() - verify(controller, never()).onTransitionAnimationStart(anyBoolean()) - verify(listener).onTransitionAnimationCancelled() - verify(listener, never()).onTransitionAnimationStart() - assertNull(runner.delegate) + waitForIdleSync() + verify(controller).onTransitionAnimationCancelled() + verify(controller, never()).onTransitionAnimationStart(anyBoolean()) + verify(listener).onTransitionAnimationCancelled() + verify(listener, never()).onTransitionAnimationStart() + assertNull(runner.delegate) + } } @Test fun startsAnimationIfWindowIsOpening() { - val runner = underTest.createEphemeralRunner(controller) - runner.onAnimationStart( - TRANSIT_NONE, - arrayOf(fakeWindow()), - emptyArray(), - emptyArray(), - iCallback, - ) - waitForIdleSync() - verify(listener).onTransitionAnimationStart() - verify(controller).onTransitionAnimationStart(anyBoolean()) + kosmos.runTest { + val controller = createController() + val runner = underTest.createEphemeralRunner(controller) + runner.onAnimationStart( + TRANSIT_NONE, + arrayOf(fakeWindow()), + emptyArray(), + emptyArray(), + iCallback, + ) + waitForIdleSync() + verify(listener).onTransitionAnimationStart() + verify(controller).onTransitionAnimationStart(anyBoolean()) + } } @Test fun creatingControllerFromNormalViewThrows() { - assertThrows(IllegalArgumentException::class.java) { - ActivityTransitionAnimator.Controller.fromView(FrameLayout(mContext)) + kosmos.runTest { + assertThrows(IllegalArgumentException::class.java) { + ActivityTransitionAnimator.Controller.fromView(FrameLayout(mContext)) + } } } @DisableFlags( - Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, - Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun creatingRunnerWithLazyInitializationThrows_whenTheFlagsAreDisabled() { kosmos.runTest { assertThrows(IllegalStateException::class.java) { - val factory = controllerFactory() + val factory = controllerFactory(createController()) underTest.createLongLivedRunner(factory, testScope, forLaunch = true) } } } @EnableFlags( - Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, - Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun runnerCreatesDelegateLazily_onAnimationStart() { kosmos.runTest { - val factory = controllerFactory() + val factory = controllerFactory(createController()) val runner = underTest.createLongLivedRunner(factory, testScope, forLaunch = true) assertNull(runner.delegate) @@ -412,13 +466,13 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { } @EnableFlags( - Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, - Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun runnerCreatesDelegateLazily_onAnimationTakeover() { kosmos.runTest { - val factory = controllerFactory() + val factory = controllerFactory(createController()) val runner = underTest.createLongLivedRunner(factory, testScope, forLaunch = false) assertNull(runner.delegate) @@ -446,58 +500,78 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { } @DisableFlags( - Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, - Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun animationTakeoverThrows_whenTheFlagsAreDisabled() { - val runner = underTest.createEphemeralRunner(controller) - assertThrows(IllegalStateException::class.java) { - runner.takeOverAnimation( - arrayOf(fakeWindow()), - emptyArray(), - SurfaceControl.Transaction(), - iCallback, - ) + kosmos.runTest { + val controller = createController() + val runner = underTest.createEphemeralRunner(controller) + assertThrows(IllegalStateException::class.java) { + runner.takeOverAnimation( + arrayOf(fakeWindow()), + emptyArray(), + SurfaceControl.Transaction(), + iCallback, + ) + } } } @DisableFlags( - Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, - Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun disposeRunner_delegateDereferenced() { - val runner = underTest.createEphemeralRunner(controller) - assertNotNull(runner.delegate) - runner.dispose() - waitForIdleSync() - assertNull(runner.delegate) + kosmos.runTest { + val controller = createController() + val runner = underTest.createEphemeralRunner(controller) + assertNotNull(runner.delegate) + runner.dispose() + waitForIdleSync() + assertNull(runner.delegate) + } } @Test fun concurrentListenerModification_doesNotThrow() { - // Need a second listener to trigger the concurrent modification. - underTest.addListener(object : ActivityTransitionAnimator.Listener {}) - `when`(listener.onTransitionAnimationStart()).thenAnswer { - underTest.removeListener(listener) - listener - } + kosmos.runTest { + // Need a second listener to trigger the concurrent modification. + underTest.addListener(object : ActivityTransitionAnimator.Listener {}) + `when`(listener.onTransitionAnimationStart()).thenAnswer { + underTest.removeListener(listener) + listener + } - val runner = underTest.createEphemeralRunner(controller) - runner.onAnimationStart( - TRANSIT_NONE, - arrayOf(fakeWindow()), - emptyArray(), - emptyArray(), - iCallback, - ) + val controller = createController() + val runner = underTest.createEphemeralRunner(controller) + runner.onAnimationStart( + TRANSIT_NONE, + arrayOf(fakeWindow()), + emptyArray(), + emptyArray(), + iCallback, + ) + + waitForIdleSync() + verify(listener).onTransitionAnimationStart() + } + } + private fun createController(): TestTransitionAnimatorController { + lateinit var transitionContainer: ViewGroup + activityRule.scenario.onActivity { activity -> + transitionContainer = LinearLayout(activity) + activity.setContentView(transitionContainer) + } waitForIdleSync() - verify(listener).onTransitionAnimationStart() + return spy(TestTransitionAnimatorController(transitionContainer)) } private fun controllerFactory( + controller: ActivityTransitionAnimator.Controller, cookie: ActivityTransitionAnimator.TransitionCookie = mock(ActivityTransitionAnimator.TransitionCookie::class.java), component: ComponentName? = mock(ComponentName::class.java), diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorSceneContainerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorSceneContainerTest.kt index b274f1c2c6df..d9c59d37b031 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorSceneContainerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorSceneContainerTest.kt @@ -88,11 +88,6 @@ class KeyguardQuickAffordanceInteractorSceneContainerTest : SysuiTestCase() { companion object { private val INTENT = Intent("some.intent.action") - private val DRAWABLE = - mock<Icon> { - whenever(this.contentDescription) - .thenReturn(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID)) - } private const val CONTENT_DESCRIPTION_RESOURCE_ID = 1337 @Parameters( @@ -337,7 +332,17 @@ class KeyguardQuickAffordanceInteractorSceneContainerTest : SysuiTestCase() { homeControls.setState( lockScreenState = - KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = DRAWABLE) + KeyguardQuickAffordanceConfig.LockScreenState.Visible( + icon = + mock<Icon> { + whenever(contentDescription) + .thenReturn( + ContentDescription.Resource( + res = CONTENT_DESCRIPTION_RESOURCE_ID + ) + ) + } + ) ) homeControls.onTriggeredResult = if (startActivity) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt index 175e8d4331a1..e048d462ef8d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt @@ -33,8 +33,8 @@ import android.platform.test.annotations.EnableFlags import android.platform.test.annotations.RequiresFlagsDisabled import android.platform.test.annotations.RequiresFlagsEnabled import android.platform.test.flag.junit.DeviceFlagsValueProvider +import android.platform.test.flag.junit.FlagsParameterization import android.testing.TestableLooper -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast import com.android.settingslib.bluetooth.LocalBluetoothManager @@ -77,6 +77,8 @@ import org.mockito.Mockito.verifyNoMoreInteractions import org.mockito.Mockito.`when` as whenever import org.mockito.junit.MockitoJUnit import org.mockito.kotlin.eq +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters private const val KEY = "TEST_KEY" private const val KEY_OLD = "TEST_KEY_OLD" @@ -89,12 +91,24 @@ private const val BROADCAST_APP_NAME = "BROADCAST_APP_NAME" private const val NORMAL_APP_NAME = "NORMAL_APP_NAME" @SmallTest -@RunWith(AndroidJUnit4::class) +@RunWith(ParameterizedAndroidJunit4::class) @TestableLooper.RunWithLooper -public class MediaDeviceManagerTest : SysuiTestCase() { +public class MediaDeviceManagerTest(flags: FlagsParameterization) : SysuiTestCase() { - private companion object { + companion object { val OTHER_DEVICE_ICON_STUB = TestStubDrawable() + + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return FlagsParameterization.progressionOf( + com.android.systemui.Flags.FLAG_MEDIA_CONTROLS_DEVICE_MANAGER_BACKGROUND_EXECUTION + ) + } + } + + init { + mSetFlagsRule.setFlagsParameterization(flags) } @get:Rule val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() @@ -187,6 +201,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @Test fun loadMediaData() { manager.onMediaDataLoaded(KEY, null, mediaData) + fakeBgExecutor.runAllReady() + fakeFgExecutor.runAllReady() verify(lmmFactory).create(PACKAGE) } @@ -195,6 +211,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { manager.onMediaDataLoaded(KEY, null, mediaData) manager.onMediaDataRemoved(KEY, false) fakeBgExecutor.runAllReady() + fakeFgExecutor.runAllReady() verify(lmm).unregisterCallback(any()) verify(muteAwaitManager).stopListening() } @@ -406,6 +423,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() { manager.onMediaDataLoaded(KEY, null, mediaData) // WHEN the notification is removed manager.onMediaDataRemoved(KEY, true) + fakeBgExecutor.runAllReady() + fakeFgExecutor.runAllReady() // THEN the listener receives key removed event verify(listener).onKeyRemoved(eq(KEY), eq(true)) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt index 6f71df5958d9..1b5f032652b4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt @@ -1,5 +1,6 @@ package com.android.systemui.qs.tiles +import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothDevice import android.os.Handler import android.os.Looper @@ -8,11 +9,11 @@ import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization import android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf +import android.service.quicksettings.Tile import android.testing.TestableLooper import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger -import com.android.internal.telephony.flags.Flags import com.android.settingslib.Utils import com.android.settingslib.bluetooth.CachedBluetoothDevice import com.android.systemui.SysuiTestCase @@ -82,6 +83,7 @@ class BluetoothTileTest(flags: FlagsParameterization) : SysuiTestCase() { testableLooper = TestableLooper.get(this) whenever(qsHost.context).thenReturn(mContext) + whenever(bluetoothController.canConfigBluetooth()).thenReturn(true) tile = FakeBluetoothTile( @@ -257,6 +259,38 @@ class BluetoothTileTest(flags: FlagsParameterization) : SysuiTestCase() { .removeOnMetadataChangedListener(eq(cachedDevice), any()) } + @Test + @EnableFlags(QSComposeFragment.FLAG_NAME) + fun disableBluetooth_transientTurningOff() { + enableBluetooth() + tile.refreshState() + testableLooper.processAllMessages() + + tile.handleSecondaryClick(null) + testableLooper.processAllMessages() + + val state = tile.state + + assertThat(state.state).isEqualTo(Tile.STATE_INACTIVE) + assertThat(state.isTransient).isTrue() + assertThat(state.icon).isEqualTo(createExpectedIcon(R.drawable.qs_bluetooth_icon_off)) + } + + @Test + @EnableFlags(QSComposeFragment.FLAG_NAME) + fun turningOffState() { + setBluetoothTurningOff() + + tile.refreshState() + testableLooper.processAllMessages() + + val state = tile.state + + assertThat(state.state).isEqualTo(Tile.STATE_INACTIVE) + assertThat(state.isTransient).isTrue() + assertThat(state.icon).isEqualTo(createExpectedIcon(R.drawable.qs_bluetooth_icon_off)) + } + private class FakeBluetoothTile( qsHost: QSHost, uiEventLogger: QsEventLogger, @@ -318,6 +352,13 @@ class BluetoothTileTest(flags: FlagsParameterization) : SysuiTestCase() { whenever(bluetoothController.isBluetoothConnecting).thenReturn(true) } + fun setBluetoothTurningOff() { + whenever(bluetoothController.isBluetoothConnected).thenReturn(false) + whenever(bluetoothController.isBluetoothConnecting).thenReturn(false) + whenever(bluetoothController.isBluetoothEnabled).thenReturn(false) + whenever(bluetoothController.bluetoothState).thenReturn(BluetoothAdapter.STATE_TURNING_OFF) + } + fun addConnectedDevice(device: CachedBluetoothDevice) { whenever(bluetoothController.connectedDevices).thenReturn(listOf(device)) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDetailsContentManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDetailsContentManagerTest.kt index c20a801cd5e3..a8bfbd18d0c5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDetailsContentManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDetailsContentManagerTest.kt @@ -103,6 +103,8 @@ class InternetDetailsContentManagerTest : SysuiTestCase() { whenever(internetWifiEntry.hasInternetAccess()).thenReturn(true) whenever(wifiEntries.size).thenReturn(1) whenever(internetDetailsContentController.getDialogTitleText()).thenReturn(TITLE) + whenever(internetDetailsContentController.getSubtitleText(ArgumentMatchers.anyBoolean())) + .thenReturn("") whenever(internetDetailsContentController.getMobileNetworkTitle(ArgumentMatchers.anyInt())) .thenReturn(MOBILE_NETWORK_TITLE) whenever( @@ -128,15 +130,13 @@ class InternetDetailsContentManagerTest : SysuiTestCase() { internetDetailsContentController, canConfigMobileData = true, canConfigWifi = true, - coroutineScope = scope, - context = mContext, uiEventLogger = mock<UiEventLogger>(), handler = handler, backgroundExecutor = bgExecutor, keyguard = keyguard, ) - internetDetailsContentManager.bind(contentView) + internetDetailsContentManager.bind(contentView, scope) internetDetailsContentManager.adapter = internetAdapter internetDetailsContentManager.connectedWifiEntry = internetWifiEntry internetDetailsContentManager.wifiEntriesCount = wifiEntries.size @@ -777,6 +777,26 @@ class InternetDetailsContentManagerTest : SysuiTestCase() { } } + @Test + fun updateTitleAndSubtitle() { + assertThat(internetDetailsContentManager.title).isEqualTo("Internet") + assertThat(internetDetailsContentManager.subTitle).isEqualTo("") + + whenever(internetDetailsContentController.getDialogTitleText()).thenReturn("New title") + whenever(internetDetailsContentController.getSubtitleText(ArgumentMatchers.anyBoolean())) + .thenReturn("New subtitle") + + internetDetailsContentManager.updateContent(true) + bgExecutor.runAllReady() + + internetDetailsContentManager.internetContentData.observe( + internetDetailsContentManager.lifecycleOwner!! + ) { + assertThat(internetDetailsContentManager.title).isEqualTo("New title") + assertThat(internetDetailsContentManager.subTitle).isEqualTo("New subtitle") + } + } + companion object { private const val TITLE = "Internet" private const val MOBILE_NETWORK_TITLE = "Mobile Title" diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/LauncherProxyServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recents/LauncherProxyServiceTest.kt index 155059ea5ed9..e0118b18ff64 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/recents/LauncherProxyServiceTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/recents/LauncherProxyServiceTest.kt @@ -244,7 +244,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(true) `when`(userManager.isUserForeground()).thenReturn(true) val spyContext = spy(context) - val ops = createLauncherProxyService(spyContext) + val ops = assertLogsWtf { createLauncherProxyService(spyContext) }.result ops.startConnectionToCurrentUser() verify(spyContext, times(0)).bindServiceAsUser(any(), any(), anyInt(), any()) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/ringtone/RingtonePlayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ringtone/RingtonePlayerTest.java new file mode 100644 index 000000000000..c231be181977 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/ringtone/RingtonePlayerTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2025 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.ringtone; + +import static org.junit.Assert.assertThrows; + +import android.media.AudioAttributes; +import android.media.AudioManager; +import android.net.Uri; +import android.os.Binder; +import android.os.UserHandle; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class RingtonePlayerTest extends SysuiTestCase { + + private AudioManager mAudioManager; + + private static final String TAG = "RingtonePlayerTest"; + + @Before + public void setup() throws Exception { + mAudioManager = getContext().getSystemService(AudioManager.class); + } + + @Test + public void testRingtonePlayerUriUserCheck() { + android.media.IRingtonePlayer irp = mAudioManager.getRingtonePlayer(); + final AudioAttributes aa = new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE).build(); + // get a UserId that doesn't belong to mine + final int otherUserId = UserHandle.myUserId() == 0 ? 10 : 0; + // build a URI that I shouldn't have access to + final Uri uri = new Uri.Builder() + .scheme("content").authority(otherUserId + "@media") + .appendPath("external").appendPath("downloads") + .appendPath("bogusPathThatDoesNotMatter.mp3") + .build(); + if (android.media.audio.Flags.ringtoneUserUriCheck()) { + assertThrows(SecurityException.class, () -> + irp.play(new Binder(), uri, aa, 1.0f /*volume*/, false /*looping*/) + ); + + assertThrows(SecurityException.class, () -> + irp.getTitle(uri)); + } + } + +} 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 51bb38fa5ba9..f72645eb8596 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt @@ -51,6 +51,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN 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.assertLogsWtf import com.android.systemui.qs.flags.QSComposeFragment import com.android.systemui.res.R import com.android.systemui.scene.ui.view.WindowRootViewKeyEventHandler @@ -413,7 +414,9 @@ class NotificationShadeWindowViewControllerTest(flags: FlagsParameterization) : // THEN move is ignored, down is handled, and window is notified assertThat(interactionEventHandler.handleDispatchTouchEvent(MOVE_EVENT)).isFalse() - assertThat(interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)).isTrue() + assertLogsWtf { + assertThat(interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)).isTrue() + } verify(notificationShadeWindowController).setLaunchingActivity(false) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java index 4315c0f638ac..84f39be2eeed 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.row; import static android.app.Flags.FLAG_NOTIFICATIONS_REDESIGN_TEMPLATES; +import static com.android.systemui.log.LogAssertKt.assertRunnableLogsWtf; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL; import static com.android.systemui.statusbar.notification.row.NotificationTestHelper.PKG; import static com.android.systemui.statusbar.notification.row.NotificationTestHelper.USER_HANDLE; @@ -1147,7 +1148,7 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { public void hasStatusBarChipDuringHeadsUpAnimation_flagOff_false() throws Exception { final ExpandableNotificationRow row = mNotificationTestHelper.createRow(); - row.setHasStatusBarChipDuringHeadsUpAnimation(true); + assertRunnableLogsWtf(() -> row.setHasStatusBarChipDuringHeadsUpAnimation(true)); assertThat(row.hasStatusBarChipDuringHeadsUpAnimation()).isFalse(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationCustomContentMemoryVerifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationCustomContentMemoryVerifierTest.java index 1cadb3c0a909..e1bab8ec47e6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationCustomContentMemoryVerifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationCustomContentMemoryVerifierTest.java @@ -46,6 +46,7 @@ import androidx.test.filters.SmallTest; import com.android.server.notification.Flags; import com.android.systemui.SysuiTestCase; +import com.android.systemui.log.LogAssertKt; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; @@ -173,8 +174,10 @@ public class NotificationCustomContentMemoryVerifierTest extends SysuiTestCase { public void satisfiesMemoryLimits_viewWithoutCustomNotificationRoot_returnsTrue() { NotificationEntry entry = new NotificationEntryBuilder().build(); View view = new FrameLayout(mContext); - assertThat(NotificationCustomContentMemoryVerifier.satisfiesMemoryLimits(view, entry)) - .isTrue(); + LogAssertKt.assertRunnableLogsWtf(() -> { + assertThat(NotificationCustomContentMemoryVerifier.satisfiesMemoryLimits(view, entry)) + .isTrue(); + }); } @Test 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 a978ecdb3534..0d7ce5353cd4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -204,8 +204,6 @@ import com.android.wm.shell.taskview.TaskViewRepository; import com.android.wm.shell.taskview.TaskViewTransitions; import com.android.wm.shell.transition.Transitions; -import kotlin.Lazy; - import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -216,9 +214,6 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; -import platform.test.runner.parameterized.ParameterizedAndroidJunit4; -import platform.test.runner.parameterized.Parameters; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -227,6 +222,10 @@ import java.util.List; import java.util.Optional; import java.util.concurrent.Executor; +import kotlin.Lazy; +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + @SmallTest @RunWith(ParameterizedAndroidJunit4.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @@ -602,14 +601,19 @@ public class BubblesTest extends SysuiTestCase { // Get a reference to KeyguardStateController.Callback verify(mKeyguardStateController, atLeastOnce()) .addCallback(mKeyguardStateControllerCallbackCaptor.capture()); + + // Make sure mocks are set up for current user + switchUser(ActivityManager.getCurrentUser()); } @After public void tearDown() throws Exception { - ArrayList<Bubble> bubbles = new ArrayList<>(mBubbleData.getBubbles()); - for (int i = 0; i < bubbles.size(); i++) { - mBubbleController.removeBubble(bubbles.get(i).getKey(), - Bubbles.DISMISS_NO_LONGER_BUBBLE); + if (mBubbleData != null) { + ArrayList<Bubble> bubbles = new ArrayList<>(mBubbleData.getBubbles()); + for (int i = 0; i < bubbles.size(); i++) { + mBubbleController.removeBubble(bubbles.get(i).getKey(), + Bubbles.DISMISS_NO_LONGER_BUBBLE); + } } mTestableLooper.processAllMessages(); @@ -2051,6 +2055,9 @@ public class BubblesTest extends SysuiTestCase { @Test public void testShowStackEdu_isConversationBubble() { + // TODO(b/401025577): Prevent this test from raising a WTF, and remove this exemption + mLogWtfRule.addFailureLogExemption(log-> log.getTag().equals("FloatingCoordinator")); + // Setup setPrefBoolean(StackEducationView.PREF_STACK_EDUCATION, false); BubbleEntry bubbleEntry = createBubbleEntry(); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java index 252c70a61b86..e550e88b7bc7 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java @@ -46,6 +46,7 @@ import androidx.test.uiautomator.UiDevice; import com.android.internal.protolog.ProtoLog; import com.android.systemui.broadcast.FakeBroadcastDispatcher; import com.android.systemui.flags.SceneContainerRule; +import com.android.systemui.log.LogWtfHandlerRule; import org.junit.After; import org.junit.AfterClass; @@ -127,6 +128,8 @@ public abstract class SysuiTestCase { @Rule public final SetFlagsRule mSetFlagsRule = isRobolectricTest() ? new SetFlagsRule() : mSetFlagsClassRule.createSetFlagsRule(); + @Rule public final LogWtfHandlerRule mLogWtfRule = new LogWtfHandlerRule(); + @Rule(order = 10) public final SceneContainerRule mSceneContainerRule = new SceneContainerRule(); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CarProjectionRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CarProjectionRepositoryKosmos.kt new file mode 100644 index 000000000000..130c2987912e --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CarProjectionRepositoryKosmos.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2025 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.communal.data.repository + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.carProjectionRepository by + Kosmos.Fixture<CarProjectionRepository> { FakeCarProjectionRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCarProjectionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCarProjectionRepository.kt new file mode 100644 index 000000000000..4042342923ea --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCarProjectionRepository.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2025 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.communal.data.repository + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow + +class FakeCarProjectionRepository : CarProjectionRepository { + private val _projectionActive = MutableStateFlow(false) + override val projectionActive: Flow<Boolean> = _projectionActive.asStateFlow() + + override suspend fun isProjectionActive(): Boolean { + return _projectionActive.value + } + + fun setProjectionActive(active: Boolean) { + _projectionActive.value = active + } +} + +val CarProjectionRepository.fake + get() = this as FakeCarProjectionRepository diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CarProjectionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CarProjectionInteractorKosmos.kt new file mode 100644 index 000000000000..23bbe36203e6 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CarProjectionInteractorKosmos.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2025 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.communal.domain.interactor + +import com.android.systemui.communal.data.repository.carProjectionRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture + +val Kosmos.carProjectionInteractor by Fixture { CarProjectionInteractor(carProjectionRepository) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractorKosmos.kt new file mode 100644 index 000000000000..5735cf82cca0 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractorKosmos.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2025 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.communal.domain.interactor + +import com.android.systemui.common.domain.interactor.batteryInteractor +import com.android.systemui.communal.posturing.domain.interactor.posturingInteractor +import com.android.systemui.dock.dockManager +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.kosmos.backgroundCoroutineContext + +val Kosmos.communalAutoOpenInteractor by Fixture { + CommunalAutoOpenInteractor( + communalSettingsInteractor = communalSettingsInteractor, + backgroundContext = backgroundCoroutineContext, + batteryInteractor = batteryInteractor, + posturingInteractor = posturingInteractor, + dockManager = dockManager, + allowSwipeAlways = false, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt index b8b2ec5a58ae..316fcbb85b26 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt @@ -16,17 +16,14 @@ package com.android.systemui.communal.domain.interactor -import android.content.pm.UserInfo import android.content.testableContext import android.os.userManager import com.android.systemui.broadcast.broadcastDispatcher -import com.android.systemui.common.domain.interactor.batteryInteractor +import com.android.systemui.communal.data.model.SuppressionReason import com.android.systemui.communal.data.repository.communalMediaRepository import com.android.systemui.communal.data.repository.communalSmartspaceRepository import com.android.systemui.communal.data.repository.communalWidgetRepository -import com.android.systemui.communal.posturing.domain.interactor.posturingInteractor import com.android.systemui.communal.widgets.EditWidgetsActivityStarter -import com.android.systemui.dock.dockManager import com.android.systemui.flags.Flags import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository @@ -39,13 +36,9 @@ import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.log.logcatLogBuffer import com.android.systemui.plugins.activityStarter -import com.android.systemui.res.R import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.settings.userTracker import com.android.systemui.statusbar.phone.fakeManagedProfileController -import com.android.systemui.user.data.repository.FakeUserRepository -import com.android.systemui.user.data.repository.fakeUserRepository -import com.android.systemui.user.domain.interactor.userLockedInteractor import com.android.systemui.util.mockito.mock val Kosmos.communalInteractor by Fixture { @@ -70,10 +63,6 @@ val Kosmos.communalInteractor by Fixture { logBuffer = logcatLogBuffer("CommunalInteractor"), tableLogBuffer = mock(), managedProfileController = fakeManagedProfileController, - batteryInteractor = batteryInteractor, - dockManager = dockManager, - posturingInteractor = posturingInteractor, - userLockedInteractor = userLockedInteractor, ) } @@ -86,28 +75,28 @@ fun Kosmos.setCommunalV2ConfigEnabled(enabled: Boolean) { ) } -suspend fun Kosmos.setCommunalEnabled(enabled: Boolean): UserInfo { +fun Kosmos.setCommunalEnabled(enabled: Boolean) { fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, enabled) - return if (enabled) { - fakeUserRepository.asMainUser() - } else { - fakeUserRepository.asDefaultUser() - } + val suppressionReasons = + if (enabled) { + emptyList() + } else { + listOf(SuppressionReason.ReasonUnknown()) + } + communalSettingsInteractor.setSuppressionReasons(suppressionReasons) } -suspend fun Kosmos.setCommunalV2Enabled(enabled: Boolean): UserInfo { +fun Kosmos.setCommunalV2Enabled(enabled: Boolean) { setCommunalV2ConfigEnabled(enabled) return setCommunalEnabled(enabled) } -suspend fun Kosmos.setCommunalAvailable(available: Boolean): UserInfo { - val user = setCommunalEnabled(available) +fun Kosmos.setCommunalAvailable(available: Boolean) { + setCommunalEnabled(available) fakeKeyguardRepository.setKeyguardShowing(available) - fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, available) - return user } -suspend fun Kosmos.setCommunalV2Available(available: Boolean): UserInfo { +fun Kosmos.setCommunalV2Available(available: Boolean) { setCommunalV2ConfigEnabled(available) - return setCommunalAvailable(available) + setCommunalAvailable(available) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorKosmos.kt index fb983f7c605f..d2fbb515e686 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorKosmos.kt @@ -24,7 +24,6 @@ import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher import com.android.systemui.settings.userTracker import com.android.systemui.user.domain.interactor.selectedUserInteractor -import com.android.systemui.util.mockito.mock val Kosmos.communalSettingsInteractor by Fixture { CommunalSettingsInteractor( @@ -34,6 +33,5 @@ val Kosmos.communalSettingsInteractor by Fixture { repository = communalSettingsRepository, userInteractor = selectedUserInteractor, userTracker = userTracker, - tableLogBuffer = mock(), ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFake.java b/packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFake.java deleted file mode 100644 index b99310bcbe38..000000000000 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFake.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.dock; - -/** - * A rudimentary fake for DockManager. - */ -public class DockManagerFake implements DockManager { - DockEventListener mCallback; - AlignmentStateListener mAlignmentListener; - private boolean mDocked; - - @Override - public void addListener(DockEventListener callback) { - this.mCallback = callback; - } - - @Override - public void removeListener(DockEventListener callback) { - this.mCallback = null; - } - - @Override - public void addAlignmentStateListener(AlignmentStateListener listener) { - mAlignmentListener = listener; - } - - @Override - public void removeAlignmentStateListener(AlignmentStateListener listener) { - mAlignmentListener = listener; - } - - @Override - public boolean isDocked() { - return mDocked; - } - - /** Sets the docked state */ - public void setIsDocked(boolean docked) { - mDocked = docked; - } - - @Override - public boolean isHidden() { - return false; - } - - /** Notifies callbacks of dock state change */ - public void setDockEvent(int event) { - mCallback.onEvent(event); - } -} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFake.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFake.kt new file mode 100644 index 000000000000..6a43c40612a7 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFake.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2025 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.dock + +import com.android.systemui.dock.DockManager.AlignmentStateListener + +/** A rudimentary fake for DockManager. */ +class DockManagerFake : DockManager { + private val callbacks = mutableSetOf<DockManager.DockEventListener>() + private val alignmentListeners = mutableSetOf<AlignmentStateListener>() + private var docked = false + + override fun addListener(callback: DockManager.DockEventListener) { + callbacks.add(callback) + } + + override fun removeListener(callback: DockManager.DockEventListener) { + callbacks.remove(callback) + } + + override fun addAlignmentStateListener(listener: AlignmentStateListener) { + alignmentListeners.add(listener) + } + + override fun removeAlignmentStateListener(listener: AlignmentStateListener) { + alignmentListeners.remove(listener) + } + + override fun isDocked(): Boolean { + return docked + } + + /** Sets the docked state */ + fun setIsDocked(docked: Boolean) { + this.docked = docked + } + + override fun isHidden(): Boolean { + return false + } + + /** Notifies callbacks of dock state change */ + fun setDockEvent(event: Int) { + for (callback in callbacks) { + callback.onEvent(event) + } + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt index bdfa875f5429..9b0a9830dcc4 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt @@ -16,7 +16,6 @@ package com.android.systemui.keyguard.domain.interactor -import com.android.systemui.communal.domain.interactor.communalInteractor import com.android.systemui.communal.domain.interactor.communalSceneInteractor import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.deviceentry.data.repository.deviceEntryRepository @@ -43,6 +42,5 @@ val Kosmos.fromAodTransitionInteractor by wakeToGoneInteractor = keyguardWakeDirectlyToGoneInteractor, communalSettingsInteractor = communalSettingsInteractor, communalSceneInteractor = communalSceneInteractor, - communalInteractor = communalInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt index 985044c80f18..511bede7349b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt @@ -16,7 +16,6 @@ package com.android.systemui.keyguard.domain.interactor -import com.android.systemui.communal.domain.interactor.communalInteractor import com.android.systemui.communal.domain.interactor.communalSceneInteractor import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository @@ -42,7 +41,6 @@ var Kosmos.fromLockscreenTransitionInteractor by communalSettingsInteractor = communalSettingsInteractor, swipeToDismissInteractor = swipeToDismissInteractor, keyguardOcclusionInteractor = keyguardOcclusionInteractor, - communalInteractor = communalInteractor, communalSceneInteractor = communalSceneInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt index 255a780a84be..113059222aa2 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.domain.interactor import android.content.applicationContext +import android.os.powerManager import android.view.accessibility.accessibilityManagerWrapper import com.android.internal.logging.uiEventLogger import com.android.systemui.broadcast.broadcastDispatcher @@ -26,6 +27,8 @@ import com.android.systemui.keyguard.data.repository.keyguardRepository import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.shade.pulsingGestureListener +import com.android.systemui.util.settings.data.repository.userAwareSecureSettingsRepository +import com.android.systemui.util.time.fakeSystemClock val Kosmos.keyguardTouchHandlingInteractor by Kosmos.Fixture { @@ -40,5 +43,8 @@ val Kosmos.keyguardTouchHandlingInteractor by accessibilityManager = accessibilityManagerWrapper, pulsingGestureListener = pulsingGestureListener, faceAuthInteractor = deviceEntryFaceAuthInteractor, + secureSettingsRepository = userAwareSecureSettingsRepository, + powerManager = powerManager, + systemClock = fakeSystemClock, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt index b41ceff5f581..a42f2025cdaa 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt @@ -18,7 +18,6 @@ package com.android.systemui.log import android.util.Log import android.util.Log.TerribleFailureHandler import com.google.common.truth.Truth.assertWithMessage -import java.util.concurrent.Callable /** Asserts that [notLoggingBlock] does not make a call to [Log.wtf] */ fun <T> assertDoesNotLogWtf( @@ -65,15 +64,6 @@ fun <T> assertLogsWtf( return WtfBlockResult(caught, result) } -/** Assert that [loggingCallable] makes a call to [Log.wtf] */ -@JvmOverloads -fun <T> assertLogsWtf( - message: String = "Expected Log.wtf to be called", - allowMultiple: Boolean = false, - loggingCallable: Callable<T>, -): WtfBlockResult<T> = - assertLogsWtf(message = message, allowMultiple = allowMultiple, loggingCallable::call) - /** Assert that [loggingBlock] makes at least one call to [Log.wtf] */ @JvmOverloads fun <T> assertLogsWtfs( @@ -81,13 +71,6 @@ fun <T> assertLogsWtfs( loggingBlock: () -> T, ): WtfBlockResult<T> = assertLogsWtf(message, allowMultiple = true, loggingBlock) -/** Assert that [loggingCallable] makes at least one call to [Log.wtf] */ -@JvmOverloads -fun <T> assertLogsWtfs( - message: String = "Expected Log.wtf to be called once or more", - loggingCallable: Callable<T>, -): WtfBlockResult<T> = assertLogsWtf(message, allowMultiple = true, loggingCallable) - /** The data passed to [TerribleFailureHandler.onTerribleFailure] */ data class TerribleFailureLog( val tag: String, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeTileDetailsViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeTileDetailsViewModel.kt index 4f8d5a14e390..9457de18b3b9 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeTileDetailsViewModel.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeTileDetailsViewModel.kt @@ -18,18 +18,14 @@ package com.android.systemui.qs import com.android.systemui.plugins.qs.TileDetailsViewModel -class FakeTileDetailsViewModel(var tileSpec: String?) : TileDetailsViewModel() { +class FakeTileDetailsViewModel(var tileSpec: String?) : TileDetailsViewModel { private var _clickOnSettingsButton = 0 override fun clickOnSettingsButton() { _clickOnSettingsButton++ } - override fun getTitle(): String { - return tileSpec ?: " Fake title" - } + override val title = tileSpec ?: " Fake title" - override fun getSubTitle(): String { - return tileSpec ?: "Fake sub title" - } + override val subTitle = tileSpec ?: "Fake sub title" } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModelKosmos.kt index 75ca311689ce..4aa4a2b1a73a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModelKosmos.kt @@ -18,6 +18,7 @@ package com.android.systemui.qs.panels.ui.viewmodel.toolbar import android.content.applicationContext import com.android.systemui.classifier.domain.interactor.falsingInteractor +import com.android.systemui.development.ui.viewmodel.buildNumberViewModelFactory import com.android.systemui.globalactions.globalActionsDialogLite import com.android.systemui.kosmos.Kosmos import com.android.systemui.qs.footerActionsInteractor @@ -29,6 +30,7 @@ val Kosmos.toolbarViewModelFactory by override fun create(): ToolbarViewModel { return ToolbarViewModel( editModeButtonViewModelFactory, + buildNumberViewModelFactory, footerActionsInteractor, { globalActionsDialogLite }, falsingInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/EntryAdapterFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/EntryAdapterFactoryKosmos.kt index e99f61e7cd13..067e420b89c3 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/EntryAdapterFactoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/EntryAdapterFactoryKosmos.kt @@ -25,12 +25,13 @@ import com.android.systemui.statusbar.notification.people.peopleNotificationIden import com.android.systemui.statusbar.notification.row.icon.notificationIconStyleProvider val Kosmos.entryAdapterFactory by -Kosmos.Fixture { - EntryAdapterFactoryImpl( - mockNotificationActivityStarter, - metricsLogger, - peopleNotificationIdentifier, - notificationIconStyleProvider, - visualStabilityCoordinator, - ) -}
\ No newline at end of file + Kosmos.Fixture { + EntryAdapterFactoryImpl( + mockNotificationActivityStarter, + metricsLogger, + peopleNotificationIdentifier, + notificationIconStyleProvider, + visualStabilityCoordinator, + mockNotificationActionClickManager, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt index 7f012ba25ab9..6a674ca29ca4 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt @@ -375,6 +375,7 @@ class ExpandableNotificationRowBuilder( Mockito.mock(PeopleNotificationIdentifier::class.java), Mockito.mock(NotificationIconStyleProvider::class.java), Mockito.mock(VisualStabilityCoordinator::class.java), + Mockito.mock(NotificationActionClickManager::class.java), ) .create(entry) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/NotificationActionClickManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/NotificationActionClickManagerKosmos.kt new file mode 100644 index 000000000000..8e62ae8825f3 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/NotificationActionClickManagerKosmos.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2025 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 com.android.systemui.kosmos.Kosmos +import org.mockito.kotlin.mock + +var Kosmos.mockNotificationActionClickManager: NotificationActionClickManager by + Kosmos.Fixture { mock<NotificationActionClickManager>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/UserLockedInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/UserLockedInteractorKosmos.kt index 933c351679a4..6bb908a6ef07 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/UserLockedInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/UserLockedInteractorKosmos.kt @@ -22,5 +22,9 @@ import com.android.systemui.user.data.repository.userRepository val Kosmos.userLockedInteractor by Kosmos.Fixture { - UserLockedInteractor(backgroundDispatcher = testDispatcher, userRepository = userRepository) + UserLockedInteractor( + backgroundDispatcher = testDispatcher, + userRepository = userRepository, + selectedUserInteractor = selectedUserInteractor, + ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt index 66bb803c182d..fd90d179debc 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt @@ -29,6 +29,9 @@ import kotlinx.coroutines.flow.asStateFlow class FakeWallpaperRepository : WallpaperRepository { private val _wallpaperInfo: MutableStateFlow<WallpaperInfo?> = MutableStateFlow(null) override val wallpaperInfo: StateFlow<WallpaperInfo?> = _wallpaperInfo.asStateFlow() + private val _lockscreenWallpaperInfo: MutableStateFlow<WallpaperInfo?> = MutableStateFlow(null) + override val lockscreenWallpaperInfo: StateFlow<WallpaperInfo?> = + _lockscreenWallpaperInfo.asStateFlow() private val _wallpaperSupportsAmbientMode = MutableStateFlow(false) override val wallpaperSupportsAmbientMode: Flow<Boolean> = _wallpaperSupportsAmbientMode.asStateFlow() diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt index 1761503b2cc9..b4a44751c43b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt @@ -19,6 +19,7 @@ package com.android.systemui.wallpapers.data.repository import android.content.applicationContext import com.android.app.wallpaperManager import com.android.systemui.broadcast.broadcastDispatcher +import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.testDispatcher @@ -35,5 +36,6 @@ val Kosmos.wallpaperRepository by Fixture { userRepository = userRepository, wallpaperManager = wallpaperManager, secureSettings = fakeSettings, + configurationInteractor = configurationInteractor, ) } diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp index ccbc46fdb03b..5424ac3bd897 100644 --- a/ravenwood/Android.bp +++ b/ravenwood/Android.bp @@ -16,7 +16,7 @@ filegroup { srcs: [ "texts/ravenwood-common-policies.txt", ], - visibility: ["//visibility:private"], + visibility: [":__subpackages__"], } filegroup { @@ -44,6 +44,22 @@ filegroup { } filegroup { + name: "ravenwood-standard-annotations", + srcs: [ + "texts/ravenwood-standard-annotations.txt", + ], + visibility: [":__subpackages__"], +} + +filegroup { + name: "ravenizer-standard-options", + srcs: [ + "texts/ravenizer-standard-options.txt", + ], + visibility: [":__subpackages__"], +} + +filegroup { name: "ravenwood-annotation-allowed-classes", srcs: [ "texts/ravenwood-annotation-allowed-classes.txt", diff --git a/ravenwood/Framework.bp b/ravenwood/Framework.bp index e36677189e02..f5b075b17fd4 100644 --- a/ravenwood/Framework.bp +++ b/ravenwood/Framework.bp @@ -33,6 +33,7 @@ genrule_defaults { ":ravenwood-common-policies", ":ravenwood-framework-policies", ":ravenwood-standard-options", + ":ravenwood-standard-annotations", ":ravenwood-annotation-allowed-classes", ], out: [ @@ -44,6 +45,7 @@ genrule_defaults { framework_minus_apex_cmd = "$(location hoststubgen) " + "@$(location :ravenwood-standard-options) " + + "@$(location :ravenwood-standard-annotations) " + "--debug-log $(location hoststubgen_framework-minus-apex.log) " + "--out-jar $(location ravenwood.jar) " + "--in-jar $(location :framework-minus-apex-for-host) " + @@ -178,6 +180,7 @@ java_genrule { tools: ["hoststubgen"], cmd: "$(location hoststubgen) " + "@$(location :ravenwood-standard-options) " + + "@$(location :ravenwood-standard-annotations) " + "--debug-log $(location hoststubgen_services.core.log) " + "--stats-file $(location hoststubgen_services.core_stats.csv) " + @@ -196,6 +199,7 @@ java_genrule { ":ravenwood-common-policies", ":ravenwood-services-policies", ":ravenwood-standard-options", + ":ravenwood-standard-annotations", ":ravenwood-annotation-allowed-classes", ], out: [ @@ -247,6 +251,7 @@ java_genrule { tools: ["hoststubgen"], cmd: "$(location hoststubgen) " + "@$(location :ravenwood-standard-options) " + + "@$(location :ravenwood-standard-annotations) " + "--debug-log $(location hoststubgen_core-icu4j-for-host.log) " + "--stats-file $(location hoststubgen_core-icu4j-for-host_stats.csv) " + @@ -265,6 +270,7 @@ java_genrule { ":ravenwood-common-policies", ":icu-ravenwood-policies", ":ravenwood-standard-options", + ":ravenwood-standard-annotations", ], out: [ "ravenwood.jar", @@ -301,6 +307,7 @@ java_genrule { tools: ["hoststubgen"], cmd: "$(location hoststubgen) " + "@$(location :ravenwood-standard-options) " + + "@$(location :ravenwood-standard-annotations) " + "--debug-log $(location framework-configinfrastructure.log) " + "--stats-file $(location framework-configinfrastructure_stats.csv) " + @@ -319,6 +326,7 @@ java_genrule { ":ravenwood-common-policies", ":framework-configinfrastructure-ravenwood-policies", ":ravenwood-standard-options", + ":ravenwood-standard-annotations", ], out: [ "ravenwood.jar", @@ -355,6 +363,7 @@ java_genrule { tools: ["hoststubgen"], cmd: "$(location hoststubgen) " + "@$(location :ravenwood-standard-options) " + + "@$(location :ravenwood-standard-annotations) " + "--debug-log $(location framework-statsd.log) " + "--stats-file $(location framework-statsd_stats.csv) " + @@ -373,6 +382,7 @@ java_genrule { ":ravenwood-common-policies", ":framework-statsd-ravenwood-policies", ":ravenwood-standard-options", + ":ravenwood-standard-annotations", ], out: [ "ravenwood.jar", @@ -409,6 +419,7 @@ java_genrule { tools: ["hoststubgen"], cmd: "$(location hoststubgen) " + "@$(location :ravenwood-standard-options) " + + "@$(location :ravenwood-standard-annotations) " + "--debug-log $(location framework-graphics.log) " + "--stats-file $(location framework-graphics_stats.csv) " + @@ -427,6 +438,7 @@ java_genrule { ":ravenwood-common-policies", ":framework-graphics-ravenwood-policies", ":ravenwood-standard-options", + ":ravenwood-standard-annotations", ], out: [ "ravenwood.jar", diff --git a/ravenwood/TEST_MAPPING b/ravenwood/TEST_MAPPING index df63cb9dfc50..1148539187ac 100644 --- a/ravenwood/TEST_MAPPING +++ b/ravenwood/TEST_MAPPING @@ -150,6 +150,10 @@ "host": true }, { + "name": "RavenwoodCoreTest-light", + "host": true + }, + { "name": "RavenwoodMinimumTest", "host": true }, @@ -168,6 +172,10 @@ { "name": "RavenwoodServicesTest", "host": true + }, + { + "name": "UinputTestsRavenwood", + "host": true } // AUTO-GENERATED-END ], diff --git a/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/ravenizer/RavenwoodJdkPatchTest.java b/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/ravenizer/RavenwoodJdkPatchTest.java new file mode 100644 index 000000000000..cdfd4a877f43 --- /dev/null +++ b/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/ravenizer/RavenwoodJdkPatchTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2025 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.ravenwoodtest.bivalenttest.ravenizer; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; + +import org.junit.Test; + +import java.io.FileDescriptor; +import java.util.LinkedHashMap; +import java.util.regex.Pattern; + +public class RavenwoodJdkPatchTest { + + @Test + public void testUnicodeRegex() { + var pattern = Pattern.compile("\\w+"); + assertTrue(pattern.matcher("über").matches()); + } + + @Test + public void testLinkedHashMapEldest() { + var map = new LinkedHashMap<String, String>(); + map.put("a", "b"); + map.put("x", "y"); + assertEquals(map.entrySet().iterator().next(), map.eldest()); + } + + @Test + public void testFileDescriptorGetSetInt() throws ErrnoException { + FileDescriptor fd = Os.open("/dev/zero", OsConstants.O_RDONLY, 0); + try { + int fdRaw = fd.getInt$(); + assertNotEquals(-1, fdRaw); + fd.setInt$(-1); + assertEquals(-1, fd.getInt$()); + fd.setInt$(fdRaw); + Os.close(fd); + assertEquals(-1, fd.getInt$()); + } finally { + Os.close(fd); + } + } +} diff --git a/ravenwood/texts/ravenizer-standard-options.txt b/ravenwood/texts/ravenizer-standard-options.txt new file mode 100644 index 000000000000..cef736f87e72 --- /dev/null +++ b/ravenwood/texts/ravenizer-standard-options.txt @@ -0,0 +1,13 @@ +# File containing standard options to Ravenizer for Ravenwood + +# Keep all classes / methods / fields in tests and its target +--default-keep + +--delete-finals + +# Include standard annotations +@jar:texts/ravenwood-standard-annotations.txt + +# Apply common policies +--policy-override-file + jar:texts/ravenwood-common-policies.txt diff --git a/ravenwood/texts/ravenwood-standard-annotations.txt b/ravenwood/texts/ravenwood-standard-annotations.txt new file mode 100644 index 000000000000..75ec5cadb6fc --- /dev/null +++ b/ravenwood/texts/ravenwood-standard-annotations.txt @@ -0,0 +1,37 @@ +# Standard annotations. +# Note, each line is a single argument, so we need newlines after each `--xxx-annotation`. +--keep-annotation + android.ravenwood.annotation.RavenwoodKeep + +--keep-annotation + android.ravenwood.annotation.RavenwoodKeepPartialClass + +--keep-class-annotation + android.ravenwood.annotation.RavenwoodKeepWholeClass + +--throw-annotation + android.ravenwood.annotation.RavenwoodThrow + +--remove-annotation + android.ravenwood.annotation.RavenwoodRemove + +--ignore-annotation + android.ravenwood.annotation.RavenwoodIgnore + +--partially-allowed-annotation + android.ravenwood.annotation.RavenwoodPartiallyAllowlisted + +--substitute-annotation + android.ravenwood.annotation.RavenwoodReplace + +--redirect-annotation + android.ravenwood.annotation.RavenwoodRedirect + +--redirection-class-annotation + android.ravenwood.annotation.RavenwoodRedirectionClass + +--class-load-hook-annotation + android.ravenwood.annotation.RavenwoodClassLoadHook + +--keep-static-initializer-annotation + android.ravenwood.annotation.RavenwoodKeepStaticInitializer diff --git a/ravenwood/texts/ravenwood-standard-options.txt b/ravenwood/texts/ravenwood-standard-options.txt index 233657557747..0a650254a71f 100644 --- a/ravenwood/texts/ravenwood-standard-options.txt +++ b/ravenwood/texts/ravenwood-standard-options.txt @@ -15,41 +15,3 @@ #--default-class-load-hook # com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded - -# Standard annotations. -# Note, each line is a single argument, so we need newlines after each `--xxx-annotation`. ---keep-annotation - android.ravenwood.annotation.RavenwoodKeep - ---keep-annotation - android.ravenwood.annotation.RavenwoodKeepPartialClass - ---keep-class-annotation - android.ravenwood.annotation.RavenwoodKeepWholeClass - ---throw-annotation - android.ravenwood.annotation.RavenwoodThrow - ---remove-annotation - android.ravenwood.annotation.RavenwoodRemove - ---ignore-annotation - android.ravenwood.annotation.RavenwoodIgnore - ---partially-allowed-annotation - android.ravenwood.annotation.RavenwoodPartiallyAllowlisted - ---substitute-annotation - android.ravenwood.annotation.RavenwoodReplace - ---redirect-annotation - android.ravenwood.annotation.RavenwoodRedirect - ---redirection-class-annotation - android.ravenwood.annotation.RavenwoodRedirectionClass - ---class-load-hook-annotation - android.ravenwood.annotation.RavenwoodClassLoadHook - ---keep-static-initializer-annotation - android.ravenwood.annotation.RavenwoodKeepStaticInitializer diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/Exceptions.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/Exceptions.kt index f59e143c1e4e..ae0a00855650 100644 --- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/Exceptions.kt +++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/Exceptions.kt @@ -15,8 +15,6 @@ */ package com.android.hoststubgen -import java.io.File - /** * We will not print the stack trace for exceptions implementing it. */ @@ -64,9 +62,6 @@ class DuplicateAnnotationException(annotationName: String?) : class InputFileNotFoundException(filename: String) : ArgumentsException("File '$filename' not found") -fun String.ensureFileExists(): String { - if (!File(this).exists()) { - throw InputFileNotFoundException(this) - } - return this -} +/** Thrown when a JAR resource does not exist. */ +class JarResourceNotFoundException(path: String) : + ArgumentsException("JAR resource '$path' not found") diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessor.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessor.kt index 4fe21eac6972..98f96a89d889 100644 --- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessor.kt +++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessor.kt @@ -16,6 +16,7 @@ package com.android.hoststubgen import com.android.hoststubgen.asm.ClassNodes +import com.android.hoststubgen.asm.findAnyAnnotation import com.android.hoststubgen.filters.AnnotationBasedFilter import com.android.hoststubgen.filters.ClassWidePolicyPropagatingFilter import com.android.hoststubgen.filters.ConstantFilter @@ -26,21 +27,25 @@ import com.android.hoststubgen.filters.KeepNativeFilter import com.android.hoststubgen.filters.OutputFilter import com.android.hoststubgen.filters.SanitizationFilter import com.android.hoststubgen.filters.TextFileFilterPolicyBuilder +import com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep import com.android.hoststubgen.utils.ClassPredicate import com.android.hoststubgen.visitors.BaseAdapter +import com.android.hoststubgen.visitors.ImplGeneratingAdapter import com.android.hoststubgen.visitors.PackageRedirectRemapper +import java.io.PrintWriter import org.objectweb.asm.ClassReader import org.objectweb.asm.ClassVisitor import org.objectweb.asm.ClassWriter import org.objectweb.asm.commons.ClassRemapper import org.objectweb.asm.util.CheckClassAdapter +import org.objectweb.asm.util.TraceClassVisitor /** * This class implements bytecode transformation of HostStubGen. */ class HostStubGenClassProcessor( private val options: HostStubGenClassProcessorOptions, - private val allClasses: ClassNodes, + val allClasses: ClassNodes, private val errors: HostStubGenErrors = HostStubGenErrors(), private val stats: HostStubGenStats? = null, ) { @@ -48,6 +53,7 @@ class HostStubGenClassProcessor( val remapper = FilterRemapper(filter) private val packageRedirector = PackageRedirectRemapper(options.packageRedirects) + private val processedAnnotation = setOf(HostStubGenProcessedAsKeep.CLASS_DESCRIPTOR) /** * Build the filter, which decides what classes/methods/fields should be put in stub or impl @@ -130,15 +136,10 @@ class HostStubGenClassProcessor( return filter } - fun processClassBytecode(bytecode: ByteArray): ByteArray { - val cr = ClassReader(bytecode) - - // COMPUTE_FRAMES wouldn't be happy if code uses - val flags = ClassWriter.COMPUTE_MAXS // or ClassWriter.COMPUTE_FRAMES - val cw = ClassWriter(flags) + private fun buildVisitor(base: ClassVisitor, className: String): ClassVisitor { + // Connect to the base visitor + var outVisitor: ClassVisitor = base - // Connect to the class writer - var outVisitor: ClassVisitor = cw if (options.enableClassChecker.get) { outVisitor = CheckClassAdapter(outVisitor) } @@ -149,15 +150,59 @@ class HostStubGenClassProcessor( val visitorOptions = BaseAdapter.Options( errors = errors, stats = stats, - enablePreTrace = options.enablePreTrace.get, - enablePostTrace = options.enablePostTrace.get, deleteClassFinals = options.deleteFinals.get, deleteMethodFinals = options.deleteFinals.get, ) - outVisitor = BaseAdapter.getVisitor( - cr.className, allClasses, outVisitor, filter, - packageRedirector, visitorOptions - ) + + val verbosePrinter = PrintWriter(log.getWriter(LogLevel.Verbose)) + + // Inject TraceClassVisitor for debugging. + if (options.enablePostTrace.get) { + outVisitor = TraceClassVisitor(outVisitor, verbosePrinter) + } + + // Handle --package-redirect + if (!packageRedirector.isEmpty) { + // Don't apply the remapper on redirect-from classes. + // Otherwise, if the target jar actually contains the "from" classes (which + // may or may not be the case) they'd be renamed. + // But we update all references in other places, so, a method call to a "from" class + // would be replaced with the "to" class. All type references (e.g. variable types) + // will be updated too. + if (!packageRedirector.isTarget(className)) { + outVisitor = ClassRemapper(outVisitor, packageRedirector) + } else { + log.v( + "Class $className is a redirect-from class, not applying" + + " --package-redirect" + ) + } + } + + outVisitor = ImplGeneratingAdapter(allClasses, outVisitor, filter, visitorOptions) + + // Inject TraceClassVisitor for debugging. + if (options.enablePreTrace.get) { + outVisitor = TraceClassVisitor(outVisitor, verbosePrinter) + } + + return outVisitor + } + + fun processClassBytecode(bytecode: ByteArray): ByteArray { + val cr = ClassReader(bytecode) + + // If the class was already processed previously, skip + val clz = allClasses.getClass(cr.className) + if (clz.findAnyAnnotation(processedAnnotation) != null) { + return bytecode + } + + // COMPUTE_FRAMES wouldn't be happy if code uses + val flags = ClassWriter.COMPUTE_MAXS // or ClassWriter.COMPUTE_FRAMES + val cw = ClassWriter(flags) + + val outVisitor = buildVisitor(cw, cr.className) cr.accept(outVisitor, ClassReader.EXPAND_FRAMES) return cw.toByteArray() diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessorOptions.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessorOptions.kt index c7c45e65a8b6..e7166f11f597 100644 --- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessorOptions.kt +++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessorOptions.kt @@ -18,6 +18,7 @@ package com.android.hoststubgen import com.android.hoststubgen.filters.FilterPolicy import com.android.hoststubgen.utils.ArgIterator import com.android.hoststubgen.utils.BaseOptions +import com.android.hoststubgen.utils.FileOrResource import com.android.hoststubgen.utils.SetOnce private fun parsePackageRedirect(fromColonTo: String): Pair<String, String> { @@ -53,7 +54,7 @@ open class HostStubGenClassProcessorOptions( var defaultClassLoadHook: SetOnce<String?> = SetOnce(null), var defaultMethodCallHook: SetOnce<String?> = SetOnce(null), - var policyOverrideFiles: MutableList<String> = mutableListOf(), + var policyOverrideFiles: MutableList<FileOrResource> = mutableListOf(), var defaultPolicy: SetOnce<FilterPolicy> = SetOnce(FilterPolicy.Remove), @@ -73,15 +74,14 @@ open class HostStubGenClassProcessorOptions( return name } - override fun parseOption(option: String, ai: ArgIterator): Boolean { + override fun parseOption(option: String, args: ArgIterator): Boolean { // Define some shorthands... - fun nextArg(): String = ai.nextArgRequired(option) + fun nextArg(): String = args.nextArgRequired(option) fun MutableSet<String>.addUniqueAnnotationArg(): String = nextArg().also { this += ensureUniqueAnnotation(it) } when (option) { - "--policy-override-file" -> - policyOverrideFiles.add(nextArg().ensureFileExists()) + "--policy-override-file" -> policyOverrideFiles.add(FileOrResource(nextArg())) "--default-remove" -> defaultPolicy.set(FilterPolicy.Remove) "--default-throw" -> defaultPolicy.set(FilterPolicy.Throw) diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/asm/AsmUtils.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/asm/AsmUtils.kt index b41ce0f65017..112ef01e20cb 100644 --- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/asm/AsmUtils.kt +++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/asm/AsmUtils.kt @@ -217,7 +217,7 @@ private val numericalInnerClassName = """.*\$\d+$""".toRegex() fun isAnonymousInnerClass(cn: ClassNode): Boolean { // TODO: Is there a better way? - return cn.name.matches(numericalInnerClassName) + return cn.outerClass != null && cn.name.matches(numericalInnerClassName) } /** diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/DelegatingFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/DelegatingFilter.kt index b8b0d8a31268..7f36aca33eee 100644 --- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/DelegatingFilter.kt +++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/DelegatingFilter.kt @@ -19,9 +19,9 @@ package com.android.hoststubgen.filters * Base class for an [OutputFilter] that uses another filter as a fallback. */ abstract class DelegatingFilter( - // fallback shouldn't be used by subclasses directly, so make it private. - // They should instead be calling into `super` or `outermostFilter`. - private val fallback: OutputFilter + // fallback shouldn't be used by subclasses directly, so make it private. + // They should instead be calling into `super` or `outermostFilter`. + private val fallback: OutputFilter ) : OutputFilter() { init { fallback.outermostFilter = this @@ -50,24 +50,24 @@ abstract class DelegatingFilter( } override fun getPolicyForField( - className: String, - fieldName: String + className: String, + fieldName: String ): FilterPolicyWithReason { return fallback.getPolicyForField(className, fieldName) } override fun getPolicyForMethod( - className: String, - methodName: String, - descriptor: String + className: String, + methodName: String, + descriptor: String ): FilterPolicyWithReason { return fallback.getPolicyForMethod(className, methodName, descriptor) } override fun getRenameTo( - className: String, - methodName: String, - descriptor: String + className: String, + methodName: String, + descriptor: String ): String? { return fallback.getRenameTo(className, methodName, descriptor) } @@ -97,13 +97,12 @@ abstract class DelegatingFilter( } override fun getMethodCallReplaceTo( - callerClassName: String, - callerMethodName: String, className: String, methodName: String, descriptor: String, ): MethodReplaceTarget? { return fallback.getMethodCallReplaceTo( - callerClassName, callerMethodName, className, methodName, descriptor) + className, methodName, descriptor + ) } } diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ImplicitOutputFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ImplicitOutputFilter.kt index 474da6dfa1b9..d44d016f7c5b 100644 --- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ImplicitOutputFilter.kt +++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ImplicitOutputFilter.kt @@ -16,7 +16,6 @@ package com.android.hoststubgen.filters import com.android.hoststubgen.HostStubGenErrors -import com.android.hoststubgen.HostStubGenInternalException import com.android.hoststubgen.asm.CLASS_INITIALIZER_DESC import com.android.hoststubgen.asm.CLASS_INITIALIZER_NAME import com.android.hoststubgen.asm.ClassNodes @@ -37,19 +36,15 @@ import org.objectweb.asm.tree.ClassNode * TODO: Do we need a way to make anonymous class methods and lambdas "throw"? */ class ImplicitOutputFilter( - private val errors: HostStubGenErrors, - private val classes: ClassNodes, - fallback: OutputFilter + private val errors: HostStubGenErrors, + private val classes: ClassNodes, + fallback: OutputFilter ) : DelegatingFilter(fallback) { - private fun getClassImplicitPolicy(className: String, cn: ClassNode): FilterPolicyWithReason? { + private fun getClassImplicitPolicy(cn: ClassNode): FilterPolicyWithReason? { if (isAnonymousInnerClass(cn)) { log.forDebug { // log.d(" anon-inner class: ${className} outer: ${cn.outerClass} ") } - if (cn.outerClass == null) { - throw HostStubGenInternalException( - "outerClass is null for anonymous inner class") - } // If the outer class needs to be in impl, it should be in impl too. val outerPolicy = outermostFilter.getPolicyForClass(cn.outerClass) if (outerPolicy.policy.needsInOutput) { @@ -65,15 +60,15 @@ class ImplicitOutputFilter( val cn = classes.getClass(className) // Use the implicit policy, if any. - getClassImplicitPolicy(className, cn)?.let { return it } + getClassImplicitPolicy(cn)?.let { return it } return fallback } override fun getPolicyForMethod( - className: String, - methodName: String, - descriptor: String + className: String, + methodName: String, + descriptor: String ): FilterPolicyWithReason { val fallback = super.getPolicyForMethod(className, methodName, descriptor) val classPolicy = outermostFilter.getPolicyForClass(className) @@ -84,12 +79,14 @@ class ImplicitOutputFilter( // "keep" instead. // Unless it's an enum -- in that case, the below code would handle it. if (!cn.isEnum() && - fallback.policy == FilterPolicy.Throw && - methodName == CLASS_INITIALIZER_NAME && descriptor == CLASS_INITIALIZER_DESC) { + fallback.policy == FilterPolicy.Throw && + methodName == CLASS_INITIALIZER_NAME && descriptor == CLASS_INITIALIZER_DESC + ) { // TODO Maybe show a warning?? But that'd be too noisy with --default-throw. return FilterPolicy.Ignore.withReason( "'throw' on static initializer is handled as 'ignore'" + - " [original throw reason: ${fallback.reason}]") + " [original throw reason: ${fallback.reason}]" + ) } log.d("Class ${cn.name} Class policy: $classPolicy") @@ -120,7 +117,8 @@ class ImplicitOutputFilter( // For synthetic methods (such as lambdas), let's just inherit the class's // policy. return memberPolicy.withReason(classPolicy.reason).wrapReason( - "is-synthetic-method") + "is-synthetic-method" + ) } } } @@ -129,8 +127,8 @@ class ImplicitOutputFilter( } override fun getPolicyForField( - className: String, - fieldName: String + className: String, + fieldName: String ): FilterPolicyWithReason { val fallback = super.getPolicyForField(className, fieldName) @@ -161,4 +159,4 @@ class ImplicitOutputFilter( return fallback } -}
\ No newline at end of file +} diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/InMemoryOutputFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/InMemoryOutputFilter.kt index fc885d6f463b..59da3da99ea5 100644 --- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/InMemoryOutputFilter.kt +++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/InMemoryOutputFilter.kt @@ -28,10 +28,12 @@ class InMemoryOutputFilter( private val classes: ClassNodes, fallback: OutputFilter, ) : DelegatingFilter(fallback) { - private val mPolicies: MutableMap<String, FilterPolicyWithReason> = mutableMapOf() - private val mRenames: MutableMap<String, String> = mutableMapOf() - private val mRedirectionClasses: MutableMap<String, String> = mutableMapOf() - private val mClassLoadHooks: MutableMap<String, String> = mutableMapOf() + private val mPolicies = mutableMapOf<String, FilterPolicyWithReason>() + private val mRenames = mutableMapOf<String, String>() + private val mRedirectionClasses = mutableMapOf<String, String>() + private val mClassLoadHooks = mutableMapOf<String, String>() + private val mMethodCallReplaceSpecs = mutableListOf<MethodCallReplaceSpec>() + private val mTypeRenameSpecs = mutableListOf<TypeRenameSpec>() private fun getClassKey(className: String): String { return className.toHumanReadableClassName() @@ -45,10 +47,6 @@ class InMemoryOutputFilter( return getClassKey(className) + "." + methodName + ";" + signature } - override fun getPolicyForClass(className: String): FilterPolicyWithReason { - return mPolicies[getClassKey(className)] ?: super.getPolicyForClass(className) - } - private fun checkClass(className: String) { if (classes.findClass(className) == null) { log.w("Unknown class $className") @@ -74,6 +72,10 @@ class InMemoryOutputFilter( } } + override fun getPolicyForClass(className: String): FilterPolicyWithReason { + return mPolicies[getClassKey(className)] ?: super.getPolicyForClass(className) + } + fun setPolicyForClass(className: String, policy: FilterPolicyWithReason) { checkClass(className) mPolicies[getClassKey(className)] = policy @@ -81,7 +83,7 @@ class InMemoryOutputFilter( override fun getPolicyForField(className: String, fieldName: String): FilterPolicyWithReason { return mPolicies[getFieldKey(className, fieldName)] - ?: super.getPolicyForField(className, fieldName) + ?: super.getPolicyForField(className, fieldName) } fun setPolicyForField(className: String, fieldName: String, policy: FilterPolicyWithReason) { @@ -90,21 +92,21 @@ class InMemoryOutputFilter( } override fun getPolicyForMethod( - className: String, - methodName: String, - descriptor: String, - ): FilterPolicyWithReason { + className: String, + methodName: String, + descriptor: String, + ): FilterPolicyWithReason { return mPolicies[getMethodKey(className, methodName, descriptor)] ?: mPolicies[getMethodKey(className, methodName, "*")] ?: super.getPolicyForMethod(className, methodName, descriptor) } fun setPolicyForMethod( - className: String, - methodName: String, - descriptor: String, - policy: FilterPolicyWithReason, - ) { + className: String, + methodName: String, + descriptor: String, + policy: FilterPolicyWithReason, + ) { checkMethod(className, methodName, descriptor) mPolicies[getMethodKey(className, methodName, descriptor)] = policy } @@ -123,7 +125,7 @@ class InMemoryOutputFilter( override fun getRedirectionClass(className: String): String? { return mRedirectionClasses[getClassKey(className)] - ?: super.getRedirectionClass(className) + ?: super.getRedirectionClass(className) } fun setRedirectionClass(from: String, to: String) { @@ -135,11 +137,52 @@ class InMemoryOutputFilter( } override fun getClassLoadHooks(className: String): List<String> { - return addNonNullElement(super.getClassLoadHooks(className), - mClassLoadHooks[getClassKey(className)]) + return addNonNullElement( + super.getClassLoadHooks(className), + mClassLoadHooks[getClassKey(className)] + ) } fun setClassLoadHook(className: String, methodName: String) { mClassLoadHooks[getClassKey(className)] = methodName.toHumanReadableMethodName() } + + override fun hasAnyMethodCallReplace(): Boolean { + return mMethodCallReplaceSpecs.isNotEmpty() || super.hasAnyMethodCallReplace() + } + + override fun getMethodCallReplaceTo( + className: String, + methodName: String, + descriptor: String, + ): MethodReplaceTarget? { + // Maybe use 'Tri' if we end up having too many replacements. + mMethodCallReplaceSpecs.forEach { + if (className == it.fromClass && + methodName == it.fromMethod + ) { + if (it.fromDescriptor == "*" || descriptor == it.fromDescriptor) { + return MethodReplaceTarget(it.toClass, it.toMethod) + } + } + } + return super.getMethodCallReplaceTo(className, methodName, descriptor) + } + + fun setMethodCallReplaceSpec(spec: MethodCallReplaceSpec) { + mMethodCallReplaceSpecs.add(spec) + } + + override fun remapType(className: String): String? { + mTypeRenameSpecs.forEach { + if (it.typeInternalNamePattern.matcher(className).matches()) { + return it.typeInternalNamePrefix + className + } + } + return super.remapType(className) + } + + fun setRemapTypeSpec(spec: TypeRenameSpec) { + mTypeRenameSpecs.add(spec) + } } diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/OutputFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/OutputFilter.kt index f99ce906240a..c47bb302920f 100644 --- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/OutputFilter.kt +++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/OutputFilter.kt @@ -41,10 +41,10 @@ abstract class OutputFilter { abstract fun getPolicyForField(className: String, fieldName: String): FilterPolicyWithReason abstract fun getPolicyForMethod( - className: String, - methodName: String, - descriptor: String, - ): FilterPolicyWithReason + className: String, + methodName: String, + descriptor: String, + ): FilterPolicyWithReason /** * If a given method is a substitute-from method, return the substitute-to method name. @@ -108,8 +108,6 @@ abstract class OutputFilter { * If a method call should be forwarded to another method, return the target's class / method. */ open fun getMethodCallReplaceTo( - callerClassName: String, - callerMethodName: String, className: String, methodName: String, descriptor: String, diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt index dd353e9caeff..97fc35302528 100644 --- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt +++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt @@ -22,13 +22,13 @@ import com.android.hoststubgen.asm.toHumanReadableClassName import com.android.hoststubgen.asm.toJvmClassName import com.android.hoststubgen.log import com.android.hoststubgen.normalizeTextLine +import com.android.hoststubgen.utils.FileOrResource import com.android.hoststubgen.whitespaceRegex -import org.objectweb.asm.tree.ClassNode import java.io.BufferedReader -import java.io.FileReader import java.io.PrintWriter import java.io.Reader import java.util.regex.Pattern +import org.objectweb.asm.tree.ClassNode /** * Print a class node as a "keep" policy. @@ -58,6 +58,23 @@ enum class SpecialClass { RFile, } +data class MethodCallReplaceSpec( + val fromClass: String, + val fromMethod: String, + val fromDescriptor: String, + val toClass: String, + val toMethod: String, +) + +/** + * When a package name matches [typeInternalNamePattern], we prepend [typeInternalNamePrefix] + * to it. + */ +data class TypeRenameSpec( + val typeInternalNamePattern: Pattern, + val typeInternalNamePrefix: String, +) + /** * This receives [TextFileFilterPolicyBuilder] parsing result. */ @@ -99,7 +116,7 @@ interface PolicyFileProcessor { className: String, methodName: String, methodDesc: String, - replaceSpec: TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec, + replaceSpec: MethodCallReplaceSpec, ) } @@ -116,9 +133,6 @@ class TextFileFilterPolicyBuilder( private var featureFlagsPolicy: FilterPolicyWithReason? = null private var syspropsPolicy: FilterPolicyWithReason? = null private var rFilePolicy: FilterPolicyWithReason? = null - private val typeRenameSpec = mutableListOf<TextFilePolicyRemapperFilter.TypeRenameSpec>() - private val methodReplaceSpec = - mutableListOf<TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec>() /** * Fields for a filter chain used for "partial allowlisting", which are used by @@ -126,47 +140,34 @@ class TextFileFilterPolicyBuilder( */ private val annotationAllowedInMemoryFilter: InMemoryOutputFilter val annotationAllowedMembersFilter: OutputFilter + get() = annotationAllowedInMemoryFilter private val annotationAllowedPolicy = FilterPolicy.AnnotationAllowed.withReason(FILTER_REASON) init { // Create a filter that checks "partial allowlisting". - var aaf: OutputFilter = ConstantFilter(FilterPolicy.Remove, "default disallowed") - - aaf = InMemoryOutputFilter(classes, aaf) - annotationAllowedInMemoryFilter = aaf - - annotationAllowedMembersFilter = annotationAllowedInMemoryFilter + val filter = ConstantFilter(FilterPolicy.Remove, "default disallowed") + annotationAllowedInMemoryFilter = InMemoryOutputFilter(classes, filter) } /** * Parse a given policy file. This method can be called multiple times to read from * multiple files. To get the resulting filter, use [createOutputFilter] */ - fun parse(file: String) { + fun parse(file: FileOrResource) { // We may parse multiple files, but we reuse the same parser, because the parser // will make sure there'll be no dupplicating "special class" policies. - parser.parse(FileReader(file), file, Processor()) + parser.parse(file.open(), file.path, Processor()) } /** * Generate the resulting [OutputFilter]. */ fun createOutputFilter(): OutputFilter { - var ret: OutputFilter = imf - if (typeRenameSpec.isNotEmpty()) { - ret = TextFilePolicyRemapperFilter(typeRenameSpec, ret) - } - if (methodReplaceSpec.isNotEmpty()) { - ret = TextFilePolicyMethodReplaceFilter(methodReplaceSpec, classes, ret) - } - // Wrap the in-memory-filter with AHF. - ret = AndroidHeuristicsFilter( - classes, aidlPolicy, featureFlagsPolicy, syspropsPolicy, rFilePolicy, ret + return AndroidHeuristicsFilter( + classes, aidlPolicy, featureFlagsPolicy, syspropsPolicy, rFilePolicy, imf ) - - return ret } private inner class Processor : PolicyFileProcessor { @@ -180,9 +181,7 @@ class TextFileFilterPolicyBuilder( } override fun onRename(pattern: Pattern, prefix: String) { - typeRenameSpec += TextFilePolicyRemapperFilter.TypeRenameSpec( - pattern, prefix - ) + imf.setRemapTypeSpec(TypeRenameSpec(pattern, prefix)) } override fun onClassStart(className: String) { @@ -284,12 +283,12 @@ class TextFileFilterPolicyBuilder( className: String, methodName: String, methodDesc: String, - replaceSpec: TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec, + replaceSpec: MethodCallReplaceSpec, ) { // Keep the source method, because the target method may call it. imf.setPolicyForMethod(className, methodName, methodDesc, FilterPolicy.Keep.withReason(FILTER_REASON)) - methodReplaceSpec.add(replaceSpec) + imf.setMethodCallReplaceSpec(replaceSpec) } } } @@ -630,13 +629,13 @@ class TextFileFilterPolicyParser { if (classAndMethod != null) { // If the substitution target contains a ".", then // it's a method call redirect. - val spec = TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec( - currentClassName!!.toJvmClassName(), - methodName, - signature, - classAndMethod.first.toJvmClassName(), - classAndMethod.second, - ) + val spec = MethodCallReplaceSpec( + className.toJvmClassName(), + methodName, + signature, + classAndMethod.first.toJvmClassName(), + classAndMethod.second, + ) processor.onMethodOutClassReplace( className, methodName, diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFilePolicyMethodReplaceFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFilePolicyMethodReplaceFilter.kt deleted file mode 100644 index a3f934cacc2c..000000000000 --- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFilePolicyMethodReplaceFilter.kt +++ /dev/null @@ -1,60 +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.hoststubgen.filters - -import com.android.hoststubgen.asm.ClassNodes - -/** - * Filter used by TextFileFilterPolicyParser for "method call relacement". - */ -class TextFilePolicyMethodReplaceFilter( - val spec: List<MethodCallReplaceSpec>, - val classes: ClassNodes, - val fallback: OutputFilter, -) : DelegatingFilter(fallback) { - - data class MethodCallReplaceSpec( - val fromClass: String, - val fromMethod: String, - val fromDescriptor: String, - val toClass: String, - val toMethod: String, - ) - - override fun hasAnyMethodCallReplace(): Boolean { - return true - } - - override fun getMethodCallReplaceTo( - callerClassName: String, - callerMethodName: String, - className: String, - methodName: String, - descriptor: String, - ): MethodReplaceTarget? { - // Maybe use 'Tri' if we end up having too many replacements. - spec.forEach { - if (className == it.fromClass && - methodName == it.fromMethod - ) { - if (it.fromDescriptor == "*" || descriptor == it.fromDescriptor) { - return MethodReplaceTarget(it.toClass, it.toMethod) - } - } - } - return null - } -} diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt deleted file mode 100644 index bc90d1248322..000000000000 --- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt +++ /dev/null @@ -1,44 +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.hoststubgen.filters - -import java.util.regex.Pattern - -/** - * A filter that provides a simple "jarjar" functionality via [mapType] - */ -class TextFilePolicyRemapperFilter( - val typeRenameSpecs: List<TypeRenameSpec>, - fallback: OutputFilter, -) : DelegatingFilter(fallback) { - /** - * When a package name matches [typeInternalNamePattern], we prepend [typeInternalNamePrefix] - * to it. - */ - data class TypeRenameSpec( - val typeInternalNamePattern: Pattern, - val typeInternalNamePrefix: String, - ) - - override fun remapType(className: String): String? { - typeRenameSpecs.forEach { - if (it.typeInternalNamePattern.matcher(className).matches()) { - return it.typeInternalNamePrefix + className - } - } - return null - } -} diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/utils/OptionUtils.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/utils/OptionUtils.kt index 0b17879b862c..d0869929edfb 100644 --- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/utils/OptionUtils.kt +++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/utils/OptionUtils.kt @@ -16,11 +16,16 @@ package com.android.hoststubgen.utils import com.android.hoststubgen.ArgumentsException -import com.android.hoststubgen.ensureFileExists +import com.android.hoststubgen.InputFileNotFoundException +import com.android.hoststubgen.JarResourceNotFoundException import com.android.hoststubgen.log import com.android.hoststubgen.normalizeTextLine -import java.io.BufferedReader +import java.io.File import java.io.FileReader +import java.io.InputStreamReader +import java.io.Reader + +const val JAR_RESOURCE_PREFIX = "jar:" /** * Base class for parsing arguments from commandline. @@ -73,7 +78,7 @@ abstract class BaseOptions { * * Subclasses override/extend this method to support more options. */ - abstract fun parseOption(option: String, ai: ArgIterator): Boolean + abstract fun parseOption(option: String, args: ArgIterator): Boolean abstract fun dumpFields(): String } @@ -112,7 +117,9 @@ class ArgIterator( companion object { fun withAtFiles(args: List<String>): ArgIterator { - return ArgIterator(expandAtFiles(args)) + val expanded = mutableListOf<String>() + expandAtFiles(args.asSequence(), expanded) + return ArgIterator(expanded) } /** @@ -125,34 +132,30 @@ class ArgIterator( * * The file can contain '#' as comments. */ - private fun expandAtFiles(args: List<String>): List<String> { - val ret = mutableListOf<String>() - + private fun expandAtFiles(args: Sequence<String>, out: MutableList<String>) { args.forEach { arg -> if (arg.startsWith("@@")) { - ret += arg.substring(1) + out.add(arg.substring(1)) return@forEach } else if (!arg.startsWith('@')) { - ret += arg + out.add(arg) return@forEach } + // Read from the file, and add each line to the result. - val filename = arg.substring(1).ensureFileExists() + val file = FileOrResource(arg.substring(1)) - log.v("Expanding options file $filename") + log.v("Expanding options file ${file.path}") - BufferedReader(FileReader(filename)).use { reader -> - while (true) { - var line = reader.readLine() ?: break // EOF + val fileArgs = file + .open() + .buffered() + .lineSequence() + .map(::normalizeTextLine) + .filter(CharSequence::isNotEmpty) - line = normalizeTextLine(line) - if (line.isNotEmpty()) { - ret += line - } - } - } + expandAtFiles(fileArgs, out) } - return ret } } } @@ -204,3 +207,37 @@ class IntSetOnce(value: Int) : SetOnce<Int>(value) { } } } + +/** + * A path either points to a file in filesystem, or an entry in the JAR. + */ +class FileOrResource(val path: String) { + init { + path.ensureFileExists() + } + + /** + * Either read from filesystem, or read from JAR resources. + */ + fun open(): Reader { + return if (path.startsWith(JAR_RESOURCE_PREFIX)) { + val path = path.removePrefix(JAR_RESOURCE_PREFIX) + InputStreamReader(this::class.java.classLoader.getResourceAsStream(path)!!) + } else { + FileReader(path) + } + } +} + +fun String.ensureFileExists(): String { + if (this.startsWith(JAR_RESOURCE_PREFIX)) { + val cl = FileOrResource::class.java.classLoader + val path = this.removePrefix(JAR_RESOURCE_PREFIX) + if (cl.getResource(path) == null) { + throw JarResourceNotFoundException(path) + } + } else if (!File(this).exists()) { + throw InputFileNotFoundException(this) + } + return this +} diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/BaseAdapter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/BaseAdapter.kt index a08d1d605949..769b769d7a20 100644 --- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/BaseAdapter.kt +++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/BaseAdapter.kt @@ -17,7 +17,6 @@ package com.android.hoststubgen.visitors import com.android.hoststubgen.HostStubGenErrors import com.android.hoststubgen.HostStubGenStats -import com.android.hoststubgen.LogLevel import com.android.hoststubgen.asm.ClassNodes import com.android.hoststubgen.asm.UnifiedVisitor import com.android.hoststubgen.asm.getPackageNameFromFullClassName @@ -26,13 +25,10 @@ import com.android.hoststubgen.filters.FilterPolicyWithReason import com.android.hoststubgen.filters.OutputFilter import com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep import com.android.hoststubgen.log -import java.io.PrintWriter import org.objectweb.asm.ClassVisitor import org.objectweb.asm.FieldVisitor import org.objectweb.asm.MethodVisitor import org.objectweb.asm.Opcodes -import org.objectweb.asm.commons.ClassRemapper -import org.objectweb.asm.util.TraceClassVisitor const val OPCODE_VERSION = Opcodes.ASM9 @@ -49,8 +45,6 @@ abstract class BaseAdapter( data class Options( val errors: HostStubGenErrors, val stats: HostStubGenStats?, - val enablePreTrace: Boolean, - val enablePostTrace: Boolean, val deleteClassFinals: Boolean, val deleteMethodFinals: Boolean, // We don't remove finals from fields, because final fields have a stronger memory @@ -253,50 +247,4 @@ abstract class BaseAdapter( substituted: Boolean, superVisitor: MethodVisitor?, ): MethodVisitor? - - companion object { - fun getVisitor( - classInternalName: String, - classes: ClassNodes, - nextVisitor: ClassVisitor, - filter: OutputFilter, - packageRedirector: PackageRedirectRemapper, - options: Options, - ): ClassVisitor { - var next = nextVisitor - - val verbosePrinter = PrintWriter(log.getWriter(LogLevel.Verbose)) - - // Inject TraceClassVisitor for debugging. - if (options.enablePostTrace) { - next = TraceClassVisitor(next, verbosePrinter) - } - - // Handle --package-redirect - if (!packageRedirector.isEmpty) { - // Don't apply the remapper on redirect-from classes. - // Otherwise, if the target jar actually contains the "from" classes (which - // may or may not be the case) they'd be renamed. - // But we update all references in other places, so, a method call to a "from" class - // would be replaced with the "to" class. All type references (e.g. variable types) - // will be updated too. - if (!packageRedirector.isTarget(classInternalName)) { - next = ClassRemapper(next, packageRedirector) - } else { - log.v( - "Class $classInternalName is a redirect-from class, not applying" + - " --package-redirect" - ) - } - } - - next = ImplGeneratingAdapter(classes, next, filter, options) - - // Inject TraceClassVisitor for debugging. - if (options.enablePreTrace) { - next = TraceClassVisitor(next, verbosePrinter) - } - return next - } - } } diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt index b8a357668c2b..617385ad438e 100644 --- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt +++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt @@ -396,7 +396,7 @@ class ImplGeneratingAdapter( } val to = filter.getMethodCallReplaceTo( - currentClassName, callerMethodName, owner, name, descriptor + owner, name, descriptor ) if (to == null diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt index 8bb454fa12e7..d9cc54aebf51 100644 --- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt +++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt @@ -18,6 +18,7 @@ package com.android.hoststubgen import com.android.hoststubgen.utils.ArgIterator import com.android.hoststubgen.utils.IntSetOnce import com.android.hoststubgen.utils.SetOnce +import com.android.hoststubgen.utils.ensureFileExists /** * Options that can be set from command line arguments. @@ -61,9 +62,9 @@ class HostStubGenOptions( } } - override fun parseOption(option: String, ai: ArgIterator): Boolean { + override fun parseOption(option: String, args: ArgIterator): Boolean { // Define some shorthands... - fun nextArg(): String = ai.nextArgRequired(option) + fun nextArg(): String = args.nextArgRequired(option) when (option) { // TODO: Write help @@ -94,7 +95,7 @@ class HostStubGenOptions( } } - else -> return super.parseOption(option, ai) + else -> return super.parseOption(option, args) } return true diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaOptions.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaOptions.kt index f7fd0804c151..58bd9e987fd1 100644 --- a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaOptions.kt +++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaOptions.kt @@ -16,10 +16,10 @@ package com.android.platform.test.ravenwood.ravenhelper.policytoannot import com.android.hoststubgen.ArgumentsException -import com.android.hoststubgen.ensureFileExists import com.android.hoststubgen.utils.ArgIterator import com.android.hoststubgen.utils.BaseOptions import com.android.hoststubgen.utils.SetOnce +import com.android.hoststubgen.utils.ensureFileExists /** * Options for the "ravenhelper pta" subcommand. @@ -41,8 +41,8 @@ class PtaOptions( var dumpOperations: SetOnce<Boolean> = SetOnce(false), ) : BaseOptions() { - override fun parseOption(option: String, ai: ArgIterator): Boolean { - fun nextArg(): String = ai.nextArgRequired(option) + override fun parseOption(option: String, args: ArgIterator): Boolean { + fun nextArg(): String = args.nextArgRequired(option) when (option) { // TODO: Write help diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt index fd6f732a06ce..5ce9a23e6e05 100644 --- a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt +++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt @@ -19,10 +19,10 @@ import com.android.hoststubgen.LogLevel import com.android.hoststubgen.asm.CLASS_INITIALIZER_NAME import com.android.hoststubgen.asm.toJvmClassName import com.android.hoststubgen.filters.FilterPolicyWithReason +import com.android.hoststubgen.filters.MethodCallReplaceSpec import com.android.hoststubgen.filters.PolicyFileProcessor import com.android.hoststubgen.filters.SpecialClass import com.android.hoststubgen.filters.TextFileFilterPolicyParser -import com.android.hoststubgen.filters.TextFilePolicyMethodReplaceFilter import com.android.hoststubgen.log import com.android.hoststubgen.utils.ClassPredicate import com.android.platform.test.ravenwood.ravenhelper.SubcommandHandler @@ -448,7 +448,7 @@ private class TextPolicyToAnnotationConverter( className: String, methodName: String, methodDesc: String, - replaceSpec: TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec, + replaceSpec: MethodCallReplaceSpec, ) { // This can't be converted to an annotation. classHasMember = true diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MapOptions.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MapOptions.kt index 8b95843f08a6..6e0b7b89cf13 100644 --- a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MapOptions.kt +++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MapOptions.kt @@ -16,10 +16,10 @@ package com.android.platform.test.ravenwood.ravenhelper.sourcemap import com.android.hoststubgen.ArgumentsException -import com.android.hoststubgen.ensureFileExists import com.android.hoststubgen.utils.ArgIterator import com.android.hoststubgen.utils.BaseOptions import com.android.hoststubgen.utils.SetOnce +import com.android.hoststubgen.utils.ensureFileExists /** * Options for the "ravenhelper map" subcommand. @@ -38,8 +38,8 @@ class MapOptions( var text: SetOnce<String?> = SetOnce(null), ) : BaseOptions() { - override fun parseOption(option: String, ai: ArgIterator): Boolean { - fun nextArg(): String = ai.nextArgRequired(option) + override fun parseOption(option: String, args: ArgIterator): Boolean { + fun nextArg(): String = args.nextArgRequired(option) when (option) { // TODO: Write help diff --git a/ravenwood/tools/ravenizer/Android.bp b/ravenwood/tools/ravenizer/Android.bp index 957e20647d44..93cda4e3c4c9 100644 --- a/ravenwood/tools/ravenizer/Android.bp +++ b/ravenwood/tools/ravenizer/Android.bp @@ -15,5 +15,10 @@ java_binary_host { "hoststubgen-lib", "ravenwood-junit-for-ravenizer", ], + java_resources: [ + ":ravenizer-standard-options", + ":ravenwood-standard-annotations", + ":ravenwood-common-policies", + ], visibility: ["//visibility:public"], } diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt index e67c730df069..04e3bda2ba27 100644 --- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt +++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt @@ -16,23 +16,22 @@ package com.android.platform.test.ravenwood.ravenizer import com.android.hoststubgen.GeneralUserErrorException +import com.android.hoststubgen.HostStubGenClassProcessor import com.android.hoststubgen.asm.ClassNodes import com.android.hoststubgen.asm.zipEntryNameToClassName import com.android.hoststubgen.executableName import com.android.hoststubgen.log import com.android.platform.test.ravenwood.ravenizer.adapter.RunnerRewritingAdapter -import org.objectweb.asm.ClassReader -import org.objectweb.asm.ClassVisitor -import org.objectweb.asm.ClassWriter -import org.objectweb.asm.util.CheckClassAdapter import java.io.BufferedInputStream import java.io.BufferedOutputStream import java.io.FileOutputStream -import java.io.InputStream -import java.io.OutputStream import java.util.zip.ZipEntry import java.util.zip.ZipFile import java.util.zip.ZipOutputStream +import org.objectweb.asm.ClassReader +import org.objectweb.asm.ClassVisitor +import org.objectweb.asm.ClassWriter +import org.objectweb.asm.util.CheckClassAdapter /** * Various stats on Ravenizer. @@ -41,7 +40,7 @@ data class RavenizerStats( /** Total end-to-end time. */ var totalTime: Double = .0, - /** Time took to build [ClasNodes] */ + /** Time took to build [ClassNodes] */ var loadStructureTime: Double = .0, /** Time took to validate the classes */ @@ -50,14 +49,17 @@ data class RavenizerStats( /** Total real time spent for converting the jar file */ var totalProcessTime: Double = .0, - /** Total real time spent for converting class files (except for I/O time). */ - var totalConversionTime: Double = .0, + /** Total real time spent for ravenizing class files (excluding I/O time). */ + var totalRavenizeTime: Double = .0, + + /** Total real time spent for processing class files HSG style (excluding I/O time). */ + var totalHostStubGenTime: Double = .0, /** Total real time spent for copying class files without modification. */ var totalCopyTime: Double = .0, /** # of entries in the input jar file */ - var totalEntiries: Int = 0, + var totalEntries: Int = 0, /** # of *.class files in the input jar file */ var totalClasses: Int = 0, @@ -67,14 +69,15 @@ data class RavenizerStats( ) { override fun toString(): String { return """ - RavenizerStats{ + RavenizerStats { totalTime=$totalTime, loadStructureTime=$loadStructureTime, validationTime=$validationTime, totalProcessTime=$totalProcessTime, - totalConversionTime=$totalConversionTime, + totalRavenizeTime=$totalRavenizeTime, + totalHostStubGenTime=$totalHostStubGenTime, totalCopyTime=$totalCopyTime, - totalEntiries=$totalEntiries, + totalEntries=$totalEntries, totalClasses=$totalClasses, processedClasses=$processedClasses, } @@ -90,12 +93,18 @@ class Ravenizer { val stats = RavenizerStats() stats.totalTime = log.nTime { + val allClasses = ClassNodes.loadClassStructures(options.inJar.get) { + stats.loadStructureTime = it + } + val processor = HostStubGenClassProcessor(options, allClasses) + process( options.inJar.get, options.outJar.get, options.enableValidation.get, options.fatalValidation.get, options.stripMockito.get, + processor, stats, ) } @@ -108,15 +117,13 @@ class Ravenizer { enableValidation: Boolean, fatalValidation: Boolean, stripMockito: Boolean, + processor: HostStubGenClassProcessor, stats: RavenizerStats, ) { - var allClasses = ClassNodes.loadClassStructures(inJar) { - time -> stats.loadStructureTime = time - } if (enableValidation) { stats.validationTime = log.iTime("Validating classes") { - if (!validateClasses(allClasses)) { - var message = "Invalid test class(es) detected." + + if (!validateClasses(processor.allClasses)) { + val message = "Invalid test class(es) detected." + " See error log for details." if (fatalValidation) { throw RavenizerInvalidTestException(message) @@ -126,7 +133,7 @@ class Ravenizer { } } } - if (includeUnsupportedMockito(allClasses)) { + if (includeUnsupportedMockito(processor.allClasses)) { log.w("Unsupported Mockito detected in $inJar!") } @@ -134,7 +141,7 @@ class Ravenizer { ZipFile(inJar).use { inZip -> val inEntries = inZip.entries() - stats.totalEntiries = inZip.size() + stats.totalEntries = inZip.size() ZipOutputStream(BufferedOutputStream(FileOutputStream(outJar))).use { outZip -> while (inEntries.hasMoreElements()) { @@ -159,9 +166,9 @@ class Ravenizer { stats.totalClasses += 1 } - if (className != null && shouldProcessClass(allClasses, className)) { - stats.processedClasses += 1 - processSingleClass(inZip, entry, outZip, allClasses, stats) + if (className != null && + shouldProcessClass(processor.allClasses, className)) { + processSingleClass(inZip, entry, outZip, processor, stats) } else { // Too slow, let's use merge_zips to bring back the original classes. copyZipEntry(inZip, entry, outZip, stats) @@ -201,14 +208,22 @@ class Ravenizer { inZip: ZipFile, entry: ZipEntry, outZip: ZipOutputStream, - allClasses: ClassNodes, + processor: HostStubGenClassProcessor, stats: RavenizerStats, ) { + stats.processedClasses += 1 val newEntry = ZipEntry(entry.name) outZip.putNextEntry(newEntry) BufferedInputStream(inZip.getInputStream(entry)).use { bis -> - processSingleClass(entry, bis, outZip, allClasses, stats) + var classBytes = bis.readBytes() + stats.totalRavenizeTime += log.vTime("Ravenize ${entry.name}") { + classBytes = ravenizeSingleClass(entry, classBytes, processor.allClasses) + } + stats.totalHostStubGenTime += log.vTime("HostStubGen ${entry.name}") { + classBytes = processor.processClassBytecode(classBytes) + } + outZip.write(classBytes) } outZip.closeEntry() } @@ -217,41 +232,34 @@ class Ravenizer { * Whether a class needs to be processed. This must be kept in sync with [processSingleClass]. */ private fun shouldProcessClass(classes: ClassNodes, classInternalName: String): Boolean { - return !classInternalName.shouldByBypassed() + return !classInternalName.shouldBypass() && RunnerRewritingAdapter.shouldProcess(classes, classInternalName) } - private fun processSingleClass( + private fun ravenizeSingleClass( entry: ZipEntry, - input: InputStream, - output: OutputStream, + input: ByteArray, allClasses: ClassNodes, - stats: RavenizerStats, - ) { - val cr = ClassReader(input) - - lateinit var data: ByteArray - stats.totalConversionTime += log.vTime("Modify ${entry.name}") { + ): ByteArray { + val classInternalName = zipEntryNameToClassName(entry.name) + ?: throw RavenizerInternalException("Unexpected zip entry name: ${entry.name}") - val classInternalName = zipEntryNameToClassName(entry.name) - ?: throw RavenizerInternalException("Unexpected zip entry name: ${entry.name}") - val flags = ClassWriter.COMPUTE_MAXS - val cw = ClassWriter(flags) - var outVisitor: ClassVisitor = cw + val flags = ClassWriter.COMPUTE_MAXS + val cw = ClassWriter(flags) + var outVisitor: ClassVisitor = cw - val enableChecker = false - if (enableChecker) { - outVisitor = CheckClassAdapter(outVisitor) - } + val enableChecker = false + if (enableChecker) { + outVisitor = CheckClassAdapter(outVisitor) + } - // This must be kept in sync with shouldProcessClass. - outVisitor = RunnerRewritingAdapter.maybeApply( - classInternalName, allClasses, outVisitor) + // This must be kept in sync with shouldProcessClass. + outVisitor = RunnerRewritingAdapter.maybeApply( + classInternalName, allClasses, outVisitor) - cr.accept(outVisitor, ClassReader.EXPAND_FRAMES) + val cr = ClassReader(input) + cr.accept(outVisitor, ClassReader.EXPAND_FRAMES) - data = cw.toByteArray() - } - output.write(data) + return cw.toByteArray() } } diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerMain.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerMain.kt index 7f4829ec6127..8a09e6d533b8 100644 --- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerMain.kt +++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerMain.kt @@ -21,6 +21,7 @@ import com.android.hoststubgen.LogLevel import com.android.hoststubgen.executableName import com.android.hoststubgen.log import com.android.hoststubgen.runMainWithBoilerplate +import com.android.hoststubgen.utils.JAR_RESOURCE_PREFIX import java.nio.file.Paths import kotlin.io.path.exists @@ -36,6 +37,10 @@ import kotlin.io.path.exists */ private val RAVENIZER_DOTFILE = System.getenv("HOME") + "/.ravenizer-unsafe" +/** + * This is the name of the standard option text file embedded inside ravenizer.jar. + */ +private const val RAVENIZER_STANDARD_OPTIONS = "texts/ravenizer-standard-options.txt" /** * Entry point. @@ -45,12 +50,12 @@ fun main(args: Array<String>) { log.setConsoleLogLevel(LogLevel.Info) runMainWithBoilerplate { - var newArgs = args.asList() + val newArgs = args.toMutableList() + newArgs.add(0, "@$JAR_RESOURCE_PREFIX$RAVENIZER_STANDARD_OPTIONS") + if (Paths.get(RAVENIZER_DOTFILE).exists()) { log.i("Reading options from $RAVENIZER_DOTFILE") - newArgs = args.toMutableList().apply { - add(0, "@$RAVENIZER_DOTFILE") - } + newArgs.add(0, "@$RAVENIZER_DOTFILE") } val options = RavenizerOptions().apply { parseArgs(newArgs) } diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt index 2c0365404ab6..5d278bb046ae 100644 --- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt +++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt @@ -16,10 +16,10 @@ package com.android.platform.test.ravenwood.ravenizer import com.android.hoststubgen.ArgumentsException -import com.android.hoststubgen.ensureFileExists +import com.android.hoststubgen.HostStubGenClassProcessorOptions import com.android.hoststubgen.utils.ArgIterator -import com.android.hoststubgen.utils.BaseOptions import com.android.hoststubgen.utils.SetOnce +import com.android.hoststubgen.utils.ensureFileExists class RavenizerOptions( /** Input jar file*/ @@ -36,10 +36,10 @@ class RavenizerOptions( /** Whether to remove mockito and dexmaker classes. */ var stripMockito: SetOnce<Boolean> = SetOnce(false), -) : BaseOptions() { +) : HostStubGenClassProcessorOptions() { - override fun parseOption(option: String, ai: ArgIterator): Boolean { - fun nextArg(): String = ai.nextArgRequired(option) + override fun parseOption(option: String, args: ArgIterator): Boolean { + fun nextArg(): String = args.nextArgRequired(option) when (option) { // TODO: Write help @@ -57,7 +57,7 @@ class RavenizerOptions( "--strip-mockito" -> stripMockito.set(true) "--no-strip-mockito" -> stripMockito.set(false) - else -> return false + else -> return super.parseOption(option, args) } return true @@ -79,6 +79,6 @@ class RavenizerOptions( enableValidation=$enableValidation, fatalValidation=$fatalValidation, stripMockito=$stripMockito, - """.trimIndent() + """.trimIndent() + '\n' + super.dumpFields() } } diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Utils.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Utils.kt index 6092fcc9402d..b394a761c7ae 100644 --- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Utils.kt +++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Utils.kt @@ -15,8 +15,8 @@ */ package com.android.platform.test.ravenwood.ravenizer -import android.platform.test.annotations.internal.InnerRunner import android.platform.test.annotations.NoRavenizer +import android.platform.test.annotations.internal.InnerRunner import android.platform.test.ravenwood.RavenwoodAwareTestRunner import com.android.hoststubgen.asm.ClassNodes import com.android.hoststubgen.asm.findAnyAnnotation @@ -85,7 +85,7 @@ fun String.isRavenwoodClass(): Boolean { /** * Classes that should never be modified. */ -fun String.shouldByBypassed(): Boolean { +fun String.shouldBypass(): Boolean { if (this.isRavenwoodClass()) { return true } diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Validator.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Validator.kt index 61e254b225c3..d252b4dc8ab6 100644 --- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Validator.kt +++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Validator.kt @@ -20,8 +20,8 @@ import com.android.hoststubgen.asm.isAbstract import com.android.hoststubgen.asm.startsWithAny import com.android.hoststubgen.asm.toHumanReadableClassName import com.android.hoststubgen.log -import org.objectweb.asm.tree.ClassNode import java.util.regex.Pattern +import org.objectweb.asm.tree.ClassNode fun validateClasses(classes: ClassNodes): Boolean { var allOk = true @@ -37,7 +37,7 @@ fun validateClasses(classes: ClassNodes): Boolean { * */ fun checkClass(cn: ClassNode, classes: ClassNodes): Boolean { - if (cn.name.shouldByBypassed()) { + if (cn.name.shouldBypass()) { // Class doesn't need to be checked. return true } @@ -145,4 +145,4 @@ com.android.server.power.stats.BatteryStatsTimerTest private fun isAllowListedLegacyTest(targetClass: ClassNode): Boolean { return allowListedLegacyTests.contains(targetClass.name) -}
\ No newline at end of file +} diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig index b52b3dabd47d..35db3c6f0a6d 100644 --- a/services/accessibility/accessibility.aconfig +++ b/services/accessibility/accessibility.aconfig @@ -260,6 +260,16 @@ flag { } flag { + name: "pointer_up_motion_event_in_touch_exploration" + namespace: "accessibility" + description: "Allows POINTER_UP motionEvents to trigger during touch exploration." + bug: "374930391" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "proxy_use_apps_on_virtual_device_listener" namespace: "accessibility" description: "Fixes race condition described in b/286587811" @@ -336,3 +346,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "hearing_input_change_when_comm_device" + namespace: "accessibility" + description: "Listen to the CommunicationDeviceChanged to show hearing device input notification." + bug: "394070235" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index c49151dd5e30..6c26c1f74002 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -521,15 +521,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub @Nullable IBinder focusedToken) { return AccessibilityManagerService.this.handleKeyGestureEvent(event); } - - @Override - public boolean isKeyGestureSupported(int gestureType) { - return switch (gestureType) { - case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION, - KeyGestureEvent.KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK -> true; - default -> false; - }; - } }; @VisibleForTesting @@ -5619,7 +5610,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } private boolean isValidDisplay(@Nullable Display display) { - if (display == null || display.getType() == Display.TYPE_OVERLAY) { + if (display == null) { return false; } // Private virtual displays are created by the ap and is not allowed to access by other diff --git a/services/accessibility/java/com/android/server/accessibility/HearingDevicePhoneCallNotificationController.java b/services/accessibility/java/com/android/server/accessibility/HearingDevicePhoneCallNotificationController.java index 10dffb59317e..805d7f820c8d 100644 --- a/services/accessibility/java/com/android/server/accessibility/HearingDevicePhoneCallNotificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/HearingDevicePhoneCallNotificationController.java @@ -65,9 +65,9 @@ public class HearingDevicePhoneCallNotificationController { private final Executor mCallbackExecutor; public HearingDevicePhoneCallNotificationController(@NonNull Context context) { - mTelephonyListener = new CallStateListener(context); mTelephonyManager = context.getSystemService(TelephonyManager.class); mCallbackExecutor = Executors.newSingleThreadExecutor(); + mTelephonyListener = new CallStateListener(context, mCallbackExecutor); } @VisibleForTesting @@ -109,14 +109,29 @@ public class HearingDevicePhoneCallNotificationController { AudioDeviceAttributes.ROLE_INPUT, AudioDeviceInfo.TYPE_BUILTIN_MIC, ""); private final Context mContext; + private final Executor mCommDeviceChangedExecutor; + private final AudioManager.OnCommunicationDeviceChangedListener mCommDeviceChangedListener; private NotificationManager mNotificationManager; private AudioManager mAudioManager; private BroadcastReceiver mHearingDeviceActionReceiver; private BluetoothDevice mHearingDevice; + private boolean mIsCommDeviceChangedRegistered = false; private boolean mIsNotificationShown = false; - CallStateListener(@NonNull Context context) { + CallStateListener(@NonNull Context context, @NonNull Executor executor) { mContext = context; + mCommDeviceChangedExecutor = executor; + mCommDeviceChangedListener = device -> { + if (device == null) { + return; + } + mHearingDevice = getSupportedInputHearingDeviceInfo(List.of(device)); + if (mHearingDevice != null) { + showNotificationIfNeeded(); + } else { + dismissNotificationIfNeeded(); + } + }; } @Override @@ -134,6 +149,11 @@ public class HearingDevicePhoneCallNotificationController { } if (state == TelephonyManager.CALL_STATE_IDLE) { + if (mIsCommDeviceChangedRegistered) { + mIsCommDeviceChangedRegistered = false; + mAudioManager.removeOnCommunicationDeviceChangedListener( + mCommDeviceChangedListener); + } dismissNotificationIfNeeded(); if (mHearingDevice != null) { @@ -143,10 +163,23 @@ public class HearingDevicePhoneCallNotificationController { mHearingDevice = null; } if (state == TelephonyManager.CALL_STATE_OFFHOOK) { - mHearingDevice = getSupportedInputHearingDeviceInfo( - mAudioManager.getAvailableCommunicationDevices()); - if (mHearingDevice != null) { - showNotificationIfNeeded(); + if (com.android.server.accessibility.Flags.hearingInputChangeWhenCommDevice()) { + AudioDeviceInfo commDevice = mAudioManager.getCommunicationDevice(); + mHearingDevice = getSupportedInputHearingDeviceInfo(List.of(commDevice)); + if (mHearingDevice != null) { + showNotificationIfNeeded(); + } else { + mAudioManager.addOnCommunicationDeviceChangedListener( + mCommDeviceChangedExecutor, + mCommDeviceChangedListener); + mIsCommDeviceChangedRegistered = true; + } + } else { + mHearingDevice = getSupportedInputHearingDeviceInfo( + mAudioManager.getAvailableCommunicationDevices()); + if (mHearingDevice != null) { + showNotificationIfNeeded(); + } } } } @@ -264,6 +297,10 @@ public class HearingDevicePhoneCallNotificationController { PendingIntent.FLAG_IMMUTABLE); } case ACTION_BLUETOOTH_DEVICE_DETAILS -> { + if (mHearingDevice == null) { + return null; + } + Bundle bundle = new Bundle(); bundle.putString(KEY_BLUETOOTH_ADDRESS, mHearingDevice.getAddress()); intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, bundle); diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java index cc93d0887d89..23166a800245 100644 --- a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java +++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java @@ -21,6 +21,7 @@ import static android.view.MotionEvent.BUTTON_SECONDARY; import static android.view.accessibility.AccessibilityManager.AUTOCLICK_CURSOR_AREA_SIZE_DEFAULT; import static android.view.accessibility.AccessibilityManager.AUTOCLICK_DELAY_DEFAULT; import static android.view.accessibility.AccessibilityManager.AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT_DEFAULT; +import static android.view.accessibility.AccessibilityManager.AUTOCLICK_REVERT_TO_LEFT_CLICK_DEFAULT; import static com.android.server.accessibility.autoclick.AutoclickIndicatorView.SHOW_INDICATOR_DELAY_TIME; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_LEFT_CLICK; @@ -124,6 +125,22 @@ public class AutoclickController extends BaseEventStreamTransformation { } }; + @VisibleForTesting + final AutoclickScrollPanel.ScrollPanelControllerInterface mScrollPanelController = + new AutoclickScrollPanel.ScrollPanelControllerInterface() { + @Override + public void handleScroll(@AutoclickScrollPanel.ScrollDirection int direction) { + // TODO(b/388845721): Perform actual scroll. + } + + @Override + public void exitScrollMode() { + if (mAutoclickScrollPanel != null) { + mAutoclickScrollPanel.hide(); + } + } + }; + public AutoclickController(Context context, int userId, AccessibilityTraceManager trace) { mTrace = trace; mContext = context; @@ -143,7 +160,8 @@ public class AutoclickController extends BaseEventStreamTransformation { initiateAutoclickIndicator(handler); } - mClickScheduler = new ClickScheduler(handler, AUTOCLICK_DELAY_DEFAULT); + mClickScheduler = new ClickScheduler( + handler, AUTOCLICK_DELAY_DEFAULT); mAutoclickSettingsObserver = new AutoclickSettingsObserver(mUserId, handler); mAutoclickSettingsObserver.start( mContext.getContentResolver(), @@ -168,7 +186,8 @@ public class AutoclickController extends BaseEventStreamTransformation { mWindowManager = mContext.getSystemService(WindowManager.class); mAutoclickTypePanel = new AutoclickTypePanel(mContext, mWindowManager, mUserId, clickPanelController); - mAutoclickScrollPanel = new AutoclickScrollPanel(mContext, mWindowManager); + mAutoclickScrollPanel = new AutoclickScrollPanel(mContext, mWindowManager, + mScrollPanelController); mAutoclickTypePanel.show(); mWindowManager.addView(mAutoclickIndicatorView, mAutoclickIndicatorView.getLayoutParams()); @@ -287,6 +306,10 @@ public class AutoclickController extends BaseEventStreamTransformation { Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT); + private final Uri mAutoclickRevertToLeftClickSettingUri = + Settings.Secure.getUriFor( + Settings.Secure.ACCESSIBILITY_AUTOCLICK_REVERT_TO_LEFT_CLICK); + private ContentResolver mContentResolver; private ClickScheduler mClickScheduler; private AutoclickIndicatorScheduler mAutoclickIndicatorScheduler; @@ -351,6 +374,13 @@ public class AutoclickController extends BaseEventStreamTransformation { /* observer= */ this, mUserId); onChange(/* selfChange= */ true, mAutoclickIgnoreMinorCursorMovementSettingUri); + + mContentResolver.registerContentObserver( + mAutoclickRevertToLeftClickSettingUri, + /* notifyForDescendants= */ false, + /* observer= */ this, + mUserId); + onChange(/* selfChange= */ true, mAutoclickRevertToLeftClickSettingUri); } } @@ -407,6 +437,20 @@ public class AutoclickController extends BaseEventStreamTransformation { == AccessibilityUtils.State.ON; mClickScheduler.setIgnoreMinorCursorMovement(ignoreMinorCursorMovement); } + + if (mAutoclickRevertToLeftClickSettingUri.equals(uri)) { + boolean revertToLeftClick = + Settings.Secure.getIntForUser( + mContentResolver, + Settings.Secure + .ACCESSIBILITY_AUTOCLICK_REVERT_TO_LEFT_CLICK, + AUTOCLICK_REVERT_TO_LEFT_CLICK_DEFAULT + ? AccessibilityUtils.State.ON + : AccessibilityUtils.State.OFF, + mUserId) + == AccessibilityUtils.State.ON; + mClickScheduler.setRevertToLeftClick(revertToLeftClick); + } } } } @@ -488,6 +532,9 @@ public class AutoclickController extends BaseEventStreamTransformation { /** Whether the minor cursor movement should be ignored. */ private boolean mIgnoreMinorCursorMovement = AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT_DEFAULT; + /** Whether the autoclick type reverts to left click once performing an action. */ + private boolean mRevertToLeftClick = AUTOCLICK_REVERT_TO_LEFT_CLICK_DEFAULT; + /** Whether there is pending click. */ private boolean mActive; /** If active, time at which pending click is scheduled. */ @@ -538,6 +585,7 @@ public class AutoclickController extends BaseEventStreamTransformation { sendClick(); resetInternalState(); + resetSelectedClickTypeIfNecessary(); } /** @@ -616,6 +664,11 @@ public class AutoclickController extends BaseEventStreamTransformation { return mDelay; } + @VisibleForTesting + boolean getRevertToLeftClickForTesting() { + return mRevertToLeftClick; + } + /** * Updates the time at which click sequence should occur. * @@ -675,6 +728,12 @@ public class AutoclickController extends BaseEventStreamTransformation { } } + private void resetSelectedClickTypeIfNecessary() { + if (mRevertToLeftClick && mActiveClickType != AUTOCLICK_TYPE_LEFT_CLICK) { + mAutoclickTypePanel.resetSelectedClickType(); + } + } + /** * @param event Observed motion event. * @return Whether the event coords are far enough from the anchor for the event not to be @@ -699,6 +758,10 @@ public class AutoclickController extends BaseEventStreamTransformation { mIgnoreMinorCursorMovement = ignoreMinorCursorMovement; } + public void setRevertToLeftClick(boolean revertToLeftClick) { + mRevertToLeftClick = revertToLeftClick; + } + private void updateMovementSlop(double slop) { mMovementSlop = slop; } diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickScrollPanel.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickScrollPanel.java index 86f79a83ea28..e79be502a6fc 100644 --- a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickScrollPanel.java +++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickScrollPanel.java @@ -18,6 +18,7 @@ package com.android.server.accessibility.autoclick; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; +import android.annotation.IntDef; import android.content.Context; import android.graphics.PixelFormat; import android.view.Gravity; @@ -25,23 +26,97 @@ import android.view.LayoutInflater; import android.view.View; import android.view.WindowInsets; import android.view.WindowManager; +import android.widget.ImageButton; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import com.android.internal.R; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + public class AutoclickScrollPanel { + public static final int DIRECTION_UP = 0; + public static final int DIRECTION_DOWN = 1; + public static final int DIRECTION_LEFT = 2; + public static final int DIRECTION_RIGHT = 3; + + @IntDef({ + DIRECTION_UP, + DIRECTION_DOWN, + DIRECTION_LEFT, + DIRECTION_RIGHT + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ScrollDirection {} + private final Context mContext; private final View mContentView; private final WindowManager mWindowManager; + private ScrollPanelControllerInterface mScrollPanelController; + + // Scroll panel buttons. + private final ImageButton mUpButton; + private final ImageButton mDownButton; + private final ImageButton mLeftButton; + private final ImageButton mRightButton; + private final ImageButton mExitButton; + private boolean mInScrollMode = false; - public AutoclickScrollPanel(Context context, WindowManager windowManager) { + /** + * Interface for handling scroll operations. + */ + public interface ScrollPanelControllerInterface { + /** + * Called when a scroll direction is hovered. + * + * @param direction The direction to scroll: one of {@link ScrollDirection} values. + */ + void handleScroll(@ScrollDirection int direction); + + /** + * Called when the exit button is hovered. + */ + void exitScrollMode(); + } + + public AutoclickScrollPanel(Context context, WindowManager windowManager, + ScrollPanelControllerInterface controller) { mContext = context; mWindowManager = windowManager; + mScrollPanelController = controller; mContentView = LayoutInflater.from(context).inflate( R.layout.accessibility_autoclick_scroll_panel, null); + + // Initialize buttons. + mUpButton = mContentView.findViewById(R.id.scroll_up); + mLeftButton = mContentView.findViewById(R.id.scroll_left); + mRightButton = mContentView.findViewById(R.id.scroll_right); + mDownButton = mContentView.findViewById(R.id.scroll_down); + mExitButton = mContentView.findViewById(R.id.scroll_exit); + + initializeButtonState(); + } + + /** + * Sets up hover listeners for scroll panel buttons. + */ + private void initializeButtonState() { + // Set up hover listeners for direction buttons. + setupHoverListenerForDirectionButton(mUpButton, DIRECTION_UP); + setupHoverListenerForDirectionButton(mLeftButton, DIRECTION_LEFT); + setupHoverListenerForDirectionButton(mRightButton, DIRECTION_RIGHT); + setupHoverListenerForDirectionButton(mDownButton, DIRECTION_DOWN); + + // Set up hover listener for exit button. + mExitButton.setOnHoverListener((v, event) -> { + if (mScrollPanelController != null) { + mScrollPanelController.exitScrollMode(); + } + return true; + }); } /** @@ -67,6 +142,19 @@ public class AutoclickScrollPanel { } /** + * Sets up a hover listener for a direction button. + */ + private void setupHoverListenerForDirectionButton(ImageButton button, + @ScrollDirection int direction) { + button.setOnHoverListener((v, event) -> { + if (mScrollPanelController != null) { + mScrollPanelController.handleScroll(direction); + } + return true; + }); + } + + /** * Retrieves the layout params for AutoclickScrollPanel, used when it's added to the Window * Manager. */ diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java index 90ddc43ae3ed..5a484d42eb96 100644 --- a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java +++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java @@ -266,16 +266,28 @@ public class AutoclickTypePanel { } private void initializeButtonState() { - mLeftClickButton.setOnClickListener(v -> togglePanelExpansion(AUTOCLICK_TYPE_LEFT_CLICK)); - mRightClickButton.setOnClickListener(v -> togglePanelExpansion(AUTOCLICK_TYPE_RIGHT_CLICK)); + // Use `createButtonListener()` to append extra pause logic to each button's click. + mLeftClickButton.setOnClickListener( + wrapWithTogglePauseListener(v -> togglePanelExpansion(AUTOCLICK_TYPE_LEFT_CLICK))); + mRightClickButton.setOnClickListener( + wrapWithTogglePauseListener(v -> togglePanelExpansion(AUTOCLICK_TYPE_RIGHT_CLICK))); mDoubleClickButton.setOnClickListener( - v -> togglePanelExpansion(AUTOCLICK_TYPE_DOUBLE_CLICK)); - mScrollButton.setOnClickListener(v -> togglePanelExpansion(AUTOCLICK_TYPE_SCROLL)); - mDragButton.setOnClickListener(v -> togglePanelExpansion(AUTOCLICK_TYPE_DRAG)); - mPositionButton.setOnClickListener(v -> moveToNextCorner()); + wrapWithTogglePauseListener( + v -> togglePanelExpansion(AUTOCLICK_TYPE_DOUBLE_CLICK))); + mScrollButton.setOnClickListener( + wrapWithTogglePauseListener(v -> togglePanelExpansion(AUTOCLICK_TYPE_SCROLL))); + mDragButton.setOnClickListener( + wrapWithTogglePauseListener(v -> togglePanelExpansion(AUTOCLICK_TYPE_DRAG))); + mPositionButton.setOnClickListener(wrapWithTogglePauseListener(v -> moveToNextCorner())); + + // The pause button calls `togglePause()` directly so it does not need extra logic. mPauseButton.setOnClickListener(v -> togglePause()); - // Initializes panel as collapsed state and only displays the left click button. + resetSelectedClickType(); + } + + /** Reset panel as collapsed state and only displays the left click button. */ + public void resetSelectedClickType() { hideAllClickTypeButtons(); mLeftClickButton.setVisibility(View.VISIBLE); setSelectedClickType(AUTOCLICK_TYPE_LEFT_CLICK); @@ -517,6 +529,18 @@ public class AutoclickTypePanel { return true; } + /* Appends a check of the pause state to the button's listener. */ + private View.OnClickListener wrapWithTogglePauseListener(View.OnClickListener listener) { + return v -> { + listener.onClick(v); + + // Resumes autoclick if the button is clicked while in a paused state. + if (mPaused) { + togglePause(); + } + }; + } + @VisibleForTesting boolean getExpansionStateForTesting() { return mExpanded; diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index fb329430acb2..b02fe2752a62 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -653,6 +653,14 @@ public class TouchExplorer extends BaseEventStreamTransformation case ACTION_UP: handleActionUp(event, rawEvent, policyFlags); break; + case ACTION_POINTER_UP: + if (com.android.server.accessibility.Flags + .pointerUpMotionEventInTouchExploration()) { + if (mState.isServiceDetectingGestures()) { + mAms.sendMotionEventToListeningServices(rawEvent); + } + } + break; default: break; } diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java index cd46b38272c2..568abd196735 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java @@ -26,6 +26,8 @@ import android.view.Display; import android.view.MotionEvent; import android.view.accessibility.AccessibilityEvent; +import androidx.annotation.VisibleForTesting; + import com.android.server.accessibility.AccessibilityManagerService; /** @@ -73,7 +75,8 @@ public class TouchState { private int mState = STATE_CLEAR; // Helper class to track received pointers. // Todo: collapse or hide this class so multiple classes don't modify it. - private final ReceivedPointerTracker mReceivedPointerTracker; + @VisibleForTesting + public final ReceivedPointerTracker mReceivedPointerTracker; // The most recently received motion event. private MotionEvent mLastReceivedEvent; // The accompanying raw event without any transformations. @@ -219,8 +222,19 @@ public class TouchState { startTouchInteracting(); break; case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END: - setState(STATE_CLEAR); - // We will clear when we actually handle the next ACTION_DOWN. + // When interaction ends, check if there are still down pointers. + // If there are any down pointers, go directly to TouchExploring instead. + if (com.android.server.accessibility.Flags + .pointerUpMotionEventInTouchExploration()) { + if (mReceivedPointerTracker.mReceivedPointersDown > 0) { + startTouchExploring(); + } else { + setState(STATE_CLEAR); + // We will clear when we actually handle the next ACTION_DOWN. + } + } else { + setState(STATE_CLEAR); + } break; case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START: startTouchExploring(); @@ -419,7 +433,8 @@ public class TouchState { private final PointerDownInfo[] mReceivedPointers = new PointerDownInfo[MAX_POINTER_COUNT]; // Which pointers are down. - private int mReceivedPointersDown; + @VisibleForTesting + public int mReceivedPointersDown; // The edge flags of the last received down event. private int mLastReceivedDownEdgeFlags; diff --git a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java index 6ccf5e47ca6c..59566677b1fc 100644 --- a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java +++ b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java @@ -39,6 +39,14 @@ import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_ import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE; import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__MENU; import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_DELAY_AFTER_ANIMATION_END; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_FILL_DIALOG_DISABLED; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_LAST_TRIGGERED_ID_CHANGED; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_SCREEN_HAS_CREDMAN_FIELD; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_TIMEOUT_AFTER_DELAY; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_TIMEOUT_SINCE_IME_ANIMATED; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_UNKNOWN; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_WAIT_FOR_IME_ANIMATION; import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__ANY_SHOWN; import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_ACTIVITY_FINISHED; import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_FILL_REQUEST_FAILED; @@ -157,8 +165,24 @@ public final class PresentationStatsEventLogger { DETECTION_PREFER_PCC }) @Retention(RetentionPolicy.SOURCE) - public @interface DetectionPreference { - } + public @interface DetectionPreference {} + + /** + * The fill dialog not shown reason. These are wrappers around + * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.FillDialogNotShownReason}. + */ + @IntDef(prefix = {"FILL_DIALOG_NOT_SHOWN_REASON"}, value = { + FILL_DIALOG_NOT_SHOWN_REASON_UNKNOWN, + FILL_DIALOG_NOT_SHOWN_REASON_FILL_DIALOG_DISABLED, + FILL_DIALOG_NOT_SHOWN_REASON_SCREEN_HAS_CREDMAN_FIELD, + FILL_DIALOG_NOT_SHOWN_REASON_LAST_TRIGGERED_ID_CHANGED, + FILL_DIALOG_NOT_SHOWN_REASON_WAIT_FOR_IME_ANIMATION, + FILL_DIALOG_NOT_SHOWN_REASON_TIMEOUT_SINCE_IME_ANIMATED, + FILL_DIALOG_NOT_SHOWN_REASON_DELAY_AFTER_ANIMATION_END, + FILL_DIALOG_NOT_SHOWN_REASON_TIMEOUT_AFTER_DELAY + }) + @Retention(RetentionPolicy.SOURCE) + public @interface FillDialogNotShownReason {} public static final int NOT_SHOWN_REASON_ANY_SHOWN = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__ANY_SHOWN; @@ -219,6 +243,25 @@ public final class PresentationStatsEventLogger { public static final int DETECTION_PREFER_PCC = AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_PCC; + // Values for AutofillFillResponseReported.fill_dialog_not_shown_reason + public static final int FILL_DIALOG_NOT_SHOWN_REASON_UNKNOWN = + AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_UNKNOWN; + public static final int FILL_DIALOG_NOT_SHOWN_REASON_FILL_DIALOG_DISABLED = + AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_FILL_DIALOG_DISABLED; + public static final int FILL_DIALOG_NOT_SHOWN_REASON_SCREEN_HAS_CREDMAN_FIELD = + AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_SCREEN_HAS_CREDMAN_FIELD; + public static final int FILL_DIALOG_NOT_SHOWN_REASON_LAST_TRIGGERED_ID_CHANGED = + AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_LAST_TRIGGERED_ID_CHANGED; + public static final int FILL_DIALOG_NOT_SHOWN_REASON_WAIT_FOR_IME_ANIMATION = + AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_WAIT_FOR_IME_ANIMATION; + public static final int FILL_DIALOG_NOT_SHOWN_REASON_TIMEOUT_SINCE_IME_ANIMATED = + AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_TIMEOUT_SINCE_IME_ANIMATED; + public static final int FILL_DIALOG_NOT_SHOWN_REASON_DELAY_AFTER_ANIMATION_END = + AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_DELAY_AFTER_ANIMATION_END; + public static final int FILL_DIALOG_NOT_SHOWN_REASON_TIMEOUT_AFTER_DELAY = + AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_TIMEOUT_AFTER_DELAY; + + private static final int DEFAULT_VALUE_INT = -1; private final int mSessionId; @@ -871,6 +914,43 @@ public final class PresentationStatsEventLogger { } /** + * Set fill_dialog_not_shown_reason + * @param reason + */ + public void maybeSetFillDialogNotShownReason(@FillDialogNotShownReason int reason) { + mEventInternal.ifPresent(event -> { + if ((event.mFillDialogNotShownReason + == FILL_DIALOG_NOT_SHOWN_REASON_DELAY_AFTER_ANIMATION_END + || event.mFillDialogNotShownReason + == FILL_DIALOG_NOT_SHOWN_REASON_WAIT_FOR_IME_ANIMATION) && reason + == FILL_DIALOG_NOT_SHOWN_REASON_TIMEOUT_SINCE_IME_ANIMATED) { + event.mFillDialogNotShownReason = FILL_DIALOG_NOT_SHOWN_REASON_TIMEOUT_AFTER_DELAY; + } else { + event.mFillDialogNotShownReason = reason; + } + }); + } + + /** + * Set fill_dialog_ready_to_show_ms + * @param val + */ + public void maybeSetFillDialogReadyToShowMs(long val) { + mEventInternal.ifPresent(event -> { + event.mFillDialogReadyToShowMs = (int) (val - mSessionStartTimestamp); + }); + } + + /** + * Set ime_animation_finish_ms + * @param val + */ + public void maybeSetImeAnimationFinishMs(long val) { + mEventInternal.ifPresent(event -> { + event.mImeAnimationFinishMs = (int) (val - mSessionStartTimestamp); + }); + } + /** * Set the log contains relayout metrics. * This is being added as a temporary measure to add logging. * In future, when we map Session's old view states to the new autofill id's as part of fixing @@ -959,7 +1039,13 @@ public final class PresentationStatsEventLogger { + " event.notExpiringResponseDuringAuthCount=" + event.mFixExpireResponseDuringAuthCount + " event.notifyViewEnteredIgnoredDuringAuthCount=" - + event.mNotifyViewEnteredIgnoredDuringAuthCount); + + event.mNotifyViewEnteredIgnoredDuringAuthCount + + " event.fillDialogNotShownReason=" + + event.mFillDialogNotShownReason + + " event.fillDialogReadyToShowMs=" + + event.mFillDialogReadyToShowMs + + " event.imeAnimationFinishMs=" + + event.mImeAnimationFinishMs); } // TODO(b/234185326): Distinguish empty responses from other no presentation reasons. @@ -1020,7 +1106,10 @@ public final class PresentationStatsEventLogger { event.mViewFilledSuccessfullyOnRefillCount, event.mViewFailedOnRefillCount, event.mFixExpireResponseDuringAuthCount, - event.mNotifyViewEnteredIgnoredDuringAuthCount); + event.mNotifyViewEnteredIgnoredDuringAuthCount, + event.mFillDialogNotShownReason, + event.mFillDialogReadyToShowMs, + event.mImeAnimationFinishMs); mEventInternal = Optional.empty(); } @@ -1087,6 +1176,9 @@ public final class PresentationStatsEventLogger { // Following are not logged and used only for internal logic boolean shouldResetShownCount = false; boolean mHasRelayoutLog = false; + @FillDialogNotShownReason int mFillDialogNotShownReason = FILL_DIALOG_NOT_SHOWN_REASON_UNKNOWN; + int mFillDialogReadyToShowMs = DEFAULT_VALUE_INT; + int mImeAnimationFinishMs = DEFAULT_VALUE_INT; PresentationStatsEventInternal() {} } diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 6515b237519a..ff3bf2acb080 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -81,6 +81,13 @@ import static com.android.server.autofill.PresentationStatsEventLogger.AUTHENTIC import static com.android.server.autofill.PresentationStatsEventLogger.AUTHENTICATION_RESULT_SUCCESS; import static com.android.server.autofill.PresentationStatsEventLogger.AUTHENTICATION_TYPE_DATASET_AUTHENTICATION; import static com.android.server.autofill.PresentationStatsEventLogger.AUTHENTICATION_TYPE_FULL_AUTHENTICATION; +import static com.android.server.autofill.PresentationStatsEventLogger.FILL_DIALOG_NOT_SHOWN_REASON_DELAY_AFTER_ANIMATION_END; +import static com.android.server.autofill.PresentationStatsEventLogger.FILL_DIALOG_NOT_SHOWN_REASON_FILL_DIALOG_DISABLED; +import static com.android.server.autofill.PresentationStatsEventLogger.FILL_DIALOG_NOT_SHOWN_REASON_LAST_TRIGGERED_ID_CHANGED; +import static com.android.server.autofill.PresentationStatsEventLogger.FILL_DIALOG_NOT_SHOWN_REASON_SCREEN_HAS_CREDMAN_FIELD; +import static com.android.server.autofill.PresentationStatsEventLogger.FILL_DIALOG_NOT_SHOWN_REASON_TIMEOUT_SINCE_IME_ANIMATED; +import static com.android.server.autofill.PresentationStatsEventLogger.FILL_DIALOG_NOT_SHOWN_REASON_UNKNOWN; +import static com.android.server.autofill.PresentationStatsEventLogger.FILL_DIALOG_NOT_SHOWN_REASON_WAIT_FOR_IME_ANIMATION; import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_ANY_SHOWN; import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_NO_FOCUS; import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_REQUEST_FAILED; @@ -5622,6 +5629,10 @@ final class Session synchronized (mLock) { final ViewState currentView = mViewStates.get(mCurrentViewId); currentView.setState(ViewState.STATE_FILL_DIALOG_SHOWN); + // Set fill_dialog_not_shown_reason to unknown (a.k.a shown). It is needed due + // to possible SHOW_FILL_DIALOG_WAIT. + mPresentationStatsEventLogger.maybeSetFillDialogNotShownReason( + FILL_DIALOG_NOT_SHOWN_REASON_UNKNOWN); } // Just show fill dialog once per fill request, so disabled after shown. // Note: Cannot disable before requestShowFillDialog() because the method @@ -5725,6 +5736,15 @@ final class Session private boolean isFillDialogUiEnabled() { synchronized (mLock) { + if (mSessionFlags.mFillDialogDisabled) { + mPresentationStatsEventLogger.maybeSetFillDialogNotShownReason( + FILL_DIALOG_NOT_SHOWN_REASON_FILL_DIALOG_DISABLED); + } + if (mSessionFlags.mScreenHasCredmanField) { + // Prefer to log "HAS_CREDMAN_FIELD" over "FILL_DIALOG_DISABLED". + mPresentationStatsEventLogger.maybeSetFillDialogNotShownReason( + FILL_DIALOG_NOT_SHOWN_REASON_SCREEN_HAS_CREDMAN_FIELD); + } return !mSessionFlags.mFillDialogDisabled && !mSessionFlags.mScreenHasCredmanField; } } @@ -5789,6 +5809,8 @@ final class Session || !ArrayUtils.contains(mLastFillDialogTriggerIds, filledId)) { // Last fill dialog triggered ids are changed. if (sDebug) Log.w(TAG, "Last fill dialog triggered ids are changed."); + mPresentationStatsEventLogger.maybeSetFillDialogNotShownReason( + FILL_DIALOG_NOT_SHOWN_REASON_LAST_TRIGGERED_ID_CHANGED); return SHOW_FILL_DIALOG_NO; } @@ -5815,6 +5837,8 @@ final class Session // we need to wait for animation to happen. We can't return from here yet. // This is the situation #2 described above. Log.d(TAG, "Waiting for ime animation to complete before showing fill dialog"); + mPresentationStatsEventLogger.maybeSetFillDialogNotShownReason( + FILL_DIALOG_NOT_SHOWN_REASON_WAIT_FOR_IME_ANIMATION); mFillDialogRunnable = createFillDialogEvalRunnable( response, filledId, filterText, flags); return SHOW_FILL_DIALOG_WAIT; @@ -5824,9 +5848,15 @@ final class Session // max of start input time or the ime finish time long effectiveDuration = currentTimestampMs - Math.max(mLastInputStartTime, mImeAnimationFinishTimeMs); + mPresentationStatsEventLogger.maybeSetFillDialogReadyToShowMs( + currentTimestampMs); + mPresentationStatsEventLogger.maybeSetImeAnimationFinishMs( + Math.max(mLastInputStartTime, mImeAnimationFinishTimeMs)); if (effectiveDuration >= mFillDialogTimeoutMs) { Log.d(TAG, "Fill dialog not shown since IME has been up for more time than " + mFillDialogTimeoutMs + "ms"); + mPresentationStatsEventLogger.maybeSetFillDialogNotShownReason( + FILL_DIALOG_NOT_SHOWN_REASON_TIMEOUT_SINCE_IME_ANIMATED); return SHOW_FILL_DIALOG_NO; } else if (effectiveDuration < mFillDialogMinWaitAfterImeAnimationMs) { // we need to wait for some time after animation ends @@ -5834,6 +5864,8 @@ final class Session response, filledId, filterText, flags); mHandler.postDelayed(runnable, mFillDialogMinWaitAfterImeAnimationMs - effectiveDuration); + mPresentationStatsEventLogger.maybeSetFillDialogNotShownReason( + FILL_DIALOG_NOT_SHOWN_REASON_DELAY_AFTER_ANIMATION_END); return SHOW_FILL_DIALOG_WAIT; } } diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java index 48d21c3a222f..fa67ef5156c1 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java @@ -981,13 +981,18 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba @Override public void handleCancel(@CancellationReason int cancellationReason) { - Slog.w(TAG, "Full backup cancel of " + mTarget.packageName); + Slog.w( + TAG, + "Cancelled backup: " + mTarget.packageName + " reason:" + cancellationReason); mBackupManagerMonitorEventSender.monitorEvent( BackupManagerMonitor.LOG_EVENT_ID_FULL_BACKUP_CANCEL, mTarget, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, - /* extras= */ null); + BackupManagerMonitorEventSender.putMonitoringExtra( + /* extras= */ null, + BackupManagerMonitor.EXTRA_LOG_CANCELLATION_REASON, + cancellationReason)); mIsCancelled = true; // Cancel tasks spun off by this task. mUserBackupManagerService.handleCancel(mEphemeralToken, cancellationReason); diff --git a/services/core/Android.bp b/services/core/Android.bp index 14d9d3f0c0a1..decac40d20f8 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -122,10 +122,10 @@ genrule { } genrule { - name: "statslog-mediarouter-java-gen", - tools: ["stats-log-api-gen"], - cmd: "$(location stats-log-api-gen) --java $(out) --module mediarouter --javaPackage com.android.server.media --javaClass MediaRouterStatsLog", - out: ["com/android/server/media/MediaRouterStatsLog.java"], + name: "statslog-mediarouter-java-gen", + tools: ["stats-log-api-gen"], + cmd: "$(location stats-log-api-gen) --java $(out) --module mediarouter --javaPackage com.android.server.media --javaClass MediaRouterStatsLog", + out: ["com/android/server/media/MediaRouterStatsLog.java"], } java_library_static { @@ -138,6 +138,7 @@ java_library_static { "ondeviceintelligence_conditionally", ], srcs: [ + ":android.hardware.audio.effect-V1-java-source", ":android.hardware.tv.hdmi.connection-V1-java-source", ":android.hardware.tv.hdmi.earc-V1-java-source", ":android.hardware.tv.mediaquality-V1-java-source", diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java index aae48daa5dde..40f7c873eae8 100644 --- a/services/core/java/com/android/server/adb/AdbService.java +++ b/services/core/java/com/android/server/adb/AdbService.java @@ -143,19 +143,16 @@ public class AdbService extends IAdbManager.Stub { @Override public File getAdbKeysFile() { - return mDebuggingManager == null ? null : mDebuggingManager.getUserKeyFile(); + return mDebuggingManager.getUserKeyFile(); } @Override public File getAdbTempKeysFile() { - return mDebuggingManager == null ? null : mDebuggingManager.getAdbTempKeysFile(); + return mDebuggingManager.getAdbTempKeysFile(); } @Override public void notifyKeyFilesUpdated() { - if (mDebuggingManager == null) { - return; - } mDebuggingManager.notifyKeyFilesUpdated(); } @@ -237,7 +234,7 @@ public class AdbService extends IAdbManager.Stub { private boolean mIsAdbUsbEnabled; private boolean mIsAdbWifiEnabled; - private AdbDebuggingManager mDebuggingManager; + private final AdbDebuggingManager mDebuggingManager; private ContentObserver mObserver; @@ -287,38 +284,27 @@ public class AdbService extends IAdbManager.Stub { */ public void bootCompleted() { Slog.d(TAG, "boot completed"); - if (mDebuggingManager != null) { - mDebuggingManager.setAdbEnabled(mIsAdbUsbEnabled, AdbTransportType.USB); - mDebuggingManager.setAdbEnabled(mIsAdbWifiEnabled, AdbTransportType.WIFI); - } + mDebuggingManager.setAdbEnabled(mIsAdbUsbEnabled, AdbTransportType.USB); + mDebuggingManager.setAdbEnabled(mIsAdbWifiEnabled, AdbTransportType.WIFI); } @Override public void allowDebugging(boolean alwaysAllow, @NonNull String publicKey) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); Preconditions.checkStringNotEmpty(publicKey); - if (mDebuggingManager != null) { - mDebuggingManager.allowDebugging(alwaysAllow, publicKey); - } + mDebuggingManager.allowDebugging(alwaysAllow, publicKey); } @Override public void denyDebugging() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); - if (mDebuggingManager != null) { - mDebuggingManager.denyDebugging(); - } + mDebuggingManager.denyDebugging(); } @Override public void clearDebuggingKeys() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); - if (mDebuggingManager != null) { - mDebuggingManager.clearDebuggingKeys(); - } else { - throw new RuntimeException("Cannot clear ADB debugging keys, " - + "AdbDebuggingManager not enabled"); - } + mDebuggingManager.clearDebuggingKeys(); } /** @@ -350,25 +336,18 @@ public class AdbService extends IAdbManager.Stub { public void allowWirelessDebugging(boolean alwaysAllow, @NonNull String bssid) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); Preconditions.checkStringNotEmpty(bssid); - if (mDebuggingManager != null) { - mDebuggingManager.allowWirelessDebugging(alwaysAllow, bssid); - } + mDebuggingManager.allowWirelessDebugging(alwaysAllow, bssid); } @Override public void denyWirelessDebugging() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); - if (mDebuggingManager != null) { - mDebuggingManager.denyWirelessDebugging(); - } + mDebuggingManager.denyWirelessDebugging(); } @Override public FingerprintAndPairDevice[] getPairedDevices() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); - if (mDebuggingManager == null) { - return null; - } Map<String, PairDevice> map = mDebuggingManager.getPairedDevices(); FingerprintAndPairDevice[] ret = new FingerprintAndPairDevice[map.size()]; int i = 0; @@ -385,17 +364,13 @@ public class AdbService extends IAdbManager.Stub { public void unpairDevice(@NonNull String fingerprint) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); Preconditions.checkStringNotEmpty(fingerprint); - if (mDebuggingManager != null) { - mDebuggingManager.unpairDevice(fingerprint); - } + mDebuggingManager.unpairDevice(fingerprint); } @Override public void enablePairingByPairingCode() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); - if (mDebuggingManager != null) { - mDebuggingManager.enablePairingByPairingCode(); - } + mDebuggingManager.enablePairingByPairingCode(); } @Override @@ -403,27 +378,19 @@ public class AdbService extends IAdbManager.Stub { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); Preconditions.checkStringNotEmpty(serviceName); Preconditions.checkStringNotEmpty(password); - if (mDebuggingManager != null) { - mDebuggingManager.enablePairingByQrCode(serviceName, password); - } + mDebuggingManager.enablePairingByQrCode(serviceName, password); } @Override public void disablePairing() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); - if (mDebuggingManager != null) { - mDebuggingManager.disablePairing(); - } + mDebuggingManager.disablePairing(); } @Override public int getAdbWirelessPort() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); - if (mDebuggingManager != null) { - return mDebuggingManager.getAdbWirelessPort(); - } - // If ro.adb.secure=0 - return mConnectionPort.get(); + return mDebuggingManager.getAdbWirelessPort(); } @Override @@ -503,7 +470,7 @@ public class AdbService extends IAdbManager.Stub { } else if (transportType == AdbTransportType.WIFI && enable != mIsAdbWifiEnabled) { mIsAdbWifiEnabled = enable; if (mIsAdbWifiEnabled) { - if (!AdbProperties.secure().orElse(false) && mDebuggingManager == null) { + if (!AdbProperties.secure().orElse(false)) { // Start adbd. If this is secure adb, then we defer enabling adb over WiFi. SystemProperties.set(WIFI_PERSISTENT_CONFIG_PROPERTY, "1"); mConnectionPortPoller = @@ -537,9 +504,7 @@ public class AdbService extends IAdbManager.Stub { } } - if (mDebuggingManager != null) { - mDebuggingManager.setAdbEnabled(enable, transportType); - } + mDebuggingManager.setAdbEnabled(enable, transportType); Slog.d(TAG, "Broadcasting enable = " + enable + ", type = " + transportType); mCallbacks.broadcast((callback) -> { @@ -586,11 +551,8 @@ public class AdbService extends IAdbManager.Stub { dump = new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")); } - if (mDebuggingManager != null) { - mDebuggingManager.dump(dump, "debugging_manager", - AdbServiceDumpProto.DEBUGGING_MANAGER); - } - + mDebuggingManager.dump(dump, "debugging_manager", + AdbServiceDumpProto.DEBUGGING_MANAGER); dump.flush(); } else { pw.println("Dump current ADB state"); diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java index 81d34f67dee9..fe4fa1068bb3 100644 --- a/services/core/java/com/android/server/am/BroadcastConstants.java +++ b/services/core/java/com/android/server/am/BroadcastConstants.java @@ -41,6 +41,7 @@ import dalvik.annotation.optimization.NeverCompile; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.TimeUnit; /** * Tunable parameters for broadcast dispatch policy @@ -286,6 +287,17 @@ public class BroadcastConstants { "max_frozen_outgoing_broadcasts"; private static final int DEFAULT_MAX_FROZEN_OUTGOING_BROADCASTS = 32; + /** + * For {@link BroadcastQueueImpl}: Indicates how long after a process start was initiated, + * it should be considered abandoned and discarded. + */ + public long PENDING_COLD_START_ABANDON_TIMEOUT_MILLIS = + DEFAULT_PENDING_COLD_START_ABANDON_TIMEOUT_MILLIS * Build.HW_TIMEOUT_MULTIPLIER; + private static final String KEY_PENDING_COLD_START_ABANDON_TIMEOUT_MILLIS = + "pending_cold_start_abandon_timeout_millis"; + private static final long DEFAULT_PENDING_COLD_START_ABANDON_TIMEOUT_MILLIS = + TimeUnit.MINUTES.toMillis(5); + // Settings override tracking for this instance private String mSettingsKey; private SettingsObserver mSettingsObserver; @@ -434,6 +446,10 @@ public class BroadcastConstants { MAX_FROZEN_OUTGOING_BROADCASTS = getDeviceConfigInt( KEY_MAX_FROZEN_OUTGOING_BROADCASTS, DEFAULT_MAX_FROZEN_OUTGOING_BROADCASTS); + PENDING_COLD_START_ABANDON_TIMEOUT_MILLIS = getDeviceConfigLong( + KEY_PENDING_COLD_START_ABANDON_TIMEOUT_MILLIS, + DEFAULT_PENDING_COLD_START_ABANDON_TIMEOUT_MILLIS) + * Build.HW_TIMEOUT_MULTIPLIER; } // TODO: migrate BroadcastRecord to accept a BroadcastConstants @@ -491,6 +507,8 @@ public class BroadcastConstants { PENDING_COLD_START_CHECK_INTERVAL_MILLIS).println(); pw.print(KEY_MAX_FROZEN_OUTGOING_BROADCASTS, MAX_FROZEN_OUTGOING_BROADCASTS).println(); + pw.print(KEY_PENDING_COLD_START_ABANDON_TIMEOUT_MILLIS, + PENDING_COLD_START_ABANDON_TIMEOUT_MILLIS).println(); pw.decreaseIndent(); pw.println(); } diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java index 508c01802156..c0fe73877c01 100644 --- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java +++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java @@ -245,6 +245,24 @@ class BroadcastProcessQueue { */ private final ArrayList<BroadcastRecord> mOutgoingBroadcasts = new ArrayList<>(); + /** + * The timestamp, in {@link SystemClock#uptimeMillis()}, at which a cold start was initiated + * for the process associated with this queue. + * + * Note: We could use the already existing {@link ProcessRecord#getStartUptime()} instead + * of this, but the need for this timestamp is to identify an issue (b/393898613) where the + * suspicion is that process is not attached or getting changed. So, we don't want to rely on + * ProcessRecord directly for this purpose. + */ + private long mProcessStartInitiatedTimestampMillis; + + /** + * Indicates whether the number of current receivers has been incremented using + * {@link ProcessReceiverRecord#incrementCurReceivers()}. This allows to skip decrementing + * the receivers when it is not required. + */ + private boolean mCurReceiversIncremented; + public BroadcastProcessQueue(@NonNull BroadcastConstants constants, @NonNull String processName, int uid) { this.constants = Objects.requireNonNull(constants); @@ -652,6 +670,52 @@ class BroadcastProcessQueue { return mActiveFirstLaunch; } + public void incrementCurAppReceivers() { + app.mReceivers.incrementCurReceivers(); + mCurReceiversIncremented = true; + } + + public void decrementCurAppReceivers() { + if (mCurReceiversIncremented) { + app.mReceivers.decrementCurReceivers(); + mCurReceiversIncremented = false; + } + } + + public void setProcessStartInitiatedTimestampMillis(@UptimeMillisLong long timestampMillis) { + mProcessStartInitiatedTimestampMillis = timestampMillis; + } + + @UptimeMillisLong + public long getProcessStartInitiatedTimestampMillis() { + return mProcessStartInitiatedTimestampMillis; + } + + public boolean hasProcessStartInitiationTimedout() { + if (mProcessStartInitiatedTimestampMillis <= 0) { + return false; + } + return (SystemClock.uptimeMillis() - mProcessStartInitiatedTimestampMillis) + > constants.PENDING_COLD_START_ABANDON_TIMEOUT_MILLIS; + } + + /** + * Returns if the process start initiation is expected to be timed out at this point. This + * allows us to dump necessary state for debugging before the process start is timed out + * and discarded. + */ + public boolean isProcessStartInitiationTimeoutExpected() { + if (mProcessStartInitiatedTimestampMillis <= 0) { + return false; + } + return (SystemClock.uptimeMillis() - mProcessStartInitiatedTimestampMillis) + > constants.PENDING_COLD_START_ABANDON_TIMEOUT_MILLIS / 2; + } + + public void clearProcessStartInitiatedTimestampMillis() { + mProcessStartInitiatedTimestampMillis = 0; + } + /** * Get package name of the first application loaded into this process. */ @@ -1558,6 +1622,10 @@ class BroadcastProcessQueue { if (mActiveReEnqueued) { pw.print("activeReEnqueued:"); pw.println(mActiveReEnqueued); } + if (mProcessStartInitiatedTimestampMillis > 0) { + pw.print("processStartInitiatedTimestamp:"); pw.println( + TimeUtils.formatUptime(mProcessStartInitiatedTimestampMillis)); + } } @NeverCompile diff --git a/services/core/java/com/android/server/am/BroadcastQueueImpl.java b/services/core/java/com/android/server/am/BroadcastQueueImpl.java index d276b9a94791..6e893ad0a425 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueImpl.java @@ -534,6 +534,7 @@ class BroadcastQueueImpl extends BroadcastQueue { // skip to look for another warm process if (mRunningColdStart == null) { mRunningColdStart = queue; + mRunningColdStart.clearProcessStartInitiatedTimestampMillis(); } else if (isPendingColdStartValid()) { // Move to considering next runnable queue queue = nextQueue; @@ -542,6 +543,7 @@ class BroadcastQueueImpl extends BroadcastQueue { // Pending cold start is not valid, so clear it and move on. clearInvalidPendingColdStart(); mRunningColdStart = queue; + mRunningColdStart.clearProcessStartInitiatedTimestampMillis(); } } @@ -588,7 +590,9 @@ class BroadcastQueueImpl extends BroadcastQueue { @GuardedBy("mService") private boolean isPendingColdStartValid() { - if (mRunningColdStart.app.getPid() > 0) { + if (mRunningColdStart.hasProcessStartInitiationTimedout()) { + return false; + } else if (mRunningColdStart.app.getPid() > 0) { // If the process has already started, check if it wasn't killed. return !mRunningColdStart.app.isKilled(); } else { @@ -673,6 +677,7 @@ class BroadcastQueueImpl extends BroadcastQueue { if ((mRunningColdStart != null) && (mRunningColdStart == queue)) { // We've been waiting for this app to cold start, and it's ready // now; dispatch its next broadcast and clear the slot + mRunningColdStart.clearProcessStartInitiatedTimestampMillis(); mRunningColdStart = null; // Now that we're running warm, we can finally request that OOM @@ -756,6 +761,7 @@ class BroadcastQueueImpl extends BroadcastQueue { // We've been waiting for this app to cold start, and it had // trouble; clear the slot and fail delivery below + mRunningColdStart.clearProcessStartInitiatedTimestampMillis(); mRunningColdStart = null; // We might be willing to kick off another cold start @@ -1036,6 +1042,7 @@ class BroadcastQueueImpl extends BroadcastQueue { "startProcessLocked failed"); return true; } + queue.setProcessStartInitiatedTimestampMillis(SystemClock.uptimeMillis()); // TODO: b/335420031 - cache receiver intent to avoid multiple calls to getReceiverIntent. mService.mProcessList.getAppStartInfoTracker().handleProcessBroadcastStart( startTimeNs, queue.app, r.getReceiverIntent(receiver), r.alarm /* isAlarm */); @@ -1991,6 +1998,32 @@ class BroadcastQueueImpl extends BroadcastQueue { if (mRunningColdStart != null) { checkState(getRunningIndexOf(mRunningColdStart) >= 0, "isOrphaned " + mRunningColdStart); + + final BroadcastProcessQueue queue = getProcessQueue(mRunningColdStart.processName, + mRunningColdStart.uid); + checkState(queue == mRunningColdStart, "Conflicting " + mRunningColdStart + + " with queue " + queue + + ";\n mRunningColdStart.app: " + mRunningColdStart.app.toDetailedString() + + ";\n queue.app: " + queue.app.toDetailedString()); + + checkState(mRunningColdStart.app != null, "Empty cold start queue " + + mRunningColdStart); + + if (mRunningColdStart.isProcessStartInitiationTimeoutExpected()) { + final StringBuilder sb = new StringBuilder(); + sb.append("Process start timeout expected for app "); + sb.append(mRunningColdStart.app); + sb.append(" in queue "); + sb.append(mRunningColdStart); + sb.append("; startUpTime: "); + final long startupTimeMs = + mRunningColdStart.getProcessStartInitiatedTimestampMillis(); + sb.append(startupTimeMs == 0 ? "<none>" + : TimeUtils.formatDuration(startupTimeMs - SystemClock.uptimeMillis())); + sb.append(";\n app: "); + sb.append(mRunningColdStart.app.toDetailedString()); + checkState(false, sb.toString()); + } } // Verify health of all known process queues @@ -2090,7 +2123,7 @@ class BroadcastQueueImpl extends BroadcastQueue { @GuardedBy("mService") private void notifyStartedRunning(@NonNull BroadcastProcessQueue queue) { if (queue.app != null) { - queue.app.mReceivers.incrementCurReceivers(); + queue.incrementCurAppReceivers(); // Don't bump its LRU position if it's in the background restricted. if (mService.mInternal.getRestrictionLevel( @@ -2115,7 +2148,7 @@ class BroadcastQueueImpl extends BroadcastQueue { @GuardedBy("mService") private void notifyStoppedRunning(@NonNull BroadcastProcessQueue queue) { if (queue.app != null) { - queue.app.mReceivers.decrementCurReceivers(); + queue.decrementCurAppReceivers(); if (queue.runningOomAdjusted) { mService.enqueueOomAdjTargetLocked(queue.app); diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java index 31704c442290..4e1d77c26129 100644 --- a/services/core/java/com/android/server/am/ConnectionRecord.java +++ b/services/core/java/com/android/server/am/ConnectionRecord.java @@ -142,6 +142,10 @@ final class ConnectionRecord implements OomAdjusterModernImpl.Connection{ | Context.BIND_BYPASS_USER_NETWORK_RESTRICTIONS); } + @Override + public boolean transmitsCpuTime() { + return !hasFlag(Context.BIND_ALLOW_FREEZE); + } public long getFlags() { return flags; @@ -273,6 +277,9 @@ final class ConnectionRecord implements OomAdjusterModernImpl.Connection{ if (hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) { sb.append("CAPS "); } + if (hasFlag(Context.BIND_ALLOW_FREEZE)) { + sb.append("!CPU "); + } if (serviceDead) { sb.append("DEAD "); } diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 336a35e7a7e3..fa35da30bf4b 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -2802,7 +2802,7 @@ public class OomAdjuster { // we check the final procstate, and remove it if the procsate is below BFGS. capability |= getBfslCapabilityFromClient(client); - capability |= getCpuCapabilityFromClient(client); + capability |= getCpuCapabilityFromClient(cr, client); if (cr.notHasFlag(Context.BIND_WAIVE_PRIORITY)) { if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) { @@ -3259,7 +3259,7 @@ public class OomAdjuster { // we check the final procstate, and remove it if the procsate is below BFGS. capability |= getBfslCapabilityFromClient(client); - capability |= getCpuCapabilityFromClient(client); + capability |= getCpuCapabilityFromClient(conn, client); if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) { // If the other app is cached for any reason, for purposes here @@ -3502,10 +3502,13 @@ public class OomAdjuster { /** * @return the CPU capability from a client (of a service binding or provider). */ - private static int getCpuCapabilityFromClient(ProcessRecord client) { - // Just grant CPU capability every time - // TODO(b/370817323): Populate with reasons to not propagate cpu capability across bindings. - return client.mState.getCurCapability() & PROCESS_CAPABILITY_CPU_TIME; + private static int getCpuCapabilityFromClient(OomAdjusterModernImpl.Connection conn, + ProcessRecord client) { + if (conn == null || conn.transmitsCpuTime()) { + return client.mState.getCurCapability() & PROCESS_CAPABILITY_CPU_TIME; + } else { + return 0; + } } /** diff --git a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java index 1b7e8f0bd244..7e7b5685cf13 100644 --- a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java +++ b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java @@ -635,6 +635,15 @@ public class OomAdjusterModernImpl extends OomAdjuster { * Returns true if this connection can propagate capabilities. */ boolean canAffectCapabilities(); + + /** + * Returns whether this connection transmits PROCESS_CAPABILITY_CPU_TIME to the host, if the + * client possesses it. + */ + default boolean transmitsCpuTime() { + // Always lend this capability by default. + return true; + } } /** diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index eea667ef2f39..400c699bf93f 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -70,6 +70,7 @@ import com.android.server.wm.WindowProcessController; import com.android.server.wm.WindowProcessListener; import java.io.PrintWriter; +import java.io.StringWriter; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; @@ -1414,6 +1415,16 @@ class ProcessRecord implements WindowProcessListener { return mStringName = sb.toString(); } + String toDetailedString() { + final StringBuilder sb = new StringBuilder(); + sb.append(this); + final StringWriter sw = new StringWriter(); + final PrintWriter pw = new PrintWriter(sw); + dump(pw, " "); + sb.append(sw); + return sb.toString(); + } + /* * Return true if package has been added false if not */ diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index cfd22fbdeece..cb4342f27bc8 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -253,11 +253,12 @@ public class SettingsToPropertiesMapper { "pixel_state_server", "pixel_system_sw_video", "pixel_video_sw", + "pixel_vpn", "pixel_watch", + "pixel_watch_debug_trace", "pixel_wifi", "platform_compat", "platform_security", - "pixel_watch_debug_trace", "pmw", "power", "preload_safety", diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index f7d7ed541780..fb33cb1ff8c0 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -367,7 +367,7 @@ public class AppOpsService extends IAppOpsService.Stub { private static final Duration RATE_LIMITER_WINDOW = Duration.ofMillis(10); private final RateLimiter mRateLimiter = new RateLimiter(RATE_LIMITER_WINDOW); - volatile @NonNull HistoricalRegistry mHistoricalRegistry; + volatile @NonNull HistoricalRegistryInterface mHistoricalRegistry; /* * These are app op restrictions imposed per user from various parties. @@ -1056,7 +1056,11 @@ public class AppOpsService extends IAppOpsService.Stub { AppOpsManager.invalidateAppOpModeCache(); AppOpsManager.disableAppOpModeCache(); - mHistoricalRegistry = new HistoricalRegistry(this, context); + if (Flags.enableAllSqliteAppopsAccesses()) { + mHistoricalRegistry = new HistoricalRegistrySql(context); + } else { + mHistoricalRegistry = new HistoricalRegistry(this, context); + } } public void publish() { @@ -1424,7 +1428,7 @@ public class AppOpsService extends IAppOpsService.Stub { @GuardedBy("this") private void packageRemovedLocked(int uid, String packageName) { - getIoHandler().post(PooledLambda.obtainRunnable(HistoricalRegistry::clearHistory, + getIoHandler().post(PooledLambda.obtainRunnable(HistoricalRegistryInterface::clearHistory, mHistoricalRegistry, uid, packageName)); UidState uidState = mUidStates.get(uid); @@ -1992,10 +1996,12 @@ public class AppOpsService extends IAppOpsService.Stub { new String[attributionChainExemptPackages.size()]) : null; // Must not hold the appops lock - getIoHandler().post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOps, + getIoHandler().post(PooledLambda.obtainRunnable( + HistoricalRegistryInterface::getHistoricalOps, mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, dataType, filter, beginTimeMillis, endTimeMillis, flags, chainExemptPkgArray, - callback).recycleOnUse()); + callback + ).recycleOnUse()); } @Override @@ -2024,7 +2030,7 @@ public class AppOpsService extends IAppOpsService.Stub { // Must not hold the appops lock getIoHandler().post(PooledLambda.obtainRunnable( - HistoricalRegistry::getHistoricalOpsFromDiskRaw, + HistoricalRegistryInterface::getHistoricalOpsFromDiskRaw, mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, dataType, filter, beginTimeMillis, endTimeMillis, flags, chainExemptPkgArray, callback).recycleOnUse()); @@ -6961,7 +6967,6 @@ public class AppOpsService extends IAppOpsService.Stub { offsetHistory_enforcePermission(); // Must not hold the appops lock mHistoricalRegistry.offsetHistory(offsetMillis); - mHistoricalRegistry.offsetDiscreteHistory(offsetMillis); } @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_APPOPS) @@ -7002,7 +7007,13 @@ public class AppOpsService extends IAppOpsService.Stub { SystemClock.sleep(offlineDurationMillis); } - mHistoricalRegistry = new HistoricalRegistry(mHistoricalRegistry); + if (Flags.enableAllSqliteAppopsAccesses()) { + mHistoricalRegistry = new HistoricalRegistrySql( + (HistoricalRegistrySql) mHistoricalRegistry); + } else { + mHistoricalRegistry = new HistoricalRegistry((HistoricalRegistry) mHistoricalRegistry); + } + mHistoricalRegistry.systemReady(mContext.getContentResolver()); mHistoricalRegistry.persistPendingHistory(); } diff --git a/services/core/java/com/android/server/appop/AttributedOp.java b/services/core/java/com/android/server/appop/AttributedOp.java index 40085ed89294..b9bc27d9c696 100644 --- a/services/core/java/com/android/server/appop/AttributedOp.java +++ b/services/core/java/com/android/server/appop/AttributedOp.java @@ -163,7 +163,7 @@ final class AttributedOp { public void rejected(@AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags) { rejected(System.currentTimeMillis(), uidState, flags); - mAppOpsService.mHistoricalRegistry.incrementOpRejected(parent.op, parent.uid, + mAppOpsService.mHistoricalRegistry.incrementOpRejectedCount(parent.op, parent.uid, parent.packageName, tag, uidState, flags); } diff --git a/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java b/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java index 0e1fbf3a6d1a..f50f45a182d0 100644 --- a/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java +++ b/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java @@ -118,7 +118,7 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry { @Override void shutdown() { mSqliteWriteHandler.removeAllPendingMessages(); - mDiscreteOpsDbHelper.insertDiscreteOps(mDiscreteOpCache.getAllEventsAndClear()); + mDiscreteOpsDbHelper.insertDiscreteOps(mDiscreteOpCache.evictAllAppOpEvents()); } @Override @@ -172,10 +172,14 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry { @Nullable String[] opNamesFilter, @Nullable String attributionTagFilter, int opFlagsFilter, Set<String> attributionExemptPkgs) { + IntArray opCodes = getAppOpCodes(filter, opNamesFilter); // flush the cache into database before read. - mDiscreteOpsDbHelper.insertDiscreteOps(mDiscreteOpCache.getAllEventsAndClear()); + if (opCodes != null) { + mDiscreteOpsDbHelper.insertDiscreteOps(mDiscreteOpCache.evictAppOpEvents(opCodes)); + } else { + mDiscreteOpsDbHelper.insertDiscreteOps(mDiscreteOpCache.evictAllAppOpEvents()); + } boolean assembleChains = attributionExemptPkgs != null; - IntArray opCodes = getAppOpCodes(filter, opNamesFilter); beginTimeMillis = Math.max(beginTimeMillis, Instant.now().minus(sDiscreteHistoryCutoff, ChronoUnit.MILLIS).toEpochMilli()); List<DiscreteOp> discreteOps = mDiscreteOpsDbHelper.getDiscreteOps(filter, uidFilter, @@ -214,7 +218,7 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry { @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix, int nDiscreteOps) { // flush the cache into database before dump. - mDiscreteOpsDbHelper.insertDiscreteOps(mDiscreteOpCache.getAllEventsAndClear()); + mDiscreteOpsDbHelper.insertDiscreteOps(mDiscreteOpCache.evictAllAppOpEvents()); IntArray opCodes = new IntArray(); if (dumpOp != AppOpsManager.OP_NONE) { opCodes.add(dumpOp); @@ -366,7 +370,7 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry { try { List<DiscreteOp> evictedEvents; synchronized (mDiscreteOpCache) { - evictedEvents = mDiscreteOpCache.evict(); + evictedEvents = mDiscreteOpCache.evictOldAppOpEvents(); } mDiscreteOpsDbHelper.insertDiscreteOps(evictedEvents); } finally { @@ -389,7 +393,7 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry { try { List<DiscreteOp> evictedEvents; synchronized (mDiscreteOpCache) { - evictedEvents = mDiscreteOpCache.evict(); + evictedEvents = mDiscreteOpCache.evictOldAppOpEvents(); // if nothing to evict, just write the whole cache to database. if (evictedEvents.isEmpty() && mDiscreteOpCache.size() >= mDiscreteOpCache.capacity()) { @@ -451,9 +455,10 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry { } /** - * Evict entries older than {@link DiscreteOpsRegistry#sDiscreteHistoryQuantization}. + * Evict entries older than {@link DiscreteOpsRegistry#sDiscreteHistoryQuantization} i.e. + * app op events older than one minute (default quantization) will be evicted. */ - private List<DiscreteOp> evict() { + private List<DiscreteOp> evictOldAppOpEvents() { synchronized (this) { List<DiscreteOp> evictedEvents = new ArrayList<>(); Set<DiscreteOp> snapshot = new ArraySet<>(mCache); @@ -470,11 +475,9 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry { } /** - * Remove all the entries from cache. - * - * @return return all removed entries. + * Evict all app op entries from cache, and return the list of removed ops. */ - public List<DiscreteOp> getAllEventsAndClear() { + public List<DiscreteOp> evictAllAppOpEvents() { synchronized (this) { List<DiscreteOp> cachedOps = new ArrayList<>(mCache.size()); if (mCache.isEmpty()) { @@ -486,6 +489,25 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry { } } + /** + * Evict specified app ops from cache, and return the list of evicted ops. + */ + public List<DiscreteOp> evictAppOpEvents(IntArray ops) { + synchronized (this) { + List<DiscreteOp> evictedOps = new ArrayList<>(); + if (mCache.isEmpty()) { + return evictedOps; + } + for (DiscreteOp discreteOp: mCache) { + if (ops.contains(discreteOp.getOpCode())) { + evictedOps.add(discreteOp); + } + } + evictedOps.forEach(mCache::remove); + return evictedOps; + } + } + int size() { return mCache.size(); } @@ -646,7 +668,10 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry { + ", uidState=" + getUidStateName(mUidState) + ", chainId=" + mChainId + ", accessTime=" + mAccessTime - + ", duration=" + mDuration + '}'; + + ", mDiscretizedAccessTime=" + mDiscretizedAccessTime + + ", duration=" + mDuration + + ", mDiscretizedDuration=" + mDiscretizedDuration + + '}'; } public int getUid() { diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java index 06e43e8ec68d..a8128dd11cfe 100644 --- a/services/core/java/com/android/server/appop/HistoricalRegistry.java +++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java @@ -128,7 +128,7 @@ import java.util.concurrent.TimeUnit; */ // TODO (bug:122218838): Make sure we handle start of epoch time // TODO (bug:122218838): Validate changed time is handled correctly -final class HistoricalRegistry { +final class HistoricalRegistry implements HistoricalRegistryInterface { private static final boolean DEBUG = false; private static final boolean KEEP_WTF_LOG = Build.IS_DEBUGGABLE; @@ -218,7 +218,8 @@ final class HistoricalRegistry { mDiscreteRegistry = other.mDiscreteRegistry; } - void systemReady(@NonNull ContentResolver resolver) { + @Override + public void systemReady(@NonNull ContentResolver resolver) { mDiscreteRegistry.systemReady(); final Uri uri = Settings.Global.getUriFor(Settings.Global.APPOP_HISTORY_PARAMETERS); resolver.registerContentObserver(uri, false, new ContentObserver( @@ -320,8 +321,10 @@ final class HistoricalRegistry { + "=" + setting + " resetting!"); } - void dump(String prefix, PrintWriter pw, int filterUid, @Nullable String filterPackage, - @Nullable String filterAttributionTag, int filterOp, + + @Override + public void dump(String prefix, PrintWriter pw, int filterUid, + @Nullable String filterPackage, @Nullable String filterAttributionTag, int filterOp, @HistoricalOpsRequestFilter int filter) { synchronized (mOnDiskLock) { synchronized (mInMemoryLock) { @@ -366,7 +369,8 @@ final class HistoricalRegistry { } } - void dumpDiscreteData(@NonNull PrintWriter pw, int uidFilter, + @Override + public void dumpDiscreteData(@NonNull PrintWriter pw, int uidFilter, @Nullable String packageNameFilter, @Nullable String attributionTagFilter, @HistoricalOpsRequestFilter int filter, int dumpOp, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix, @@ -381,7 +385,8 @@ final class HistoricalRegistry { } } - void getHistoricalOpsFromDiskRaw(int uid, @Nullable String packageName, + @Override + public void getHistoricalOpsFromDiskRaw(int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String[] opNames, @OpHistoryFlags int historyFlags, @HistoricalOpsRequestFilter int filter, long beginTimeMillis, long endTimeMillis, @OpFlags int flags, @@ -414,11 +419,12 @@ final class HistoricalRegistry { callback.sendResult(payload); } - void getHistoricalOps(int uid, @Nullable String packageName, @Nullable String attributionTag, - @Nullable String[] opNames, @OpHistoryFlags int historyFlags, - @HistoricalOpsRequestFilter int filter, long beginTimeMillis, long endTimeMillis, - @OpFlags int flags, @Nullable String[] attributionExemptPkgs, - @NonNull RemoteCallback callback) { + @Override + public void getHistoricalOps(int uid, @Nullable String packageName, + @Nullable String attributionTag, @Nullable String[] opNames, + @OpHistoryFlags int historyFlags, @HistoricalOpsRequestFilter int filter, + long beginTimeMillis, long endTimeMillis, @OpFlags int flags, + @Nullable String[] attributionExemptPkgs, @NonNull RemoteCallback callback) { final long currentTimeMillis = System.currentTimeMillis(); if (endTimeMillis == Long.MAX_VALUE) { endTimeMillis = currentTimeMillis; @@ -493,7 +499,8 @@ final class HistoricalRegistry { callback.sendResult(payload); } - void incrementOpAccessedCount(int op, int uid, @NonNull String packageName, + @Override + public void incrementOpAccessedCount(int op, int uid, @NonNull String packageName, @NonNull String deviceId, @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags, long accessTime, @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId, @@ -515,7 +522,8 @@ final class HistoricalRegistry { } } - void incrementOpRejected(int op, int uid, @NonNull String packageName, + @Override + public void incrementOpRejectedCount(int op, int uid, @NonNull String packageName, @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags) { synchronized (mInMemoryLock) { if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) { @@ -530,7 +538,8 @@ final class HistoricalRegistry { } } - void increaseOpAccessDuration(int op, int uid, @NonNull String packageName, + @Override + public void increaseOpAccessDuration(int op, int uid, @NonNull String packageName, @NonNull String deviceId, @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags, long eventStartTime, long increment, @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId) { @@ -550,7 +559,8 @@ final class HistoricalRegistry { } } - void setHistoryParameters(@HistoricalMode int mode, + @Override + public void setHistoryParameters(@HistoricalMode int mode, long baseSnapshotInterval, long intervalCompressionMultiplier) { synchronized (mOnDiskLock) { synchronized (mInMemoryLock) { @@ -585,7 +595,8 @@ final class HistoricalRegistry { } } - void offsetHistory(long offsetMillis) { + @Override + public void offsetHistory(long offsetMillis) { synchronized (mOnDiskLock) { synchronized (mInMemoryLock) { if (!isPersistenceInitializedMLocked()) { @@ -607,13 +618,11 @@ final class HistoricalRegistry { mPersistence.persistHistoricalOpsDLocked(history); } } - } - - void offsetDiscreteHistory(long offsetMillis) { mDiscreteRegistry.offsetHistory(offsetMillis); } - void addHistoricalOps(HistoricalOps ops) { + @Override + public void addHistoricalOps(HistoricalOps ops) { final List<HistoricalOps> pendingWrites; synchronized (mInMemoryLock) { if (!isPersistenceInitializedMLocked()) { @@ -634,7 +643,8 @@ final class HistoricalRegistry { offsetHistory(offsetMillis); } - void resetHistoryParameters() { + @Override + public void resetHistoryParameters() { if (!isPersistenceInitializedMLocked()) { Slog.d(LOG_TAG, "Interaction before persistence initialized"); return; @@ -644,7 +654,8 @@ final class HistoricalRegistry { mDiscreteRegistry.setDebugMode(false); } - void clearHistory(int uid, String packageName) { + @Override + public void clearHistory(int uid, String packageName) { synchronized (mOnDiskLock) { synchronized (mInMemoryLock) { if (!isPersistenceInitializedMLocked()) { @@ -668,11 +679,13 @@ final class HistoricalRegistry { mDiscreteRegistry.clearHistory(uid, packageName); } - void writeAndClearDiscreteHistory() { + @Override + public void writeAndClearDiscreteHistory() { mDiscreteRegistry.writeAndClearOldAccessHistory(); } - void clearAllHistory() { + @Override + public void clearAllHistory() { clearHistoricalRegistry(); mDiscreteRegistry.clearHistory(); } @@ -741,7 +754,8 @@ final class HistoricalRegistry { return mCurrentHistoricalOps; } - void shutdown() { + @Override + public void shutdown() { synchronized (mInMemoryLock) { if (mMode == AppOpsManager.HISTORICAL_MODE_DISABLED) { return; @@ -752,7 +766,8 @@ final class HistoricalRegistry { mDiscreteRegistry.shutdown(); } - void persistPendingHistory() { + @Override + public void persistPendingHistory() { final List<HistoricalOps> pendingWrites; synchronized (mOnDiskLock) { synchronized (mInMemoryLock) { diff --git a/services/core/java/com/android/server/appop/HistoricalRegistryInterface.java b/services/core/java/com/android/server/appop/HistoricalRegistryInterface.java new file mode 100644 index 000000000000..b6210a727e6d --- /dev/null +++ b/services/core/java/com/android/server/appop/HistoricalRegistryInterface.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2025 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.appop; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.AppOpsManager; +import android.content.ContentResolver; +import android.os.RemoteCallback; + +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * A registry to record app operation access events, which are generated upon an application's + * access to private data or system resources. These events are stored in both aggregated + * and individual/discrete formats. + */ +public interface HistoricalRegistryInterface { + /** + * A callback to inform system components are ready. + */ + void systemReady(@NonNull ContentResolver resolver); + + /** + * Callback for system shutdown. + */ + void shutdown(); + + /** + * Dumps aggregated/historical events to the console based on the filters. + */ + void dump(String prefix, PrintWriter pw, int filterUid, + @Nullable String filterPackage, @Nullable String filterAttributionTag, int filterOp, + @AppOpsManager.HistoricalOpsRequestFilter int filter); + + /** + * Dumps discrete/individual events to the console based on filters. + */ + void dumpDiscreteData(@NonNull PrintWriter pw, int uidFilter, + @Nullable String packageNameFilter, @Nullable String attributionTagFilter, + @AppOpsManager.HistoricalOpsRequestFilter int filter, int dumpOp, + @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix, + int nDiscreteOps); + + /** + * Record duration for given op. + */ + void increaseOpAccessDuration(int op, int uid, @NonNull String packageName, + @NonNull String deviceId, @Nullable String attributionTag, + @AppOpsManager.UidState int uidState, + @AppOpsManager.OpFlags int flags, long eventStartTime, long increment, + @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId); + + /** + * Record access counts for given op. + */ + void incrementOpAccessedCount(int op, int uid, @NonNull String packageName, + @NonNull String deviceId, @Nullable String attributionTag, + @AppOpsManager.UidState int uidState, + @AppOpsManager.OpFlags int flags, long accessTime, + @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId, + int accessCount); + + /** + * Record rejected counts for given op. + */ + void incrementOpRejectedCount(int op, int uid, @NonNull String packageName, + @Nullable String attributionTag, @AppOpsManager.UidState int uidState, + @AppOpsManager.OpFlags int flags); + + /** + * Read historical ops from both aggregated and discrete events based on input filter. + */ + void getHistoricalOps(int uid, @Nullable String packageName, @Nullable String attributionTag, + @Nullable String[] opNames, @AppOpsManager.OpHistoryFlags int historyFlags, + @AppOpsManager.HistoricalOpsRequestFilter int filter, long beginTimeMillis, + long endTimeMillis, + @AppOpsManager.OpFlags int flags, @Nullable String[] attributionExemptPkgs, + @NonNull RemoteCallback callback); + + /** + * Remove app op events for a given UID and package. + */ + void clearHistory(int uid, String packageName); + + /** + * A periodic callback from {@link AppOpsService} to flush the in memory discrete + * app op events to disk/database. + */ + void writeAndClearDiscreteHistory(); + + /** + * A callback flush the in memory app op events to disk/database. + */ + void persistPendingHistory(); + + /** + * Set history parameters. + * + * @param mode - Whether historical registry is Active, Passive or Disabled. + * @param baseSnapshotInterval - Interval between 2 snapshots, default 15 minutes. + * @param intervalCompressionMultiplier - Interval compression multiplier, default is 10. + */ + void setHistoryParameters(@AppOpsManager.HistoricalMode int mode, + long baseSnapshotInterval, long intervalCompressionMultiplier); + + /** + * Reset history parameters to defaults. + */ + void resetHistoryParameters(); + + /** + * Remove all app op accesses from both aggregated and individual event's storage. + */ + void clearAllHistory(); + + /** + * Offsets the history by the given duration. + */ + void offsetHistory(long offsetMillis); + + /** + * Retrieve historical app op stats for a period form disk. + */ + void getHistoricalOpsFromDiskRaw(int uid, @Nullable String packageName, + @Nullable String attributionTag, @Nullable String[] opNames, + @AppOpsManager.OpHistoryFlags int historyFlags, + @AppOpsManager.HistoricalOpsRequestFilter int filter, + long beginTimeMillis, long endTimeMillis, @AppOpsManager.OpFlags int flags, + String[] attributionExemptedPackages, @NonNull RemoteCallback callback); + + /** + * Adds ops to the history directly. This could be useful for testing especially + * when the historical registry operates in passive mode. + */ + void addHistoricalOps(AppOpsManager.HistoricalOps ops); +} diff --git a/services/core/java/com/android/server/appop/HistoricalRegistrySql.java b/services/core/java/com/android/server/appop/HistoricalRegistrySql.java new file mode 100644 index 000000000000..cf5b941c7b33 --- /dev/null +++ b/services/core/java/com/android/server/appop/HistoricalRegistrySql.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2025 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.appop; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.AppOpsManager; +import android.content.ContentResolver; +import android.content.Context; +import android.os.RemoteCallback; + +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.Date; + +// TODO add more documentation later + +/** + * This historical registry implementation store app events in sqlite. The data is stored in 2 + * tables 1) discrete events 2) aggregated events. + */ +public class HistoricalRegistrySql implements HistoricalRegistryInterface { + // TODO impl will be added in a separate CL + HistoricalRegistrySql(Context context) { + } + + HistoricalRegistrySql(HistoricalRegistrySql other) { + } + + @Override + public void systemReady(@NonNull ContentResolver resolver) { + + } + + @Override + public void shutdown() { + + } + + @Override + public void dump(String prefix, PrintWriter pw, int filterUid, + @Nullable String filterPackage, @Nullable String filterAttributionTag, int filterOp, + int filter) { + + } + + @Override + public void dumpDiscreteData(@NonNull PrintWriter pw, int uidFilter, + @Nullable String packageNameFilter, @Nullable String attributionTagFilter, int filter, + int dumpOp, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix, + int nDiscreteOps) { + + } + + @Override + public void increaseOpAccessDuration(int op, int uid, @NonNull String packageName, + @NonNull String deviceId, @Nullable String attributionTag, int uidState, int flags, + long eventStartTime, long increment, int attributionFlags, int attributionChainId) { + + } + + @Override + public void incrementOpAccessedCount(int op, int uid, @NonNull String packageName, + @NonNull String deviceId, @Nullable String attributionTag, int uidState, int flags, + long accessTime, int attributionFlags, int attributionChainId, int accessCount) { + + } + + @Override + public void incrementOpRejectedCount(int op, int uid, @NonNull String packageName, + @Nullable String attributionTag, int uidState, int flags) { + + } + + @Override + public void getHistoricalOps(int uid, @Nullable String packageName, + @Nullable String attributionTag, @Nullable String[] opNames, int historyFlags, + int filter, long beginTimeMillis, long endTimeMillis, int flags, + @Nullable String[] attributionExemptPkgs, @NonNull RemoteCallback callback) { + + } + + @Override + public void clearHistory(int uid, String packageName) { + + } + + @Override + public void writeAndClearDiscreteHistory() { + + } + + @Override + public void persistPendingHistory() { + + } + + @Override + public void setHistoryParameters(int mode, long baseSnapshotInterval, + long intervalCompressionMultiplier) { + + } + + @Override + public void resetHistoryParameters() { + + } + + @Override + public void clearAllHistory() { + + } + + @Override + public void offsetHistory(long offsetMillis) { + + } + + @Override + public void getHistoricalOpsFromDiskRaw(int uid, @Nullable String packageName, + @Nullable String attributionTag, @Nullable String[] opNames, int historyFlags, + int filter, long beginTimeMillis, long endTimeMillis, int flags, + String[] attributionExemptedPackages, @NonNull RemoteCallback callback) { + + } + + @Override + public void addHistoricalOps(AppOpsManager.HistoricalOps ops) { + + } +} diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 4b5f06b13885..8ef79a916530 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -1472,8 +1472,8 @@ public class AudioDeviceBroker { mAudioService.postAccessoryPlugMediaUnmute(device); } - /*package*/ int getVolumeForDeviceIgnoreMute(int streamType, int device) { - return mAudioService.getVolumeForDeviceIgnoreMute(streamType, device); + /*package*/ int getVssVolumeForDevice(int streamType, int device) { + return mAudioService.getVssVolumeForDevice(streamType, device); } /*package*/ int getMaxVssVolumeForStream(int streamType) { diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 2e6d98485e85..829d9ea7495f 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -2482,7 +2482,7 @@ public class AudioDeviceInventory { @GuardedBy("mDevicesLock") private void makeHearingAidDeviceAvailable( String address, String name, int streamType, String eventSource) { - final int hearingAidVolIndex = mDeviceBroker.getVolumeForDeviceIgnoreMute(streamType, + final int hearingAidVolIndex = mDeviceBroker.getVssVolumeForDevice(streamType, DEVICE_OUT_HEARING_AID); mDeviceBroker.postSetHearingAidVolumeIndex(hearingAidVolIndex, streamType); @@ -2672,7 +2672,7 @@ public class AudioDeviceInventory { } final int leAudioVolIndex = (volumeIndex == -1) - ? mDeviceBroker.getVolumeForDeviceIgnoreMute(streamType, device) + ? mDeviceBroker.getVssVolumeForDevice(streamType, device) : volumeIndex; final int maxIndex = mDeviceBroker.getMaxVssVolumeForStream(streamType); mDeviceBroker.postSetLeAudioVolumeIndex(leAudioVolIndex, maxIndex, streamType); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index a43e4d98c077..766456134b20 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -529,7 +529,7 @@ public class AudioService extends IAudioService.Stub */ private InputDeviceVolumeHelper mInputDeviceVolumeHelper; - /*package*/ int getVolumeForDeviceIgnoreMute(int stream, int device) { + /*package*/ int getVssVolumeForDevice(int stream, int device) { final VolumeStreamState streamState = mStreamStates.get(stream); return streamState != null ? streamState.getIndex(device) : -1; } @@ -4997,6 +4997,8 @@ public class AudioService extends IAudioService.Stub pw.println("\tcom.android.media.audio.disablePrescaleAbsoluteVolume:" + disablePrescaleAbsoluteVolume()); pw.println("\tcom.android.media.audio.setStreamVolumeOrder - EOL"); + pw.println("\tandroid.media.audio.ringtoneUserUriCheck:" + + android.media.audio.Flags.ringtoneUserUriCheck()); pw.println("\tandroid.media.audio.roForegroundAudioControl:" + roForegroundAudioControl()); pw.println("\tandroid.media.audio.scoManagedByAudio:" @@ -5098,7 +5100,7 @@ public class AudioService extends IAudioService.Stub } final int device = absVolumeDevices.toArray(new Integer[0])[0].intValue(); - final int index = getVolumeForDeviceIgnoreMute(streamType, device); + final int index = getStreamVolume(streamType, device); if (DEBUG_VOL) { Slog.i(TAG, "onUpdateContextualVolumes streamType: " + streamType diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java index 67afff79dffd..643f3308d8f5 100644 --- a/services/core/java/com/android/server/audio/SoundDoseHelper.java +++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java @@ -724,7 +724,7 @@ public class SoundDoseHelper { int device = mAudioService.getDeviceForStream(AudioSystem.STREAM_MUSIC); if (safeDevicesContains(device) && isStreamActive) { scheduleMusicActiveCheck(); - int index = mAudioService.getVolumeForDeviceIgnoreMute(AudioSystem.STREAM_MUSIC, + int index = mAudioService.getVssVolumeForDevice(AudioSystem.STREAM_MUSIC, device); if (index > safeMediaVolumeIndex(device)) { // Approximate cumulative active music time diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index c2fecf283a34..d9db178e0dc2 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -568,6 +568,7 @@ public class InputManagerService extends IInputManager.Stub } mWindowManagerCallbacks = callbacks; registerLidSwitchCallbackInternal(mWindowManagerCallbacks); + mKeyGestureController.setWindowManagerCallbacks(callbacks); } public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) { @@ -2756,24 +2757,6 @@ public class InputManagerService extends IInputManager.Stub @Nullable IBinder focussedToken) { return InputManagerService.this.handleKeyGestureEvent(event); } - - @Override - public boolean isKeyGestureSupported(int gestureType) { - switch (gestureType) { - case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP: - case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN: - case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE: - case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK: - case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS: - case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS: - case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS: - case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS: - return true; - default: - return false; - - } - } }); } @@ -3371,6 +3354,11 @@ public class InputManagerService extends IInputManager.Stub */ @Nullable SurfaceControl createSurfaceForGestureMonitor(String name, int displayId); + + /** + * Provide information on whether the keyguard is currently locked or not. + */ + boolean isKeyguardLocked(int displayId); } /** diff --git a/services/core/java/com/android/server/input/KeyGestureController.java b/services/core/java/com/android/server/input/KeyGestureController.java index ef5babf19d83..395c77322c04 100644 --- a/services/core/java/com/android/server/input/KeyGestureController.java +++ b/services/core/java/com/android/server/input/KeyGestureController.java @@ -62,8 +62,10 @@ import android.view.Display; import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.KeyEvent; +import android.view.ViewConfiguration; import com.android.internal.R; +import com.android.internal.accessibility.AccessibilityShortcutController; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.IShortcutService; @@ -104,6 +106,7 @@ final class KeyGestureController { private static final int MSG_NOTIFY_KEY_GESTURE_EVENT = 1; private static final int MSG_PERSIST_CUSTOM_GESTURES = 2; private static final int MSG_LOAD_CUSTOM_GESTURES = 3; + private static final int MSG_ACCESSIBILITY_SHORTCUT = 4; // must match: config_settingsKeyBehavior in config.xml private static final int SETTINGS_KEY_BEHAVIOR_SETTINGS_ACTIVITY = 0; @@ -122,12 +125,15 @@ final class KeyGestureController { static final int POWER_VOLUME_UP_BEHAVIOR_GLOBAL_ACTIONS = 2; private final Context mContext; + private InputManagerService.WindowManagerCallbacks mWindowManagerCallbacks; private final Handler mHandler; private final Handler mIoHandler; private final int mSystemPid; private final KeyCombinationManager mKeyCombinationManager; private final SettingsObserver mSettingsObserver; private final AppLaunchShortcutManager mAppLaunchShortcutManager; + @VisibleForTesting + final AccessibilityShortcutController mAccessibilityShortcutController; private final InputGestureManager mInputGestureManager; private final DisplayManager mDisplayManager; @GuardedBy("mInputDataStore") @@ -175,8 +181,14 @@ final class KeyGestureController { private final boolean mVisibleBackgroundUsersEnabled = isVisibleBackgroundUsersEnabled(); - KeyGestureController(Context context, Looper looper, Looper ioLooper, + public KeyGestureController(Context context, Looper looper, Looper ioLooper, InputDataStore inputDataStore) { + this(context, looper, ioLooper, inputDataStore, new Injector()); + } + + @VisibleForTesting + KeyGestureController(Context context, Looper looper, Looper ioLooper, + InputDataStore inputDataStore, Injector injector) { mContext = context; mHandler = new Handler(looper, this::handleMessage); mIoHandler = new Handler(ioLooper, this::handleIoMessage); @@ -197,6 +209,8 @@ final class KeyGestureController { mSettingsObserver = new SettingsObserver(mHandler); mAppLaunchShortcutManager = new AppLaunchShortcutManager(mContext); mInputGestureManager = new InputGestureManager(mContext); + mAccessibilityShortcutController = injector.getAccessibilityShortcutController(mContext, + mHandler); mDisplayManager = Objects.requireNonNull(mContext.getSystemService(DisplayManager.class)); mInputDataStore = inputDataStore; mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); @@ -295,8 +309,8 @@ final class KeyGestureController { KeyEvent.KEYCODE_VOLUME_UP) { @Override public boolean preCondition() { - return isKeyGestureSupported( - KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD); + return mAccessibilityShortcutController.isAccessibilityShortcutAvailable( + mWindowManagerCallbacks.isKeyguardLocked(DEFAULT_DISPLAY)); } @Override @@ -376,15 +390,15 @@ final class KeyGestureController { KeyEvent.KEYCODE_DPAD_DOWN) { @Override public boolean preCondition() { - return isKeyGestureSupported( - KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD); + return mAccessibilityShortcutController + .isAccessibilityShortcutAvailable(false); } @Override public void execute() { handleMultiKeyGesture( new int[]{KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN}, - KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD, + KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD, KeyGestureEvent.ACTION_GESTURE_START, 0); } @@ -392,7 +406,7 @@ final class KeyGestureController { public void cancel() { handleMultiKeyGesture( new int[]{KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN}, - KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD, + KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD, KeyGestureEvent.ACTION_GESTURE_COMPLETE, KeyGestureEvent.FLAG_CANCELLED); } @@ -438,6 +452,7 @@ final class KeyGestureController { mSettingsObserver.observe(); mAppLaunchShortcutManager.systemRunning(); mInputGestureManager.systemRunning(); + initKeyGestures(); int userId; synchronized (mUserLock) { @@ -447,6 +462,27 @@ final class KeyGestureController { mIoHandler.obtainMessage(MSG_LOAD_CUSTOM_GESTURES, userId).sendToTarget(); } + @SuppressLint("MissingPermission") + private void initKeyGestures() { + InputManager im = Objects.requireNonNull(mContext.getSystemService(InputManager.class)); + im.registerKeyGestureEventHandler((event, focusedToken) -> { + switch (event.getKeyGestureType()) { + case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD: + if (event.getAction() == KeyGestureEvent.ACTION_GESTURE_START) { + mHandler.removeMessages(MSG_ACCESSIBILITY_SHORTCUT); + mHandler.sendMessageDelayed( + mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT), + getAccessibilityShortcutTimeout()); + } else { + mHandler.removeMessages(MSG_ACCESSIBILITY_SHORTCUT); + } + return true; + default: + return false; + } + }); + } + public boolean interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { if (mVisibleBackgroundUsersEnabled && shouldIgnoreKeyEventForVisibleBackgroundUser(event)) { return false; @@ -971,17 +1007,6 @@ final class KeyGestureController { return false; } - private boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType) { - synchronized (mKeyGestureHandlerRecords) { - for (KeyGestureHandlerRecord handler : mKeyGestureHandlerRecords.values()) { - if (handler.isKeyGestureSupported(gestureType)) { - return true; - } - } - } - return false; - } - public void notifyKeyGestureCompleted(int deviceId, int[] keycodes, int modifierState, @KeyGestureEvent.KeyGestureType int gestureType) { // TODO(b/358569822): Once we move the gesture detection logic to IMS, we ideally @@ -1019,9 +1044,16 @@ final class KeyGestureController { synchronized (mUserLock) { mCurrentUserId = userId; } + mAccessibilityShortcutController.setCurrentUser(userId); mIoHandler.obtainMessage(MSG_LOAD_CUSTOM_GESTURES, userId).sendToTarget(); } + + public void setWindowManagerCallbacks( + @NonNull InputManagerService.WindowManagerCallbacks callbacks) { + mWindowManagerCallbacks = callbacks; + } + private boolean isDefaultDisplayOn() { Display defaultDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY); if (defaultDisplay == null) { @@ -1068,6 +1100,9 @@ final class KeyGestureController { AidlKeyGestureEvent event = (AidlKeyGestureEvent) msg.obj; notifyKeyGestureEvent(event); break; + case MSG_ACCESSIBILITY_SHORTCUT: + mAccessibilityShortcutController.performAccessibilityShortcut(); + break; } return true; } @@ -1347,17 +1382,6 @@ final class KeyGestureController { } return false; } - - public boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType) { - try { - return mKeyGestureHandler.isKeyGestureSupported(gestureType); - } catch (RemoteException ex) { - Slog.w(TAG, "Failed to identify if key gesture type is supported by the " - + "process " + mPid + ", assuming it died.", ex); - binderDied(); - } - return false; - } } private class SettingsObserver extends ContentObserver { @@ -1413,6 +1437,25 @@ final class KeyGestureController { return event; } + private long getAccessibilityShortcutTimeout() { + synchronized (mUserLock) { + final ViewConfiguration config = ViewConfiguration.get(mContext); + final boolean hasDialogShown = Settings.Secure.getIntForUser( + mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, mCurrentUserId) != 0; + final boolean skipTimeoutRestriction = + Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.SKIP_ACCESSIBILITY_SHORTCUT_DIALOG_TIMEOUT_RESTRICTION, + 0, mCurrentUserId) != 0; + + // If users manually set the volume key shortcut for any accessibility service, the + // system would bypass the timeout restriction of the shortcut dialog. + return hasDialogShown || skipTimeoutRestriction + ? config.getAccessibilityShortcutKeyTimeoutAfterConfirmation() + : config.getAccessibilityShortcutKeyTimeout(); + } + } + public void dump(IndentingPrintWriter ipw) { ipw.println("KeyGestureController:"); ipw.increaseIndent(); @@ -1459,4 +1502,12 @@ final class KeyGestureController { mAppLaunchShortcutManager.dump(ipw); mInputGestureManager.dump(ipw); } + + @VisibleForTesting + static class Injector { + AccessibilityShortcutController getAccessibilityShortcutController(Context context, + Handler handler) { + return new AccessibilityShortcutController(context, handler, UserHandle.USER_SYSTEM); + } + } } diff --git a/services/core/java/com/android/server/inputmethod/IInputMethodManagerImpl.java b/services/core/java/com/android/server/inputmethod/IInputMethodManagerImpl.java index 02987a98417f..15f186b047f2 100644 --- a/services/core/java/com/android/server/inputmethod/IInputMethodManagerImpl.java +++ b/services/core/java/com/android/server/inputmethod/IInputMethodManagerImpl.java @@ -132,8 +132,8 @@ final class IInputMethodManagerImpl extends IInputMethodManager.Stub { @Nullable EditorInfo editorInfo, IRemoteInputConnection inputConnection, IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, int unverifiedTargetSdkVersion, @UserIdInt int userId, - @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq, - boolean useAsyncShowHideMethod); + @NonNull ImeOnBackInvokedDispatcher imeDispatcher, boolean imeRequestedVisible, + int startInputSeq, boolean useAsyncShowHideMethod); InputBindResult startInputOrWindowGainedFocus( @StartInputReason int startInputReason, IInputMethodClient client, @@ -142,7 +142,7 @@ final class IInputMethodManagerImpl extends IInputMethodManager.Stub { @Nullable EditorInfo editorInfo, IRemoteInputConnection inputConnection, IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, int unverifiedTargetSdkVersion, @UserIdInt int userId, - @NonNull ImeOnBackInvokedDispatcher imeDispatcher); + @NonNull ImeOnBackInvokedDispatcher imeDispatcher, boolean imeRequestedVisible); void showInputMethodPickerFromClient(IInputMethodClient client, int auxiliarySubtypeMode); @@ -324,11 +324,11 @@ final class IInputMethodManagerImpl extends IInputMethodManager.Stub { IRemoteInputConnection inputConnection, IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, int unverifiedTargetSdkVersion, @UserIdInt int userId, - @NonNull ImeOnBackInvokedDispatcher imeDispatcher) { + @NonNull ImeOnBackInvokedDispatcher imeDispatcher, boolean imeRequestedVisible) { return mCallback.startInputOrWindowGainedFocus( startInputReason, client, windowToken, startInputFlags, softInputMode, windowFlags, editorInfo, inputConnection, remoteAccessibilityInputConnection, - unverifiedTargetSdkVersion, userId, imeDispatcher); + unverifiedTargetSdkVersion, userId, imeDispatcher, imeRequestedVisible); } @Override @@ -340,13 +340,13 @@ final class IInputMethodManagerImpl extends IInputMethodManager.Stub { IRemoteInputConnection inputConnection, IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, int unverifiedTargetSdkVersion, @UserIdInt int userId, - @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq, - boolean useAsyncShowHideMethod) { + @NonNull ImeOnBackInvokedDispatcher imeDispatcher, boolean imeRequestedVisible, + int startInputSeq, boolean useAsyncShowHideMethod) { mCallback.startInputOrWindowGainedFocusAsync( startInputReason, client, windowToken, startInputFlags, softInputMode, windowFlags, editorInfo, inputConnection, remoteAccessibilityInputConnection, - unverifiedTargetSdkVersion, userId, imeDispatcher, startInputSeq, - useAsyncShowHideMethod); + unverifiedTargetSdkVersion, userId, imeDispatcher, imeRequestedVisible, + startInputSeq, useAsyncShowHideMethod); } @Override diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java index 69353becc692..2c07a3179344 100644 --- a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java +++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java @@ -443,7 +443,8 @@ public final class ImeVisibilityStateComputer { } @GuardedBy("ImfLock.class") - ImeVisibilityResult computeState(ImeTargetWindowState state, boolean allowVisible) { + ImeVisibilityResult computeState(ImeTargetWindowState state, boolean allowVisible, + boolean imeRequestedVisible) { // TODO: Output the request IME visibility state according to the requested window state final int softInputVisibility = state.mSoftInputModeState & SOFT_INPUT_MASK_STATE; // Should we auto-show the IME even if the caller has not @@ -576,7 +577,8 @@ public final class ImeVisibilityStateComputer { SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR); } } - if (!state.hasEditorFocused() && mInputShown && state.isStartInputByGainFocus() + if (!state.hasEditorFocused() && (mInputShown || (Flags.refactorInsetsController() + && imeRequestedVisible)) && state.isStartInputByGainFocus() && mService.mInputMethodDeviceConfigs.shouldHideImeWhenNoEditorFocus()) { // Hide the soft-keyboard when the system do nothing for softInputModeState // of the window being gained focus without an editor. This behavior benefits diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 68ad8f7e9433..23757757e336 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -3725,8 +3725,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. IRemoteInputConnection inputConnection, IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, int unverifiedTargetSdkVersion, @UserIdInt int userId, - @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq, - boolean useAsyncShowHideMethod) { + @NonNull ImeOnBackInvokedDispatcher imeDispatcher, boolean imeRequestedVisible, + int startInputSeq, boolean useAsyncShowHideMethod) { // implemented by ZeroJankProxy } @@ -3739,7 +3739,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. IRemoteInputConnection inputConnection, IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, int unverifiedTargetSdkVersion, @UserIdInt int userId, - @NonNull ImeOnBackInvokedDispatcher imeDispatcher) { + @NonNull ImeOnBackInvokedDispatcher imeDispatcher, boolean imeRequestedVisible) { if (UserHandle.getCallingUserId() != userId) { mContext.enforceCallingOrSelfPermission( Manifest.permission.INTERACT_ACROSS_USERS_FULL, null); @@ -3870,7 +3870,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. result = startInputOrWindowGainedFocusInternalLocked(startInputReason, client, windowToken, startInputFlags, softInputMode, windowFlags, editorInfo, inputConnection, remoteAccessibilityInputConnection, - unverifiedTargetSdkVersion, bindingController, imeDispatcher, cs); + unverifiedTargetSdkVersion, bindingController, imeDispatcher, cs, + imeRequestedVisible); } finally { Binder.restoreCallingIdentity(ident); } @@ -3899,7 +3900,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. IRemoteInputConnection inputContext, @Nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, int unverifiedTargetSdkVersion, @NonNull InputMethodBindingController bindingController, - @NonNull ImeOnBackInvokedDispatcher imeDispatcher, @NonNull ClientState cs) { + @NonNull ImeOnBackInvokedDispatcher imeDispatcher, @NonNull ClientState cs, + boolean imeRequestedVisible) { ProtoLog.v(IMMS_DEBUG, "startInputOrWindowGainedFocusInternalLocked: reason=%s" + " client=%s" + " inputContext=%s" @@ -3910,12 +3912,13 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. + " unverifiedTargetSdkVersion=%s" + " bindingController=%s" + " imeDispatcher=%s" - + " cs=%s", + + " cs=%s" + + " imeRequestedVisible=%s", InputMethodDebug.startInputReasonToString(startInputReason), client.asBinder(), inputContext, editorInfo, InputMethodDebug.startInputFlagsToString(startInputFlags), InputMethodDebug.softInputModeToString(softInputMode), Integer.toHexString(windowFlags), unverifiedTargetSdkVersion, bindingController, - imeDispatcher, cs); + imeDispatcher, cs, imeRequestedVisible); final int userId = bindingController.getUserId(); final var userData = getUserData(userId); @@ -3963,7 +3966,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. InputBindResult res = null; final ImeVisibilityResult imeVisRes = visibilityStateComputer.computeState(windowState, - isSoftInputModeStateVisibleAllowed(unverifiedTargetSdkVersion, startInputFlags)); + isSoftInputModeStateVisibleAllowed(unverifiedTargetSdkVersion, startInputFlags), + imeRequestedVisible); if (imeVisRes != null) { boolean isShow = false; switch (imeVisRes.getReason()) { diff --git a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java index 72529254545e..12c1d9cbb2a1 100644 --- a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java +++ b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java @@ -234,15 +234,15 @@ final class ZeroJankProxy implements IInputMethodManagerImpl.Callback { IRemoteInputConnection inputConnection, IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, int unverifiedTargetSdkVersion, @UserIdInt int userId, - @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq, - boolean useAsyncShowHideMethod) { + @NonNull ImeOnBackInvokedDispatcher imeDispatcher, boolean imeRequestedVisible, + int startInputSeq, boolean useAsyncShowHideMethod) { offload(() -> { InputBindResult result = mInner.startInputOrWindowGainedFocus(startInputReason, client, windowToken, startInputFlags, softInputMode, windowFlags, editorInfo, inputConnection, remoteAccessibilityInputConnection, unverifiedTargetSdkVersion, - userId, imeDispatcher); + userId, imeDispatcher, imeRequestedVisible); 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) { @@ -269,7 +269,7 @@ final class ZeroJankProxy implements IInputMethodManagerImpl.Callback { IRemoteInputConnection inputConnection, IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, int unverifiedTargetSdkVersion, @UserIdInt int userId, - @NonNull ImeOnBackInvokedDispatcher imeDispatcher) { + @NonNull ImeOnBackInvokedDispatcher imeDispatcher, boolean imeRequestedVisible) { // Should never be called when flag is enabled i.e. when this proxy is used. return null; } diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java index 9e38435ff7f1..ad108f64ffe3 100644 --- a/services/core/java/com/android/server/media/quality/MediaQualityService.java +++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java @@ -28,6 +28,7 @@ import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; +import android.hardware.audio.effect.DefaultExtension; import android.hardware.tv.mediaquality.AmbientBacklightColorFormat; import android.hardware.tv.mediaquality.IMediaQuality; import android.hardware.tv.mediaquality.IPictureProfileAdjustmentListener; @@ -57,6 +58,7 @@ import android.os.Binder; import android.os.Bundle; import android.os.Environment; import android.os.IBinder; +import android.os.Parcel; import android.os.PersistableBundle; import android.os.RemoteCallbackList; import android.os.RemoteException; @@ -365,13 +367,21 @@ public class MediaQualityService extends SystemService { try { if (mMediaQuality != null) { + PictureParameters pp = new PictureParameters(); PictureParameter[] pictureParameters = MediaQualityUtils .convertPersistableBundleToPictureParameterList(params); - PictureParameters pp = new PictureParameters(); + PersistableBundle vendorPictureParameters = params + .getPersistableBundle(BaseParameters.VENDOR_PARAMETERS); + Parcel parcel = Parcel.obtain(); + if (vendorPictureParameters != null) { + setVendorPictureParameters(pp, parcel, vendorPictureParameters); + } + pp.pictureParameters = pictureParameters; mMediaQuality.sendDefaultPictureParameters(pp); + parcel.recycle(); return true; } } catch (RemoteException e) { @@ -1419,11 +1429,19 @@ public class MediaQualityService extends SystemService { MediaQualityUtils.convertPersistableBundleToPictureParameterList( params); + PersistableBundle vendorPictureParameters = params + .getPersistableBundle(BaseParameters.VENDOR_PARAMETERS); + Parcel parcel = Parcel.obtain(); + if (vendorPictureParameters != null) { + setVendorPictureParameters(pictureParameters, parcel, vendorPictureParameters); + } + android.hardware.tv.mediaquality.PictureProfile toReturn = new android.hardware.tv.mediaquality.PictureProfile(); toReturn.pictureProfileId = id; toReturn.parameters = pictureParameters; + parcel.recycle(); return toReturn; } @@ -1729,4 +1747,16 @@ public class MediaQualityService extends SystemService { return android.hardware.tv.mediaquality.IMediaQualityCallback.Stub.VERSION; } } + + private void setVendorPictureParameters( + PictureParameters pictureParameters, + Parcel parcel, + PersistableBundle vendorPictureParameters) { + vendorPictureParameters.writeToParcel(parcel, 0); + byte[] vendorBundleToByteArray = parcel.marshall(); + DefaultExtension defaultExtension = new DefaultExtension(); + defaultExtension.bytes = Arrays.copyOf( + vendorBundleToByteArray, vendorBundleToByteArray.length); + pictureParameters.vendorPictureParameters.setParcelable(defaultExtension); + } } diff --git a/services/core/java/com/android/server/os/instrumentation/DynamicInstrumentationManagerService.java b/services/core/java/com/android/server/os/instrumentation/DynamicInstrumentationManagerService.java index 871d12ee6394..7791f5180e57 100644 --- a/services/core/java/com/android/server/os/instrumentation/DynamicInstrumentationManagerService.java +++ b/services/core/java/com/android/server/os/instrumentation/DynamicInstrumentationManagerService.java @@ -38,6 +38,7 @@ import com.android.server.SystemService; import dalvik.system.VMDebug; +import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.util.NoSuchElementException; import java.util.Objects; @@ -95,10 +96,16 @@ public class DynamicInstrumentationManagerService extends SystemService { } } - Method method = MethodDescriptorParser.parseMethodDescriptor( + Executable executable = MethodDescriptorParser.parseMethodDescriptor( getClass().getClassLoader(), methodDescriptor); - VMDebug.ExecutableMethodFileOffsets location = - VMDebug.getExecutableMethodFileOffsets(method); + VMDebug.ExecutableMethodFileOffsets location; + if (com.android.art.flags.Flags.executableMethodFileOffsetsV2()) { + location = VMDebug.getExecutableMethodFileOffsets(executable); + } else if (executable instanceof Method) { + location = VMDebug.getExecutableMethodFileOffsets((Method) executable); + } else { + throw new UnsupportedOperationException(); + } try { if (location == null) { diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index cf598e89c988..62264dd73795 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -96,6 +96,7 @@ import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.os.ShellCommand; import android.os.SystemClock; +import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; @@ -1564,6 +1565,12 @@ class PackageManagerShellCommand extends ShellCommand { private int doRunInstall(final InstallParams params) throws RemoteException { final PrintWriter pw = getOutPrintWriter(); + // Do not allow app installation if boot has not completed already + if (!SystemProperties.getBoolean("sys.boot_completed", false)) { + pw.println("Error: device is still booting."); + return 1; + } + int requestUserId = params.userId; if (requestUserId != UserHandle.USER_ALL && requestUserId != UserHandle.USER_CURRENT) { UserManagerInternal umi = @@ -2174,6 +2181,13 @@ class PackageManagerShellCommand extends ShellCommand { private int runUninstall() throws RemoteException { final PrintWriter pw = getOutPrintWriter(); + + // Do not allow app uninstallation if boot has not completed already + if (!SystemProperties.getBoolean("sys.boot_completed", false)) { + pw.println("Error: device is still booting."); + return 1; + } + int flags = 0; int userId = UserHandle.USER_ALL; long versionCode = PackageManager.VERSION_CODE_HIGHEST; diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 46dc75817a36..3230e891db55 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -4240,66 +4240,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (!useKeyGestureEventHandler()) { return; } - mInputManager.registerKeyGestureEventHandler(new InputManager.KeyGestureEventHandler() { - @Override - public boolean handleKeyGestureEvent(@NonNull KeyGestureEvent event, - @Nullable IBinder focusedToken) { - boolean handled = PhoneWindowManager.this.handleKeyGestureEvent(event, - focusedToken); - if (handled && !event.isCancelled() && Arrays.stream(event.getKeycodes()).anyMatch( - (keycode) -> keycode == KeyEvent.KEYCODE_POWER)) { - mPowerKeyHandled = true; - } - return handled; - } - - @Override - public boolean isKeyGestureSupported(int gestureType) { - switch (gestureType) { - case KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS: - case KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH: - case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT: - case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT: - case KeyGestureEvent.KEY_GESTURE_TYPE_HOME: - case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS: - case KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN: - case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL: - case KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT: - case KeyGestureEvent.KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT: - case KeyGestureEvent.KEY_GESTURE_TYPE_BACK: - case KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION: - case KeyGestureEvent.KEY_GESTURE_TYPE_DESKTOP_MODE: - case KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT: - case KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT: - case KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER: - case KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_UP: - case KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_DOWN: - case KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER: - case KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS: - case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS: - case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SEARCH: - case KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH: - case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT: - case KeyGestureEvent.KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS: - case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION: - case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_DO_NOT_DISTURB: - case KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD: - case KeyGestureEvent.KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD: - case KeyGestureEvent.KEY_GESTURE_TYPE_GLOBAL_ACTIONS: - case KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT: - case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK: - case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS: - return true; - case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD: - return mAccessibilityShortcutController.isAccessibilityShortcutAvailable( - isKeyguardLocked()); - case KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD: - return mAccessibilityShortcutController.isAccessibilityShortcutAvailable( - false); - default: - return false; - } + mInputManager.registerKeyGestureEventHandler((event, focusedToken) -> { + boolean handled = PhoneWindowManager.this.handleKeyGestureEvent(event, + focusedToken); + if (handled && !event.isCancelled() && Arrays.stream(event.getKeycodes()).anyMatch( + (keycode) -> keycode == KeyEvent.KEYCODE_POWER)) { + mPowerKeyHandled = true; } + return handled; }); } @@ -4457,13 +4405,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { cancelPendingScreenshotChordAction(); } return true; - case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD: - if (start) { - interceptAccessibilityShortcutChord(); - } else { - cancelPendingAccessibilityShortcutAction(); - } - return true; case KeyGestureEvent.KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD: if (start) { interceptRingerToggleChord(); @@ -4481,14 +4422,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { cancelGlobalActionsAction(); } return true; - // TODO (b/358569822): Consolidate TV and non-TV gestures into same KeyGestureEvent - case KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD: - if (start) { - interceptAccessibilityGestureTv(); - } else { - cancelAccessibilityGestureTv(); - } - return true; case KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT: if (start) { interceptBugreportGestureTv(); diff --git a/services/core/java/com/android/server/security/CertificateRevocationStatusManager.java b/services/core/java/com/android/server/security/CertificateRevocationStatusManager.java index 799157520ca5..800fc7c25de5 100644 --- a/services/core/java/com/android/server/security/CertificateRevocationStatusManager.java +++ b/services/core/java/com/android/server/security/CertificateRevocationStatusManager.java @@ -23,6 +23,7 @@ import android.content.ComponentName; import android.content.Context; import android.net.NetworkCapabilities; import android.net.NetworkRequest; +import android.os.Binder; import android.os.Environment; import android.util.AtomicFile; import android.util.Slog; @@ -119,7 +120,7 @@ class CertificateRevocationStatusManager { } catch (IOException | JSONException ex) { Slog.d(TAG, "Fallback to check stored revocation status", ex); if (ex instanceof IOException && mShouldScheduleJob) { - scheduleJobToFetchRemoteRevocationJob(); + Binder.withCleanCallingIdentity(this::scheduleJobToFetchRemoteRevocationJob); } try { revocationList = getStoredRevocationList(); @@ -210,7 +211,7 @@ class CertificateRevocationStatusManager { return; } Slog.d(TAG, "Scheduling job to fetch remote CRL."); - jobScheduler.schedule( + jobScheduler.forNamespace(TAG).schedule( new JobInfo.Builder( JOB_ID, new ComponentName( diff --git a/services/core/java/com/android/server/security/advancedprotection/features/UsbDataAdvancedProtectionHook.java b/services/core/java/com/android/server/security/advancedprotection/features/UsbDataAdvancedProtectionHook.java index 9a9c56f7bd17..55a8f7e6ea54 100644 --- a/services/core/java/com/android/server/security/advancedprotection/features/UsbDataAdvancedProtectionHook.java +++ b/services/core/java/com/android/server/security/advancedprotection/features/UsbDataAdvancedProtectionHook.java @@ -20,6 +20,8 @@ import static android.content.Intent.ACTION_SCREEN_OFF; import static android.content.Intent.ACTION_USER_PRESENT; import static android.hardware.usb.UsbManager.ACTION_USB_PORT_CHANGED; import static android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_DISALLOW_USB; +import static android.hardware.usb.UsbPortStatus.DATA_ROLE_NONE; +import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_FORCE; import android.app.KeyguardManager; import android.app.Notification; @@ -33,15 +35,18 @@ import android.hardware.usb.ParcelableUsbPort; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbManager; +import android.hardware.usb.IUsbManagerInternal; import android.hardware.usb.UsbPort; import android.hardware.usb.UsbPortStatus; import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.Looper; +import android.os.RemoteException; import android.os.UserHandle; import android.util.Slog; +import com.android.server.LocalServices; import java.lang.Runnable; import java.util.function.Consumer; @@ -52,6 +57,7 @@ import android.security.advancedprotection.AdvancedProtectionFeature; import com.android.internal.R; import java.util.Map; +import java.util.Objects; /** * AAPM Feature for managing and protecting USB data signal from attacks. @@ -65,11 +71,13 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { private static final String CHANNEL_NAME = "BackgroundInstallUiNotificationChannel"; private static final int APM_USB_FEATURE_CHANNEL_ID = 1; private static final int DELAY_DISABLE_MS = 1000; + private static final int OS_USB_DISABLE_REASON_LOCKDOWN_MODE = 1; private final Context mContext; private final Handler mDelayedDisableHandler = new Handler(Looper.getMainLooper()); private UsbManager mUsbManager; + private IUsbManagerInternal mUsbManagerInternal; private BroadcastReceiver mUsbProtectionBroadcastReceiver; private KeyguardManager mKeyguardManager; private NotificationManager mNotificationManager; @@ -85,6 +93,8 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { super(context, enabled); mContext = context; mUsbManager = mContext.getSystemService(UsbManager.class); + mUsbManagerInternal = Objects.requireNonNull( + LocalServices.getService(IUsbManagerInternal.class)); onAdvancedProtectionChanged(enabled); } @@ -117,9 +127,7 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { if (mBroadcastReceiverIsRegistered) { unregisterReceiver(); } - if (!mUsbManager.enableUsbDataSignal(true)) { - Slog.e(TAG, "USB Data protection toggle failed"); - } + setUsbDataSignalIfPossible(true); } } @@ -134,23 +142,41 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { if (ACTION_USER_PRESENT.equals(intent.getAction()) && !mKeyguardManager.isKeyguardLocked()) { mDelayedDisableHandler.removeCallbacksAndMessages(null); - setUsbDataSignalIfNoConnectedDevices(true); + setUsbDataSignalIfPossible(true); + } else if (ACTION_SCREEN_OFF.equals(intent.getAction()) && mKeyguardManager.isKeyguardLocked()) { - setUsbDataSignalIfNoConnectedDevices(false); + setUsbDataSignalIfPossible(false); + } else if (ACTION_USB_PORT_CHANGED.equals(intent.getAction())) { if (Build.IS_DEBUGGABLE) { dumpUsbDevices(); } - setDelayedDisableTaskIfDisconnectedAndLocked(intent); + if(mKeyguardManager.isKeyguardLocked()) { + updateDelayedDisableTask(intent); + } sendNotificationIfDeviceLocked(intent); + } } catch (Exception e) { Slog.e(TAG, "USB Data protection failed with: " + e.getMessage()); } } - private boolean getUsbPortStatusIsConnectedAndDataEnabled(Intent intent) { + private void updateDelayedDisableTask(Intent intent) { + // For recovered intermittent/unreliable USB connections + if(usbPortIsConnectedAndDataEnabled(intent)) { + mDelayedDisableHandler.removeCallbacksAndMessages(null); + } else if(!mDelayedDisableHandler.hasMessagesOrCallbacks()) { + mDelayedDisableHandler.postDelayed(() -> { + if (mKeyguardManager.isKeyguardLocked()) { + setUsbDataSignalIfPossible(false); + } + }, DELAY_DISABLE_MS); + } + } + + private boolean usbPortIsConnectedAndDataEnabled(Intent intent) { UsbPortStatus portStatus = intent.getParcelableExtra( UsbManager.EXTRA_PORT_STATUS, UsbPortStatus.class); @@ -160,40 +186,7 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { != UsbPortStatus.DATA_STATUS_DISABLED_FORCE; } - private void setDelayedDisableTaskIfDisconnectedAndLocked(Intent intent) { - if(mKeyguardManager.isKeyguardLocked()) { - if(getUsbPortStatusIsConnectedAndDataEnabled(intent)) { - mDelayedDisableHandler.removeCallbacksAndMessages(null); - } else if(!mDelayedDisableHandler.hasMessagesOrCallbacks()) { - mDelayedDisableHandler.postDelayed(() -> { - disableChangedUsbPortIfDisconnected(intent); - }, DELAY_DISABLE_MS); - } - } - } - - private void disableChangedUsbPortIfDisconnected(Intent intent) { - UsbPortStatus portStatus = - intent.getParcelableExtra( - UsbManager.EXTRA_PORT_STATUS, UsbPortStatus.class); - if (Build.IS_DEBUGGABLE) { - Slog.i( - TAG, - "disableChangedUsbPortIfDisconnected: " + portStatus == null - ? "null" - : portStatus.toString()); - } - - if (mKeyguardManager.isKeyguardLocked() - && portStatus != null && !portStatus.isConnected() - ) { - intent.getParcelableExtra( - UsbManager.EXTRA_PORT, ParcelableUsbPort.class) - .getUsbPort(mUsbManager) - .enableUsbData(false); - } - } - + // TODO: b/401540215 Remove this as part of pre-release cleanup private void dumpUsbDevices() { Slog.d(TAG, "dumpUsbDevices: "); Map<String, UsbDevice> portStatusMap = mUsbManager.getDeviceList(); @@ -238,9 +231,7 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { UsbPortStatus portStatus = intent.getParcelableExtra(UsbManager.EXTRA_PORT_STATUS, UsbPortStatus.class); if (mKeyguardManager.isKeyguardLocked() - && portStatus != null - && portStatus.isConnected() - && portStatus.getUsbDataStatus() == UsbPortStatus.DATA_STATUS_DISABLED_FORCE) { + && usbPortIsConnectedWithDataDisabled(portStatus)) { sendNotification( mContext.getString( R.string.usb_apm_usb_plugged_in_when_locked_notification_title), @@ -251,39 +242,46 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { } } - private void setUsbDataSignalIfNoConnectedDevices(boolean status) { - // disable all ports that don't have an active data connection - if (!status) { - for (UsbPort usbPort : mUsbManager.getPorts()) { - if (Build.IS_DEBUGGABLE) { - Slog.i( - TAG, - "setUsbDataSignal: false " + usbPort.getStatus() == null - ? "null" - : usbPort.getStatus().toString()); - } - if (usbPort.getStatus() == null - || !usbPort.getStatus().isConnected() - || usbPort.getStatus().getCurrentDataRole() - == UsbPortStatus.DATA_ROLE_NONE) { - usbPort.enableUsbData(false); - } - } + private boolean usbPortIsConnectedWithDataDisabled(UsbPortStatus portStatus) { + return portStatus != null + && portStatus.isConnected() + && portStatus.getUsbDataStatus() == DATA_STATUS_DISABLED_FORCE; + } + + private void setUsbDataSignalIfPossible(boolean status) { + if (!status && deviceHaveUsbDataConnection()) { + return; } - // Always re-enable all if true - else { - if (!mUsbManager.enableUsbDataSignal(status)) { + try { + if (!mUsbManagerInternal.enableUsbDataSignal(status, + OS_USB_DISABLE_REASON_LOCKDOWN_MODE)) { Slog.e(TAG, "USB Data protection toggle failed"); } - for (UsbPort usbPort : mUsbManager.getPorts()) { - usbPort.resetUsbPort(mContext.getMainExecutor(), - new Consumer<Integer>() { - public void accept(Integer status) { - Slog.i(TAG, "Consumer status: " + status); - } - }); + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException thrown when calling enableUsbDataSignal", e); + } + } + + private boolean deviceHaveUsbDataConnection() { + for (UsbPort usbPort : mUsbManager.getPorts()) { + if (Build.IS_DEBUGGABLE) { + Slog.i( + TAG, + "setUsbDataSignal: false, Port status: " + usbPort.getStatus() == null + ? "null" + : usbPort.getStatus().toString()); + } + if (usbPortIsConnectedWithDataEnabled(usbPort)) { + return true; } } + return false; + } + + private boolean usbPortIsConnectedWithDataEnabled(UsbPort usbPort) { + return usbPort.getStatus() != null + && usbPort.getStatus().isConnected() + && usbPort.getStatus().getCurrentDataRole() != DATA_ROLE_NONE; } private void registerReceiver() { diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index 1299a4d86623..f243d4fa825a 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -153,7 +153,7 @@ final class AccessibilityController { final DisplayContent dc = mService.mRoot.getDisplayContent(displayId); if (dc != null) { final Display display = dc.getDisplay(); - if (display != null && display.getType() != Display.TYPE_OVERLAY) { + if (display != null) { final DisplayMagnifier magnifier = new DisplayMagnifier( mService, dc, display, callbacks); magnifier.notifyImeWindowVisibilityChanged( diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index 3f24da9d89f2..51025d204b46 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -60,6 +60,7 @@ import com.android.server.wm.ActivityStarter.DefaultFactory; import com.android.server.wm.ActivityStarter.Factory; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.List; /** @@ -97,6 +98,9 @@ public class ActivityStartController { /** Whether an {@link ActivityStarter} is currently executing (starting an Activity). */ private boolean mInExecution = false; + /** The {@link TaskDisplayArea}s that are currently starting home activity. */ + private ArrayList<TaskDisplayArea> mHomeLaunchingTaskDisplayAreas = new ArrayList<>(); + /** * TODO(b/64750076): Capture information necessary for dump and * {@link #postStartActivityProcessingForLastStarter} rather than keeping the entire object @@ -162,6 +166,11 @@ public class ActivityStartController { void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, TaskDisplayArea taskDisplayArea) { + if (mHomeLaunchingTaskDisplayAreas.contains(taskDisplayArea)) { + Slog.e(TAG, "Abort starting home on " + taskDisplayArea + " recursively."); + return; + } + final ActivityOptions options = ActivityOptions.makeBasic(); options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); if (!ActivityRecord.isResolverActivity(aInfo.name)) { @@ -186,13 +195,18 @@ public class ActivityStartController { mSupervisor.endDeferResume(); } - mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason) - .setOutActivity(tmpOutRecord) - .setCallingUid(0) - .setActivityInfo(aInfo) - .setActivityOptions(options.toBundle(), - Binder.getCallingPid(), Binder.getCallingUid()) - .execute(); + try { + mHomeLaunchingTaskDisplayAreas.add(taskDisplayArea); + mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason) + .setOutActivity(tmpOutRecord) + .setCallingUid(0) + .setActivityInfo(aInfo) + .setActivityOptions(options.toBundle(), + Binder.getCallingPid(), Binder.getCallingUid()) + .execute(); + } finally { + mHomeLaunchingTaskDisplayAreas.remove(taskDisplayArea); + } mLastHomeActivityStartRecord = tmpOutRecord[0]; if (rootHomeTask.mInResumeTopActivity) { // If we are in resume section already, home activity will be initialized, but not @@ -479,9 +493,9 @@ public class ActivityStartController { } } catch (SecurityException securityException) { ActivityStarter.logAndThrowExceptionForIntentRedirect(mService.mContext, - "Creator URI Grant Caused Exception.", intent, creatorUid, - creatorPackage, filterCallingUid, callingPackage, - securityException); + ActivityStarter.INTENT_REDIRECT_EXCEPTION_GRANT_URI_PERMISSION, + intent, creatorUid, creatorPackage, filterCallingUid, + callingPackage, securityException); } } if ((aInfo.applicationInfo.privateFlags @@ -720,6 +734,12 @@ public class ActivityStartController { } } + if (!mHomeLaunchingTaskDisplayAreas.isEmpty()) { + dumped = true; + pw.print(prefix); + pw.println("mHomeLaunchingTaskDisplayAreas:" + mHomeLaunchingTaskDisplayAreas); + } + if (!dumped) { pw.print(prefix); pw.println("(nothing)"); diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 233f91385ca4..a84a008f66eb 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -65,6 +65,7 @@ import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TAS import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_CONFIGURATION; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_TASKS; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS; +import static com.android.internal.util.FrameworkStatsLog.INTENT_REDIRECT_BLOCKED; import static com.android.server.pm.PackageArchiver.isArchivingEnabled; import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW; @@ -140,6 +141,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.HeavyWeightSwitcherActivity; import com.android.internal.app.IVoiceInteractor; import com.android.internal.protolog.ProtoLog; +import com.android.internal.util.FrameworkStatsLog; import com.android.server.UiThread; import com.android.server.am.ActivityManagerService.IntentCreatorToken; import com.android.server.am.PendingIntentRecord; @@ -623,7 +625,7 @@ class ActivityStarter { if ((intent.getExtendedFlags() & Intent.EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN) != 0) { logAndThrowExceptionForIntentRedirect(supervisor.mService.mContext, - "Unparceled intent does not have a creator token set.", intent, + ActivityStarter.INTENT_REDIRECT_EXCEPTION_MISSING_OR_INVALID_TOKEN, intent, intentCreatorUid, intentCreatorPackage, resolvedCallingUid, resolvedCallingPackage, null); } @@ -659,9 +661,9 @@ class ActivityStarter { } } catch (SecurityException securityException) { logAndThrowExceptionForIntentRedirect(supervisor.mService.mContext, - "Creator URI Grant Caused Exception.", intent, intentCreatorUid, - intentCreatorPackage, resolvedCallingUid, - resolvedCallingPackage, securityException); + ActivityStarter.INTENT_REDIRECT_EXCEPTION_GRANT_URI_PERMISSION, + intent, intentCreatorUid, intentCreatorPackage, + resolvedCallingUid, resolvedCallingPackage, securityException); } } } else { @@ -683,9 +685,9 @@ class ActivityStarter { } } catch (SecurityException securityException) { logAndThrowExceptionForIntentRedirect(supervisor.mService.mContext, - "Creator URI Grant Caused Exception.", intent, intentCreatorUid, - intentCreatorPackage, resolvedCallingUid, - resolvedCallingPackage, securityException); + ActivityStarter.INTENT_REDIRECT_EXCEPTION_GRANT_URI_PERMISSION, + intent, intentCreatorUid, intentCreatorPackage, + resolvedCallingUid, resolvedCallingPackage, securityException); } } } @@ -1109,8 +1111,11 @@ class ActivityStarter { if (sourceRecord != null) { if (requestCode >= 0 && !sourceRecord.finishing) { resultRecord = sourceRecord; + request.logMessage.append(" (rr="); + } else { + request.logMessage.append(" (sr="); } - request.logMessage.append(" (sr=" + System.identityHashCode(sourceRecord) + ")"); + request.logMessage.append(System.identityHashCode(sourceRecord) + ")"); } } @@ -1261,27 +1266,27 @@ class ActivityStarter { request.ignoreTargetSecurity, inTask != null, null, resultRecord, resultRootTask)) { abort = logAndAbortForIntentRedirect(mService.mContext, - "Creator checkStartAnyActivityPermission Caused abortion.", + ActivityStarter.INTENT_REDIRECT_ABORT_START_ANY_ACTIVITY_PERMISSION, intent, intentCreatorUid, intentCreatorPackage, callingUid, callingPackage); } } catch (SecurityException e) { logAndThrowExceptionForIntentRedirect(mService.mContext, - "Creator checkStartAnyActivityPermission Caused Exception.", + ActivityStarter.INTENT_REDIRECT_EXCEPTION_START_ANY_ACTIVITY_PERMISSION, intent, intentCreatorUid, intentCreatorPackage, callingUid, callingPackage, e); } if (!mService.mIntentFirewall.checkStartActivity(intent, intentCreatorUid, 0, resolvedType, aInfo.applicationInfo)) { abort = logAndAbortForIntentRedirect(mService.mContext, - "Creator IntentFirewall.checkStartActivity Caused abortion.", + ActivityStarter.INTENT_REDIRECT_ABORT_INTENT_FIREWALL_START_ACTIVITY, intent, intentCreatorUid, intentCreatorPackage, callingUid, callingPackage); } if (!mService.getPermissionPolicyInternal().checkStartActivity(intent, intentCreatorUid, intentCreatorPackage)) { abort = logAndAbortForIntentRedirect(mService.mContext, - "Creator PermissionPolicyService.checkStartActivity Caused abortion.", + ActivityStarter.INTENT_REDIRECT_ABORT_PERMISSION_POLICY_START_ACTIVITY, intent, intentCreatorUid, intentCreatorPackage, callingUid, callingPackage); } } @@ -3626,13 +3631,41 @@ class ActivityStarter { pw.println(mInTaskFragment); } + /** + * Error codes for intent redirect. + * + * @hide + */ + @IntDef(prefix = {"INTENT_REDIRECT_"}, value = { + INTENT_REDIRECT_EXCEPTION_MISSING_OR_INVALID_TOKEN, + INTENT_REDIRECT_EXCEPTION_GRANT_URI_PERMISSION, + INTENT_REDIRECT_EXCEPTION_START_ANY_ACTIVITY_PERMISSION, + INTENT_REDIRECT_ABORT_START_ANY_ACTIVITY_PERMISSION, + INTENT_REDIRECT_ABORT_INTENT_FIREWALL_START_ACTIVITY, + INTENT_REDIRECT_ABORT_PERMISSION_POLICY_START_ACTIVITY, + }) + @Retention(RetentionPolicy.SOURCE) + @interface IntentRedirectErrorCode { + } + + /** + * Error codes for intent redirect issues + */ + static final int INTENT_REDIRECT_EXCEPTION_MISSING_OR_INVALID_TOKEN = 1; + static final int INTENT_REDIRECT_EXCEPTION_GRANT_URI_PERMISSION = 2; + static final int INTENT_REDIRECT_EXCEPTION_START_ANY_ACTIVITY_PERMISSION = 3; + static final int INTENT_REDIRECT_ABORT_START_ANY_ACTIVITY_PERMISSION = 4; + static final int INTENT_REDIRECT_ABORT_INTENT_FIREWALL_START_ACTIVITY = 5; + static final int INTENT_REDIRECT_ABORT_PERMISSION_POLICY_START_ACTIVITY = 6; + static void logAndThrowExceptionForIntentRedirect(@NonNull Context context, - @NonNull String message, @NonNull Intent intent, int intentCreatorUid, + @IntentRedirectErrorCode int errorCode, @NonNull Intent intent, int intentCreatorUid, @Nullable String intentCreatorPackage, int callingUid, @Nullable String callingPackage, @Nullable SecurityException originalException) { - String msg = getIntentRedirectPreventedLogMessage(message, intent, intentCreatorUid, + String msg = getIntentRedirectPreventedLogMessage(errorCode, intent, intentCreatorUid, intentCreatorPackage, callingUid, callingPackage); Slog.wtf(TAG, msg); + FrameworkStatsLog.write(INTENT_REDIRECT_BLOCKED, intentCreatorUid, callingUid, errorCode); if (preventIntentRedirectShowToast()) { UiThread.getHandler().post( () -> Toast.makeText(context, @@ -3646,12 +3679,13 @@ class ActivityStarter { } private static boolean logAndAbortForIntentRedirect(@NonNull Context context, - @NonNull String message, @NonNull Intent intent, int intentCreatorUid, + @IntentRedirectErrorCode int errorCode, @NonNull Intent intent, int intentCreatorUid, @Nullable String intentCreatorPackage, int callingUid, @Nullable String callingPackage) { - String msg = getIntentRedirectPreventedLogMessage(message, intent, intentCreatorUid, + String msg = getIntentRedirectPreventedLogMessage(errorCode, intent, intentCreatorUid, intentCreatorPackage, callingUid, callingPackage); Slog.wtf(TAG, msg); + FrameworkStatsLog.write(INTENT_REDIRECT_BLOCKED, intentCreatorUid, callingUid, errorCode); if (preventIntentRedirectShowToast()) { UiThread.getHandler().post( () -> Toast.makeText(context, @@ -3662,11 +3696,38 @@ class ActivityStarter { ENABLE_PREVENT_INTENT_REDIRECT_TAKE_ACTION, callingUid); } - private static String getIntentRedirectPreventedLogMessage(@NonNull String message, + private static String getIntentRedirectPreventedLogMessage( + @IntentRedirectErrorCode int errorCode, @NonNull Intent intent, int intentCreatorUid, @Nullable String intentCreatorPackage, int callingUid, @Nullable String callingPackage) { + String message = getIntentRedirectErrorMessageFromCode(errorCode); return "[IntentRedirect Hardening] " + message + " intentCreatorUid: " + intentCreatorUid + "; intentCreatorPackage: " + intentCreatorPackage + "; callingUid: " + callingUid + "; callingPackage: " + callingPackage + "; intent: " + intent; } + + private static String getIntentRedirectErrorMessageFromCode( + @IntentRedirectErrorCode int errorCode) { + return switch (errorCode) { + case INTENT_REDIRECT_EXCEPTION_MISSING_OR_INVALID_TOKEN -> + "INTENT_REDIRECT_EXCEPTION_MISSING_OR_INVALID_TOKEN" + + " (Unparceled intent does not have a creator token set, throw exception.)"; + case INTENT_REDIRECT_EXCEPTION_GRANT_URI_PERMISSION -> + "INTENT_REDIRECT_EXCEPTION_GRANT_URI_PERMISSION" + + " (Creator URI permission grant throw exception.)"; + case INTENT_REDIRECT_EXCEPTION_START_ANY_ACTIVITY_PERMISSION -> + "INTENT_REDIRECT_ABORT_START_ANY_ACTIVITY_PERMISSION" + + " (Creator checkStartAnyActivityPermission, throw exception)"; + case INTENT_REDIRECT_ABORT_START_ANY_ACTIVITY_PERMISSION -> + "INTENT_REDIRECT_ABORT_START_ANY_ACTIVITY_PERMISSION" + + " (Creator checkStartAnyActivityPermission, abort)"; + case INTENT_REDIRECT_ABORT_INTENT_FIREWALL_START_ACTIVITY -> + "INTENT_REDIRECT_ABORT_INTENT_FIREWALL_START_ACTIVITY" + + " (Creator IntentFirewall.checkStartActivity, abort)"; + case INTENT_REDIRECT_ABORT_PERMISSION_POLICY_START_ACTIVITY -> + "INTENT_REDIRECT_ABORT_PERMISSION_POLICY_START_ACTIVITY" + + " (Creator PermissionPolicyService.checkStartActivity, abort)"; + default -> "Unknown error code: " + errorCode; + }; + } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 353ccd5836c8..42b63d125d6b 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -7104,6 +7104,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp public void setAnimatingTypes(@InsetsType int animatingTypes) { if (mAnimatingTypes != animatingTypes) { mAnimatingTypes = animatingTypes; + + if (android.view.inputmethod.Flags.reportAnimatingInsetsTypes()) { + getInsetsStateController().onAnimatingTypesChanged(this); + } } } } diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java index 2cac63c1e5e9..040bbe46c3aa 100644 --- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java @@ -263,8 +263,8 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { boolean oldVisibility = mSource.isVisible(); super.updateVisibility(); if (Flags.refactorInsetsController()) { - if (mSource.isVisible() && !oldVisibility && mImeRequester != null) { - reportImeDrawnForOrganizerIfNeeded(mImeRequester); + if (mSource.isVisible() && !oldVisibility && mControlTarget != null) { + reportImeDrawnForOrganizerIfNeeded(mControlTarget); } } onSourceChanged(); @@ -288,11 +288,15 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { // If insets target is not available (e.g. RemoteInsetsControlTarget), use current // IME input target to update IME request state. For example, switch from a task // with showing IME to a split-screen task without showing IME. - InsetsTarget insetsTarget = target.getWindow(); - if (insetsTarget == null && mServerVisible) { - insetsTarget = mDisplayContent.getImeInputTarget(); + InputTarget imeInputTarget = mDisplayContent.getImeInputTarget(); + if (imeInputTarget != target && imeInputTarget != null) { + // The controlTarget should be updated with the visibility of the + // current IME input target. + reportImeInputTargetStateToControlTarget(imeInputTarget, target, + statsToken); + } else { + invokeOnImeRequestedChangedListener(target, statsToken); } - invokeOnImeRequestedChangedListener(insetsTarget, statsToken); } } } @@ -328,8 +332,7 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { if (changed) { ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_UPDATE_CLIENT_VISIBILITY); - invokeOnImeRequestedChangedListener(mDisplayContent.getImeInputTarget(), - statsToken); + invokeOnImeRequestedChangedListener(controlTarget, statsToken); } else { // TODO(b/353463205) check cancelled / failed ImeTracker.forLogging().onCancelled(statsToken, @@ -383,7 +386,8 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { // not all virtual displays have an ImeInsetsSourceProvider, so it is not // guaranteed that the IME will be started when the control target reports its // requested visibility back. Thus, invoking the listener here. - invokeOnImeRequestedChangedListener(imeInsetsTarget, statsToken); + invokeOnImeRequestedChangedListener((InsetsControlTarget) imeInsetsTarget, + statsToken); } else { ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY); @@ -392,18 +396,21 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { } // TODO(b/353463205) check callers to see if we can make statsToken @NonNull - private void invokeOnImeRequestedChangedListener(InsetsTarget insetsTarget, + private void invokeOnImeRequestedChangedListener(InsetsControlTarget controlTarget, @Nullable ImeTracker.Token statsToken) { final var imeListener = mDisplayContent.mWmService.mOnImeRequestedChangedListener; if (imeListener != null) { - if (insetsTarget != null) { + if (controlTarget != null) { + final boolean imeAnimating = Flags.reportAnimatingInsetsTypes() + && (controlTarget.getAnimatingTypes() & WindowInsets.Type.ime()) != 0; ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_WM_POSTING_CHANGED_IME_VISIBILITY); mDisplayContent.mWmService.mH.post(() -> { ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_WM_INVOKING_IME_REQUESTED_LISTENER); - imeListener.onImeRequestedChanged(insetsTarget.getWindowToken(), - insetsTarget.isRequestedVisible(WindowInsets.Type.ime()), statsToken); + imeListener.onImeRequestedChanged(controlTarget.getWindowToken(), + controlTarget.isRequestedVisible(WindowInsets.Type.ime()) + || imeAnimating, statsToken); }); } else { ImeTracker.forLogging().onFailed(statsToken, @@ -416,6 +423,21 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { } } + @Override + void onAnimatingTypesChanged(InsetsControlTarget caller) { + if (Flags.reportAnimatingInsetsTypes()) { + final InsetsControlTarget controlTarget = getControlTarget(); + // If the IME is not being requested anymore and the animation is finished, we need to + // invoke the listener, to let IMS eventually know + if (caller != null && caller == controlTarget && !caller.isRequestedVisible( + WindowInsets.Type.ime()) + && (caller.getAnimatingTypes() & WindowInsets.Type.ime()) == 0) { + // TODO(b/353463205) check statsToken + invokeOnImeRequestedChangedListener(caller, null); + } + } + } + private void reportImeDrawnForOrganizerIfNeeded(@NonNull InsetsControlTarget caller) { final WindowState callerWindow = caller.getWindow(); if (callerWindow == null) { diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java index 7751ac3f9fc6..a4bc5cbcb5d3 100644 --- a/services/core/java/com/android/server/wm/InputManagerCallback.java +++ b/services/core/java/com/android/server/wm/InputManagerCallback.java @@ -343,6 +343,13 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal } } + @Override + public boolean isKeyguardLocked(int displayId) { + synchronized (mService.mGlobalLock) { + return mService.mAtmService.mKeyguardController.isKeyguardLocked(displayId); + } + } + /** Waits until the built-in input devices have been configured. */ public boolean waitForInputDevicesReady(long timeoutMillis) { synchronized (mInputDevicesReadyMonitor) { diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index b7489029768a..1b693fc05b21 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -673,6 +673,9 @@ class InsetsSourceProvider { mServerVisible, mClientVisible); } + void onAnimatingTypesChanged(InsetsControlTarget caller) { + } + protected boolean isLeashReadyForDispatching() { return isLeashInitialized(); } diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index 5e0395f70e65..810e48f492e1 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -393,6 +393,13 @@ class InsetsStateController { } } + void onAnimatingTypesChanged(InsetsControlTarget target) { + for (int i = mProviders.size() - 1; i >= 0; i--) { + final InsetsSourceProvider provider = mProviders.valueAt(i); + provider.onAnimatingTypesChanged(target); + } + } + private void notifyPendingInsetsControlChanged() { if (mPendingTargetProvidersMap.isEmpty()) { return; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index e98b2b749af8..8587b5a9c7ca 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -3831,10 +3831,11 @@ class Task extends TaskFragment { pw.print(ActivityInfo.resizeModeToString(mResizeMode)); pw.print(" mSupportsPictureInPicture="); pw.print(mSupportsPictureInPicture); pw.print(" isResizeable="); pw.println(isResizeable()); - pw.print(" isPerceptible="); pw.println(mIsPerceptible); + pw.print(prefix); pw.print("isPerceptible="); pw.println(mIsPerceptible); pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime); pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)"); - pw.print(prefix); pw.println(" isTrimmable=" + mIsTrimmableFromRecents); + pw.print(prefix); pw.print("isTrimmable=" + mIsTrimmableFromRecents); + pw.print(" isForceHidden="); pw.println(isForceHidden()); if (mLaunchAdjacentDisabled) { pw.println(prefix + "mLaunchAdjacentDisabled=true"); } diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 2dabb253744a..960f5beae2b3 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -24,7 +24,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 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; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; @@ -2453,7 +2452,8 @@ class TaskFragment extends WindowContainer<WindowContainer> { inOutConfig.windowConfiguration.setAppBounds(mTmpFullBounds); outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); - if (!customContainerPolicy && windowingMode != WINDOWING_MODE_FREEFORM) { + // Floating tasks shouldn't be restricted by containing app bounds. + if (!customContainerPolicy && !isFloating(windowingMode)) { final Rect containingAppBounds; if (insideParentBounds) { containingAppBounds = useOverrideInsetsForConfig diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 1022d18ac0e9..d528776a2c25 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -100,7 +100,6 @@ import static android.view.WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME; import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER; import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET; -import static com.android.input.flags.Flags.removeInputChannelFromWindowstate; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ADD_REMOVE; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ANIM; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_APP_TRANSITIONS; @@ -613,10 +612,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // Input channel and input window handle used by the input dispatcher. final InputWindowHandleWrapper mInputWindowHandle; - /** - * Only populated if flag REMOVE_INPUT_CHANNEL_FROM_WINDOWSTATE is disabled. - */ - private InputChannel mInputChannel; /** * The token will be assigned to {@link InputWindowHandle#token} if this window can receive @@ -862,6 +857,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mWmService.scheduleAnimationLocked(); mAnimatingTypes = animatingTypes; + + if (android.view.inputmethod.Flags.reportAnimatingInsetsTypes()) { + final InsetsStateController insetsStateController = + getDisplayContent().getInsetsStateController(); + insetsStateController.onAnimatingTypesChanged(this); + } } } @@ -1824,12 +1825,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * Input Manager uses when discarding windows from input consideration. */ boolean isPotentialDragTarget(boolean targetInterceptsGlobalDrag) { - if (removeInputChannelFromWindowstate()) { - return (targetInterceptsGlobalDrag || isVisibleNow()) && !mRemoved - && mInputChannelToken != null && mInputWindowHandle != null; - } return (targetInterceptsGlobalDrag || isVisibleNow()) && !mRemoved - && mInputChannel != null && mInputWindowHandle != null; + && mInputChannelToken != null && mInputWindowHandle != null; } /** @@ -2577,25 +2574,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (mInputChannelToken != null) { throw new IllegalStateException("Window already has an input channel token."); } - if (removeInputChannelFromWindowstate()) { - String name = getName(); - InputChannel channel = mWmService.mInputManager.createInputChannel(name); - mInputChannelToken = channel.getToken(); - mInputWindowHandle.setToken(mInputChannelToken); - mWmService.mInputToWindowMap.put(mInputChannelToken, this); - channel.copyTo(outInputChannel); - channel.dispose(); - return; - } - if (mInputChannel != null) { - throw new IllegalStateException("Window already has an input channel."); - } String name = getName(); - mInputChannel = mWmService.mInputManager.createInputChannel(name); - mInputChannelToken = mInputChannel.getToken(); + InputChannel channel = mWmService.mInputManager.createInputChannel(name); + mInputChannelToken = channel.getToken(); mInputWindowHandle.setToken(mInputChannelToken); mWmService.mInputToWindowMap.put(mInputChannelToken, this); - mInputChannel.copyTo(outInputChannel); + channel.copyTo(outInputChannel); + channel.dispose(); } /** @@ -2618,12 +2603,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mInputChannelToken = null; } - if (!removeInputChannelFromWindowstate()) { - if (mInputChannel != null) { - mInputChannel.dispose(); - mInputChannel = null; - } - } mInputWindowHandle.setToken(null); } diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index a8c49e11e4e9..e32ce525cb40 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -2309,13 +2309,6 @@ static jint nativeGetKeyCodeForKeyLocation(JNIEnv* env, jobject nativeImplObj, j locationKeyCode); } -static void handleInputChannelDisposed(JNIEnv* env, jobject /* inputChannelObj */, - const std::shared_ptr<InputChannel>& inputChannel, - void* data) { - NativeInputManager* im = static_cast<NativeInputManager*>(data); - im->removeInputChannel(inputChannel->getConnectionToken()); -} - static jobject nativeCreateInputChannel(JNIEnv* env, jobject nativeImplObj, jstring nameObj) { NativeInputManager* im = getNativeInputManager(env, nativeImplObj); @@ -2337,8 +2330,6 @@ static jobject nativeCreateInputChannel(JNIEnv* env, jobject nativeImplObj, jstr return nullptr; } - android_view_InputChannel_setDisposeCallback(env, inputChannelObj, - handleInputChannelDisposed, im); return inputChannelObj; } diff --git a/services/tests/DynamicInstrumentationManagerServiceTests/Android.bp b/services/tests/DynamicInstrumentationManagerServiceTests/Android.bp index 2c2e5fdb68d9..b354e36e1e8f 100644 --- a/services/tests/DynamicInstrumentationManagerServiceTests/Android.bp +++ b/services/tests/DynamicInstrumentationManagerServiceTests/Android.bp @@ -29,6 +29,7 @@ android_test { static_libs: [ "androidx.test.core", "androidx.test.runner", + "flag-junit", "hamcrest-library", "platform-test-annotations", "services.core", diff --git a/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/TestClass.java b/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/TestClass.java index 085f5953f0e5..d3a287dc6423 100644 --- a/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/TestClass.java +++ b/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/TestClass.java @@ -17,6 +17,9 @@ package com.android.server; public class TestClass { + TestClass() { + } + void primitiveParams(boolean a, boolean[] b, byte c, byte[] d, char e, char[] f, short g, short[] h, int i, int[] j, long k, long[] l, float m, float[] n, double o, double[] p) { } diff --git a/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/os/instrumentation/ParseMethodDescriptorTest.java b/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/os/instrumentation/ParseMethodDescriptorTest.java index 6e14bad11837..905c244af4ec 100644 --- a/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/os/instrumentation/ParseMethodDescriptorTest.java +++ b/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/os/instrumentation/ParseMethodDescriptorTest.java @@ -22,6 +22,9 @@ import static org.junit.Assert.assertThrows; import android.os.instrumentation.MethodDescriptor; import android.os.instrumentation.MethodDescriptorParser; import android.platform.test.annotations.Presubmit; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import androidx.test.filters.SmallTest; @@ -31,9 +34,10 @@ import com.android.server.TestClass; import com.android.server.TestInterface; import com.android.server.TestInterfaceImpl; +import org.junit.Rule; import org.junit.Test; -import java.lang.reflect.Method; +import java.lang.reflect.Executable; /** @@ -53,6 +57,10 @@ public class ParseMethodDescriptorTest { private static final String[] CLASS_PARAMS = new String[]{"java.lang.String", "java.lang.String[]"}; + @Rule + public final CheckFlagsRule mCheckFlagsRule = + DeviceFlagsValueProvider.createCheckFlagsRule(); + @Test public void primitiveParams() { assertNotNull(parseMethodDescriptor(TestClass.class.getName(), "primitiveParams", @@ -66,6 +74,13 @@ public class ParseMethodDescriptorTest { } @Test + @RequiresFlagsEnabled(com.android.art.flags.Flags.FLAG_EXECUTABLE_METHOD_FILE_OFFSETS_V2) + public void constructor() { + assertNotNull( + parseMethodDescriptor(TestClass.class.getName(), "<init>")); + } + + @Test public void publicMethod() { assertNotNull( parseMethodDescriptor(TestClass.class.getName(), "publicMethod")); @@ -119,13 +134,14 @@ public class ParseMethodDescriptorTest { new String[]{"int"})); } - private Method parseMethodDescriptor(String fqcn, String methodName) { + private Executable parseMethodDescriptor(String fqcn, String methodName) { return MethodDescriptorParser.parseMethodDescriptor( getClass().getClassLoader(), getMethodDescriptor(fqcn, methodName, new String[]{})); } - private Method parseMethodDescriptor(String fqcn, String methodName, String[] fqParameters) { + private Executable parseMethodDescriptor( + String fqcn, String methodName, String[] fqParameters) { return MethodDescriptorParser.parseMethodDescriptor( getClass().getClassLoader(), getMethodDescriptor(fqcn, methodName, fqParameters)); diff --git a/services/tests/InputMethodSystemServerTests/Android.bp b/services/tests/InputMethodSystemServerTests/Android.bp index ae9a34efc222..c1d8382fcd0e 100644 --- a/services/tests/InputMethodSystemServerTests/Android.bp +++ b/services/tests/InputMethodSystemServerTests/Android.bp @@ -73,10 +73,7 @@ android_ravenwood_test { static_libs: [ "androidx.annotation_annotation", "androidx.test.rules", - "framework", - "ravenwood-runtime", - "ravenwood-utils", - "services", + "services.core", ], libs: [ "android.test.base.stubs.system", diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java index 05615f68427d..2339a940e2d0 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java +++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java @@ -287,6 +287,7 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe mMockRemoteAccessibilityInputConnection /* remoteAccessibilityInputConnection */, mTargetSdkVersion /* unverifiedTargetSdkVersion */, mUserId /* userId */, - mMockImeOnBackInvokedDispatcher /* imeDispatcher */); + mMockImeOnBackInvokedDispatcher /* imeDispatcher */, + true /* imeRequestedVisible */); } } diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java index 70eeae648dd0..aa779197f301 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java +++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java @@ -267,7 +267,8 @@ public class ImeVisibilityStateComputerTest extends InputMethodManagerServiceTes // visibility state will be preserved to the current window state. final ImeTargetWindowState stateWithUnChangedFlag = initImeTargetWindowState( mWindowToken); - mComputer.computeState(stateWithUnChangedFlag, true /* allowVisible */); + mComputer.computeState(stateWithUnChangedFlag, true /* allowVisible */, + true /* imeRequestedVisible */); assertThat(stateWithUnChangedFlag.isRequestedImeVisible()).isEqualTo( lastState.isRequestedImeVisible()); } diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java index 11abc9469c82..b81b570389da 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java +++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java @@ -320,7 +320,8 @@ public class InputMethodManagerServiceWindowGainedFocusTest mMockRemoteAccessibilityInputConnection /* remoteAccessibilityInputConnection */, mTargetSdkVersion /* unverifiedTargetSdkVersion */, mUserId /* userId */, - mMockImeOnBackInvokedDispatcher /* imeDispatcher */); + mMockImeOnBackInvokedDispatcher /* imeDispatcher */, + true /* imeRequestedVisible */); } @Test diff --git a/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java b/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java index 7c239ef02e58..586ff52aa78c 100644 --- a/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java +++ b/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java @@ -328,6 +328,7 @@ public class TestDreamEnvironment { case DREAM_STATE_STARTED -> startDream(); case DREAM_STATE_WOKEN -> wakeDream(); } + mTestableLooper.processAllMessages(); } while (mCurrentDreamState < state); return true; diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java index 2a513ae3a8e8..d79d88400cf9 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java @@ -953,11 +953,13 @@ public final class AlarmManagerServiceTest { @Test @EnableFlags(Flags.FLAG_ACQUIRE_WAKELOCK_BEFORE_SEND) - public void testWakelockOrdering() throws Exception { + public void testWakelockOrderingFirstAlarm() throws Exception { final long triggerTime = mNowElapsedTest + 5000; final PendingIntent alarmPi = getNewMockPendingIntent(); setTestAlarm(ELAPSED_REALTIME_WAKEUP, triggerTime, alarmPi); + // Pretend that it is the first alarm in this batch, or no other alarms are still processing + mService.mBroadcastRefCount = 0; mNowElapsedTest = mTestTimer.getElapsed(); mTestTimer.expire(); @@ -975,20 +977,51 @@ public final class AlarmManagerServiceTest { @Test @EnableFlags(Flags.FLAG_ACQUIRE_WAKELOCK_BEFORE_SEND) - public void testWakelockReleasedWhenSendFails() throws Exception { + public void testWakelockOrderingNonFirst() throws Exception { final long triggerTime = mNowElapsedTest + 5000; final PendingIntent alarmPi = getNewMockPendingIntent(); setTestAlarm(ELAPSED_REALTIME_WAKEUP, triggerTime, alarmPi); + // Pretend that some previous alarms are still processing. + mService.mBroadcastRefCount = 3; + mNowElapsedTest = mTestTimer.getElapsed(); + mTestTimer.expire(); + + final ArgumentCaptor<PendingIntent.OnFinished> onFinishedCaptor = + ArgumentCaptor.forClass(PendingIntent.OnFinished.class); + verify(alarmPi).send(eq(mMockContext), eq(0), any(Intent.class), onFinishedCaptor.capture(), + any(Handler.class), isNull(), any()); + onFinishedCaptor.getValue().onSendFinished(alarmPi, null, 0, null, null); + + verify(mWakeLock, never()).acquire(); + verify(mWakeLock, never()).release(); + } + + @Test + @EnableFlags(Flags.FLAG_ACQUIRE_WAKELOCK_BEFORE_SEND) + public void testWakelockReleasedWhenSendFails() throws Exception { + final PendingIntent alarmPi = getNewMockPendingIntent(); doThrow(new PendingIntent.CanceledException("test")).when(alarmPi).send(eq(mMockContext), eq(0), any(Intent.class), any(), any(Handler.class), isNull(), any()); + setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5000, alarmPi); + + // Pretend that it is the first alarm in this batch, or no other alarms are still processing + mService.mBroadcastRefCount = 0; mNowElapsedTest = mTestTimer.getElapsed(); mTestTimer.expire(); final InOrder inOrder = Mockito.inOrder(mWakeLock); inOrder.verify(mWakeLock).acquire(); inOrder.verify(mWakeLock).release(); + + setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5000, alarmPi); + + // Pretend that some previous alarms are still processing. + mService.mBroadcastRefCount = 4; + mNowElapsedTest = mTestTimer.getElapsed(); + mTestTimer.expire(); + inOrder.verifyNoMoreInteractions(); } @Test diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java index 3a9c99d57d71..d540b2ec13eb 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java @@ -155,7 +155,6 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest { doAnswer((invocation) -> { Log.v(TAG, "Intercepting startProcessLocked() for " + Arrays.toString(invocation.getArguments())); - assertHealth(); final String processName = invocation.getArgument(0); final ProcessStartBehavior behavior = mNewProcessStartBehaviors.getOrDefault( processName, mNextProcessStartBehavior.getAndSet(ProcessStartBehavior.SUCCESS)); @@ -206,6 +205,9 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest { mActiveProcesses.remove(res); res.setKilled(true); break; + case MISSING_RESPONSE: + res.setPendingStart(true); + break; default: throw new UnsupportedOperationException(); } @@ -244,6 +246,7 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest { mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT = 0; mConstants.PENDING_COLD_START_CHECK_INTERVAL_MILLIS = 500; mConstants.MAX_FROZEN_OUTGOING_BROADCASTS = 10; + mConstants.PENDING_COLD_START_ABANDON_TIMEOUT_MILLIS = 2000; } @After @@ -279,6 +282,8 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest { FAIL_NULL, /** Process is killed without reporting to BroadcastQueue */ KILLED_WITHOUT_NOTIFY, + /** Process start fails without no response */ + MISSING_RESPONSE, } private enum ProcessBehavior { @@ -1173,6 +1178,37 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest { verifyScheduleReceiver(times(1), receiverOrangeApp, timezone); } + @Test + public void testProcessStartWithMissingResponse() throws Exception { + final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED); + final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE); + + mNewProcessStartBehaviors.put(PACKAGE_GREEN, ProcessStartBehavior.MISSING_RESPONSE); + + final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, List.of( + withPriority(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), 10), + withPriority(makeRegisteredReceiver(receiverBlueApp), 5), + withPriority(makeManifestReceiver(PACKAGE_YELLOW, CLASS_YELLOW), 0)))); + + final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED); + enqueueBroadcast(makeBroadcastRecord(timezone, callerApp, + List.of(makeManifestReceiver(PACKAGE_ORANGE, CLASS_ORANGE)))); + + waitForIdle(); + final ProcessRecord receiverGreenApp = mAms.getProcessRecordLocked(PACKAGE_GREEN, + getUidForPackage(PACKAGE_GREEN)); + final ProcessRecord receiverYellowApp = mAms.getProcessRecordLocked(PACKAGE_YELLOW, + getUidForPackage(PACKAGE_YELLOW)); + final ProcessRecord receiverOrangeApp = mAms.getProcessRecordLocked(PACKAGE_ORANGE, + getUidForPackage(PACKAGE_ORANGE)); + + verifyScheduleReceiver(times(1), receiverGreenApp, airplane); + verifyScheduleRegisteredReceiver(times(1), receiverBlueApp, airplane); + verifyScheduleReceiver(times(1), receiverYellowApp, airplane); + verifyScheduleReceiver(times(1), receiverOrangeApp, timezone); + } + /** * Verify that a broadcast sent to a frozen app, which gets killed as part of unfreezing * process due to pending sync binder transactions, is delivered as expected. diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java index 5d8f57866f7d..e094111c327a 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java @@ -746,6 +746,36 @@ public class MockingOomAdjusterTests { @SuppressWarnings("GuardedBy") @Test @EnableFlags(Flags.FLAG_USE_CPU_TIME_CAPABILITY) + public void testUpdateOomAdjFreezeState_bindingWithAllowFreeze() { + ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, + MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); + WindowProcessController wpc = app.getWindowProcessController(); + doReturn(true).when(wpc).hasVisibleActivities(); + + final ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, + MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); + + // App with a visible activity binds to app2 without any special flag. + bindService(app2, app, null, null, 0, mock(IBinder.class)); + + final ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID, + MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); + + // App with a visible activity binds to app3 with ALLOW_FREEZE. + bindService(app3, app, null, null, Context.BIND_ALLOW_FREEZE, mock(IBinder.class)); + + setProcessesToLru(app, app2, app3); + + updateOomAdj(app); + + assertCpuTime(app); + assertCpuTime(app2); + assertNoCpuTime(app3); + } + + @SuppressWarnings("GuardedBy") + @Test + @EnableFlags(Flags.FLAG_USE_CPU_TIME_CAPABILITY) @DisableFlags(Flags.FLAG_PROTOTYPE_AGGRESSIVE_FREEZING) public void testUpdateOomAdjFreezeState_bindingFromFgs() { final ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java index 9cfa51a85988..8253595a50d1 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java @@ -2374,14 +2374,6 @@ public class AccessibilityManagerServiceTest { return lockState; } - private void assertStartActivityWithExpectedComponentName(Context mockContext, - String componentName) { - verify(mockContext).startActivityAsUser(mIntentArgumentCaptor.capture(), - any(Bundle.class), any(UserHandle.class)); - assertThat(mIntentArgumentCaptor.getValue().getStringExtra( - Intent.EXTRA_COMPONENT_NAME)).isEqualTo(componentName); - } - private void assertStartActivityWithExpectedShortcutType(Context mockContext, @UserShortcutType int shortcutType) { verify(mockContext).startActivityAsUser(mIntentArgumentCaptor.capture(), @@ -2484,10 +2476,6 @@ public class AccessibilityManagerServiceTest { return mMockContext; } - public void addMockUserContext(int userId, Context context) { - mMockUserContexts.put(userId, context); - } - @Override @NonNull public Context createContextAsUser(UserHandle user, int flags) { diff --git a/services/tests/servicestests/src/com/android/server/accessibility/HearingDevicePhoneCallNotificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/HearingDevicePhoneCallNotificationControllerTest.java index efea21428937..63c572af37b2 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/HearingDevicePhoneCallNotificationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/HearingDevicePhoneCallNotificationControllerTest.java @@ -171,7 +171,7 @@ public class HearingDevicePhoneCallNotificationControllerTest { HearingDevicePhoneCallNotificationController.CallStateListener { TestCallStateListener(@NonNull Context context) { - super(context); + super(context, context.getMainExecutor()); } @Override diff --git a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java index ea25e7992dd9..2be43c6f21a5 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java @@ -18,6 +18,7 @@ package com.android.server.accessibility.autoclick; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_RIGHT_CLICK; import static com.android.server.testutils.MockitoUtilsKt.eq; import static com.google.common.truth.Truth.assertThat; @@ -547,6 +548,29 @@ public class AutoclickControllerTest { @Test @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR) + public void triggerRightClickWithRevertToLeftClickEnabled_resetClickType() { + // Move mouse to initialize autoclick panel. + injectFakeMouseActionHoverMoveEvent(); + + AutoclickTypePanel mockAutoclickTypePanel = mock(AutoclickTypePanel.class); + mController.mAutoclickTypePanel = mockAutoclickTypePanel; + mController.clickPanelController.handleAutoclickTypeChange(AUTOCLICK_TYPE_RIGHT_CLICK); + + // Set ACCESSIBILITY_AUTOCLICK_REVERT_TO_LEFT_CLICK to true. + Settings.Secure.putIntForUser(mTestableContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_AUTOCLICK_REVERT_TO_LEFT_CLICK, + AccessibilityUtils.State.ON, + mTestableContext.getUserId()); + mController.onChangeForTesting(/* selfChange= */ true, + Settings.Secure.getUriFor( + Settings.Secure.ACCESSIBILITY_AUTOCLICK_REVERT_TO_LEFT_CLICK)); + when(mockAutoclickTypePanel.isPaused()).thenReturn(false); + mController.mClickScheduler.run(); + assertThat(mController.mClickScheduler.getRevertToLeftClickForTesting()).isTrue(); + } + + @Test + @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR) public void pauseButton_flagOn_clickNotTriggeredWhenPaused() { injectFakeMouseActionHoverMoveEvent(); @@ -766,6 +790,8 @@ public class AutoclickControllerTest { // Set click type to right click. mController.clickPanelController.handleAutoclickTypeChange( AutoclickTypePanel.AUTOCLICK_TYPE_RIGHT_CLICK); + AutoclickTypePanel mockAutoclickTypePanel = mock(AutoclickTypePanel.class); + mController.mAutoclickTypePanel = mockAutoclickTypePanel; // Send hover move event. MotionEvent hoverMove = MotionEvent.obtain( diff --git a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickScrollPanelTest.java b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickScrollPanelTest.java index f445b50c7d9c..02361ff259c2 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickScrollPanelTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickScrollPanelTest.java @@ -28,7 +28,12 @@ import android.content.Context; import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableLooper; +import android.view.MotionEvent; +import android.view.View; import android.view.WindowManager; +import android.widget.ImageButton; + +import com.android.internal.R; import org.junit.Before; import org.junit.Rule; @@ -49,12 +54,31 @@ public class AutoclickScrollPanelTest { new TestableContext(getInstrumentation().getContext()); @Mock private WindowManager mMockWindowManager; + @Mock private AutoclickScrollPanel.ScrollPanelControllerInterface mMockScrollPanelController; + private AutoclickScrollPanel mScrollPanel; + // Scroll panel buttons. + private ImageButton mUpButton; + private ImageButton mDownButton; + private ImageButton mLeftButton; + private ImageButton mRightButton; + private ImageButton mExitButton; + @Before public void setUp() { mTestableContext.addMockSystemService(Context.WINDOW_SERVICE, mMockWindowManager); - mScrollPanel = new AutoclickScrollPanel(mTestableContext, mMockWindowManager); + mScrollPanel = new AutoclickScrollPanel(mTestableContext, mMockWindowManager, + mMockScrollPanelController); + + View contentView = mScrollPanel.getContentViewForTesting(); + + // Initialize buttons. + mUpButton = contentView.findViewById(R.id.scroll_up); + mDownButton = contentView.findViewById(R.id.scroll_down); + mLeftButton = contentView.findViewById(R.id.scroll_left); + mRightButton = contentView.findViewById(R.id.scroll_right); + mExitButton = contentView.findViewById(R.id.scroll_exit); } @Test @@ -89,4 +113,55 @@ public class AutoclickScrollPanelTest { // Verify scroll panel is hidden. assertThat(mScrollPanel.isVisible()).isFalse(); } + + @Test + public void initialState_correctButtonVisibility() { + // Verify all expected buttons exist in the view. + assertThat(mUpButton.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mDownButton.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mLeftButton.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mRightButton.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mExitButton.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void directionButtons_onHover_callsHandleScroll() { + // Test up button. + triggerHoverEvent(mUpButton); + verify(mMockScrollPanelController).handleScroll(AutoclickScrollPanel.DIRECTION_UP); + + // Test down button. + triggerHoverEvent(mDownButton); + verify(mMockScrollPanelController).handleScroll(AutoclickScrollPanel.DIRECTION_DOWN); + + // Test left button. + triggerHoverEvent(mLeftButton); + verify(mMockScrollPanelController).handleScroll(AutoclickScrollPanel.DIRECTION_LEFT); + + // Test right button. + triggerHoverEvent(mRightButton); + verify(mMockScrollPanelController).handleScroll(AutoclickScrollPanel.DIRECTION_RIGHT); + } + + @Test + public void exitButton_onHover_callsExitScrollMode() { + // Test exit button. + triggerHoverEvent(mExitButton); + verify(mMockScrollPanelController).exitScrollMode(); + } + + // Helper method to simulate a hover event on a view. + private void triggerHoverEvent(View view) { + MotionEvent event = MotionEvent.obtain( + /* downTime= */ 0, + /* eventTime= */ 0, + /* action= */ MotionEvent.ACTION_HOVER_ENTER, + /* x= */ 0, + /* y= */ 0, + /* metaState= */ 0); + + // Dispatch the event to the view's OnHoverListener. + view.dispatchGenericMotionEvent(event); + event.recycle(); + } } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java index dd089fcb1d70..8bbbca0b7ed4 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java @@ -198,6 +198,72 @@ public class AutoclickTypePanelTest { } @Test + public void clickLeftClickButton_resumeAutoClick() { + // Pause autoclick. + mPauseButton.callOnClick(); + assertThat(mAutoclickTypePanel.isPaused()).isTrue(); + + // Click the button and verify autoclick resumes. + mLeftClickButton.callOnClick(); + assertThat(mAutoclickTypePanel.isPaused()).isFalse(); + } + + @Test + public void clickRightClickButton_resumeAutoClick() { + // Pause autoclick. + mPauseButton.callOnClick(); + assertThat(mAutoclickTypePanel.isPaused()).isTrue(); + + // Click the button and verify autoclick resumes. + mRightClickButton.callOnClick(); + assertThat(mAutoclickTypePanel.isPaused()).isFalse(); + } + + @Test + public void clickDoubleClickButton_resumeAutoClick() { + // Pause autoclick. + mPauseButton.callOnClick(); + assertThat(mAutoclickTypePanel.isPaused()).isTrue(); + + // Click the button and verify autoclick resumes. + mDoubleClickButton.callOnClick(); + assertThat(mAutoclickTypePanel.isPaused()).isFalse(); + } + + @Test + public void clickDragButton_resumeAutoClick() { + // Pause autoclick. + mPauseButton.callOnClick(); + assertThat(mAutoclickTypePanel.isPaused()).isTrue(); + + // Click the button and verify autoclick resumes. + mDragButton.callOnClick(); + assertThat(mAutoclickTypePanel.isPaused()).isFalse(); + } + + @Test + public void clickScrollButton_resumeAutoClick() { + // Pause autoclick. + mPauseButton.callOnClick(); + assertThat(mAutoclickTypePanel.isPaused()).isTrue(); + + // Click the button and verify autoclick resumes. + mScrollButton.callOnClick(); + assertThat(mAutoclickTypePanel.isPaused()).isFalse(); + } + + @Test + public void clickPositionButton_resumeAutoClick() { + // Pause autoclick. + mPauseButton.callOnClick(); + assertThat(mAutoclickTypePanel.isPaused()).isTrue(); + + // Click the button and verify autoclick resumes. + mPositionButton.callOnClick(); + assertThat(mAutoclickTypePanel.isPaused()).isFalse(); + } + + @Test public void moveToNextCorner_positionButton_rotatesThroughAllPositions() { // Define all positions in sequence int[][] expectedPositions = { diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java index 1af59daa9c78..5922b12edc1e 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java @@ -37,6 +37,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -46,6 +47,7 @@ import android.content.Context; import android.graphics.PointF; import android.os.Looper; import android.os.SystemClock; +import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import android.testing.DexmakerShareClassLoaderRule; @@ -504,6 +506,36 @@ public class TouchExplorerTest { assertThat(sentRawEvent.getDisplayId()).isEqualTo(rawDisplayId); } + @Test + @DisableFlags(Flags.FLAG_POINTER_UP_MOTION_EVENT_IN_TOUCH_EXPLORATION) + public void handleMotionEventStateTouchExploring_pointerUp_doesNotSendToManager() { + mTouchExplorer.getState().setServiceDetectsGestures(true); + mTouchExplorer.getState().clear(); + + mLastEvent = pointerDownEvent(); + mTouchExplorer.getState().startTouchExploring(); + MotionEvent event = fromTouchscreen(pointerUpEvent()); + + mTouchExplorer.onMotionEvent(event, event, /*policyFlags=*/0); + + verify(mMockAms, never()).sendMotionEventToListeningServices(event); + } + + @Test + @EnableFlags(Flags.FLAG_POINTER_UP_MOTION_EVENT_IN_TOUCH_EXPLORATION) + public void handleMotionEventStateTouchExploring_pointerUp_sendsToManager() { + mTouchExplorer.getState().setServiceDetectsGestures(true); + mTouchExplorer.getState().clear(); + + mLastEvent = pointerDownEvent(); + mTouchExplorer.getState().startTouchExploring(); + MotionEvent event = fromTouchscreen(pointerUpEvent()); + + mTouchExplorer.onMotionEvent(event, event, /*policyFlags=*/0); + + verify(mMockAms).sendMotionEventToListeningServices(event); + } + /** * Used to play back event data of a gesture by parsing the log into MotionEvents and sending * them to TouchExplorer. diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchStateTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchStateTest.java new file mode 100644 index 000000000000..3e7d9fd05327 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchStateTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.accessibility.gestures; + +import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_INTERACTION_END; + +import static com.android.server.accessibility.gestures.TouchState.STATE_CLEAR; +import static com.android.server.accessibility.gestures.TouchState.STATE_TOUCH_EXPLORING; + +import static com.google.common.truth.Truth.assertThat; + +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; +import android.view.Display; + +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.accessibility.AccessibilityManagerService; +import com.android.server.accessibility.Flags; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +@RunWith(AndroidJUnit4.class) +public class TouchStateTest { + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + private TouchState mTouchState; + @Mock private AccessibilityManagerService mMockAms; + + @Before + public void setup() { + mTouchState = new TouchState(Display.DEFAULT_DISPLAY, mMockAms); + } + + @EnableFlags(Flags.FLAG_POINTER_UP_MOTION_EVENT_IN_TOUCH_EXPLORATION) + @Test + public void injectedEvent_interactionEnd_pointerDown_startsTouchExploring() { + mTouchState.mReceivedPointerTracker.mReceivedPointersDown = 1; + mTouchState.onInjectedAccessibilityEvent(TYPE_TOUCH_INTERACTION_END); + assertThat(mTouchState.getState()).isEqualTo(STATE_TOUCH_EXPLORING); + } + + @EnableFlags(Flags.FLAG_POINTER_UP_MOTION_EVENT_IN_TOUCH_EXPLORATION) + @Test + public void injectedEvent_interactionEnd_pointerUp_clears() { + mTouchState.mReceivedPointerTracker.mReceivedPointersDown = 0; + mTouchState.onInjectedAccessibilityEvent(TYPE_TOUCH_INTERACTION_END); + assertThat(mTouchState.getState()).isEqualTo(STATE_CLEAR); + } + + @DisableFlags(Flags.FLAG_POINTER_UP_MOTION_EVENT_IN_TOUCH_EXPLORATION) + @Test + public void injectedEvent_interactionEnd_clears() { + mTouchState.onInjectedAccessibilityEvent(TYPE_TOUCH_INTERACTION_END); + assertThat(mTouchState.getState()).isEqualTo(STATE_CLEAR); + } +} diff --git a/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpSqlPersistenceTest.java b/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpSqlPersistenceTest.java index 01fee7f66497..918159f9262b 100644 --- a/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpSqlPersistenceTest.java +++ b/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpSqlPersistenceTest.java @@ -97,7 +97,8 @@ public class DiscreteAppOpSqlPersistenceTest { mDiscreteRegistry.recordDiscreteAccess(opEvent2); List<DiscreteOp> discreteOps = mDiscreteRegistry.getAllDiscreteOps(); - assertThat(discreteOps.size()).isEqualTo(1); + assertWithMessage("Expected list size is 1, but the list is: " + discreteOps) + .that(discreteOps.size()).isEqualTo(1); assertThat(discreteOps).contains(opEvent); } diff --git a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java index 3ca019728c2b..fcdf88f16550 100644 --- a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java @@ -605,29 +605,6 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase { } @Test - public void testKeyGestureAccessibilityShortcutChord() { - Assert.assertTrue( - sendKeyGestureEventStart( - KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD)); - mPhoneWindowManager.moveTimeForward(5000); - Assert.assertTrue( - sendKeyGestureEventCancel( - KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD)); - mPhoneWindowManager.assertAccessibilityKeychordCalled(); - } - - @Test - public void testKeyGestureAccessibilityShortcutChordCancelled() { - Assert.assertTrue( - sendKeyGestureEventStart( - KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD)); - Assert.assertTrue( - sendKeyGestureEventCancel( - KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD)); - mPhoneWindowManager.assertAccessibilityKeychordNotCalled(); - } - - @Test public void testKeyGestureRingerToggleChord() { mPhoneWindowManager.overridePowerVolumeUp(POWER_VOLUME_UP_BEHAVIOR_MUTE); Assert.assertTrue( @@ -670,29 +647,6 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase { } @Test - public void testKeyGestureAccessibilityTvShortcutChord() { - Assert.assertTrue( - sendKeyGestureEventStart( - KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD)); - mPhoneWindowManager.moveTimeForward(5000); - Assert.assertTrue( - sendKeyGestureEventCancel( - KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD)); - mPhoneWindowManager.assertAccessibilityKeychordCalled(); - } - - @Test - public void testKeyGestureAccessibilityTvShortcutChordCancelled() { - Assert.assertTrue( - sendKeyGestureEventStart( - KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD)); - Assert.assertTrue( - sendKeyGestureEventCancel( - KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD)); - mPhoneWindowManager.assertAccessibilityKeychordNotCalled(); - } - - @Test public void testKeyGestureTvTriggerBugReport() { Assert.assertTrue( sendKeyGestureEventStart(KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT)); diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java index f88492477487..e56fd3c6272d 100644 --- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java +++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java @@ -750,11 +750,6 @@ class TestPhoneWindowManager { verify(mAccessibilityShortcutController).performAccessibilityShortcut(); } - void assertAccessibilityKeychordNotCalled() { - mTestLooper.dispatchAll(); - verify(mAccessibilityShortcutController, never()).performAccessibilityShortcut(); - } - void assertCloseAllDialogs() { verify(mContext).closeSystemDialogs(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java index 7d59f4872d37..eb6d5cf8bb14 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java @@ -21,10 +21,18 @@ import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import android.graphics.PixelFormat; +import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.view.WindowInsets; import android.view.inputmethod.Flags; import android.view.inputmethod.ImeTracker; @@ -211,4 +219,29 @@ public class ImeInsetsSourceProviderTest extends WindowTestsBase { mImeProvider.setFrozen(false); assertFalse(mImeProvider.getSource().isVisible()); } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_REFACTOR_INSETS_CONTROLLER) + public void testUpdateControlForTarget_remoteInsetsControlTarget() throws RemoteException { + final WindowState ime = newWindowBuilder("ime", TYPE_INPUT_METHOD).build(); + makeWindowVisibleAndDrawn(ime); + mImeProvider.setWindowContainer(ime, null, null); + mImeProvider.setServerVisible(true); + mImeProvider.setClientVisible(true); + final WindowState inputTarget = newWindowBuilder("app", TYPE_APPLICATION).build(); + final var displayWindowInsetsController = spy(createDisplayWindowInsetsController()); + mDisplayContent.setRemoteInsetsController(displayWindowInsetsController); + final var controlTarget = mDisplayContent.mRemoteInsetsControlTarget; + + inputTarget.setRequestedVisibleTypes( + WindowInsets.Type.defaultVisible() | WindowInsets.Type.ime()); + mDisplayContent.setImeInputTarget(inputTarget); + mDisplayContent.setImeControlTarget(controlTarget); + + assertTrue(inputTarget.isRequestedVisible(WindowInsets.Type.ime())); + assertFalse(controlTarget.isRequestedVisible(WindowInsets.Type.ime())); + mImeProvider.updateControlForTarget(controlTarget, true /* force */, null /* statsToken */); + verify(displayWindowInsetsController, times(1)).setImeInputTargetRequestedVisibility( + eq(true), 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 ae6144713a1d..5401a44d7016 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -910,7 +910,7 @@ public class WindowOrganizerTests extends WindowTestsBase { final RunningTaskInfo info2 = task2.getTaskInfo(); WindowContainerTransaction wct = new WindowContainerTransaction(); - wct.setAdjacentRoots(info1.token, info2.token); + wct.setAdjacentRootSet(info1.token, info2.token); mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); assertTrue(task1.isAdjacentTo(task2)); assertTrue(task2.isAdjacentTo(task1)); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index fbba999bfb36..14d567d141cb 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -3371,14 +3371,13 @@ public class TelephonyManager { return telephony.getDataNetworkTypeForSubscriber(subId, getOpPackageName(), getAttributionTag()); } else { - // This can happen when the ITelephony interface is not up yet. + Log.e(TAG, "getDataNetworkType: ITelephony interface is not up yet"); return NETWORK_TYPE_UNKNOWN; } - } catch(RemoteException ex) { - // This shouldn't happen in the normal case - return NETWORK_TYPE_UNKNOWN; - } catch (NullPointerException ex) { - // This could happen before phone restarts due to crashing + } catch (RemoteException // Shouldn't happen in the normal case + | NullPointerException ex // Could happen before phone restarts due to crashing + ) { + Log.e(TAG, "getDataNetworkType: " + ex.getMessage()); return NETWORK_TYPE_UNKNOWN; } } diff --git a/tests/Input/assets/testPointerScale.png b/tests/Input/assets/testPointerScale.png Binary files differindex 54d37c24afc6..781df47a5e24 100644 --- a/tests/Input/assets/testPointerScale.png +++ b/tests/Input/assets/testPointerScale.png diff --git a/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt b/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt index e99c81493394..794fd0255726 100644 --- a/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt +++ b/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt @@ -214,9 +214,5 @@ class KeyGestureEventHandlerTest { ): Boolean { return handler(event, focusedToken) } - - override fun isKeyGestureSupported(gestureType: Int): Boolean { - return true - } } } diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt index 2799f6c79215..4f1fb6487b19 100644 --- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt +++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt @@ -32,6 +32,7 @@ import android.hardware.input.InputGestureData import android.hardware.input.InputManager import android.hardware.input.InputManagerGlobal import android.hardware.input.KeyGestureEvent +import android.os.Handler import android.os.IBinder import android.os.Process import android.os.SystemClock @@ -48,9 +49,11 @@ import android.view.WindowManagerPolicyConstants.FLAG_INTERACTIVE import androidx.test.core.app.ApplicationProvider import com.android.dx.mockito.inline.extended.ExtendedMockito import com.android.internal.R +import com.android.internal.accessibility.AccessibilityShortcutController import com.android.internal.annotations.Keep import com.android.internal.util.FrameworkStatsLog import com.android.modules.utils.testing.ExtendedMockitoRule +import com.android.server.input.InputManagerService.WindowManagerCallbacks import java.io.File import java.io.FileOutputStream import java.io.InputStream @@ -67,6 +70,8 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito +import org.mockito.kotlin.never +import org.mockito.kotlin.times /** * Tests for {@link KeyGestureController}. @@ -102,6 +107,7 @@ class KeyGestureControllerTests { const val SETTINGS_KEY_BEHAVIOR_SETTINGS_ACTIVITY = 0 const val SETTINGS_KEY_BEHAVIOR_NOTIFICATION_PANEL = 1 const val SETTINGS_KEY_BEHAVIOR_NOTHING = 2 + const val TEST_PID = 10 } @JvmField @@ -116,11 +122,10 @@ class KeyGestureControllerTests { @Rule val rule = SetFlagsRule() - @Mock - private lateinit var iInputManager: IInputManager - - @Mock - private lateinit var packageManager: PackageManager + @Mock private lateinit var iInputManager: IInputManager + @Mock private lateinit var packageManager: PackageManager + @Mock private lateinit var wmCallbacks: WindowManagerCallbacks + @Mock private lateinit var accessibilityShortcutController: AccessibilityShortcutController private var currentPid = 0 private lateinit var context: Context @@ -207,8 +212,34 @@ class KeyGestureControllerTests { private fun setupKeyGestureController() { keyGestureController = - KeyGestureController(context, testLooper.looper, testLooper.looper, inputDataStore) - Mockito.`when`(iInputManager.getAppLaunchBookmarks()) + KeyGestureController( + context, + testLooper.looper, + testLooper.looper, + inputDataStore, + object : KeyGestureController.Injector() { + override fun getAccessibilityShortcutController( + context: Context?, + handler: Handler? + ): AccessibilityShortcutController { + return accessibilityShortcutController + } + }) + Mockito.`when`(iInputManager.registerKeyGestureHandler(Mockito.any())) + .thenAnswer { + val args = it.arguments + if (args[0] != null) { + keyGestureController.registerKeyGestureHandler( + args[0] as IKeyGestureHandler, + TEST_PID + ) + } + } + keyGestureController.setWindowManagerCallbacks(wmCallbacks) + Mockito.`when`(wmCallbacks.isKeyguardLocked(Mockito.anyInt())).thenReturn(false) + Mockito.`when`(accessibilityShortcutController + .isAccessibilityShortcutAvailable(Mockito.anyBoolean())).thenReturn(true) + Mockito.`when`(iInputManager.appLaunchBookmarks) .thenReturn(keyGestureController.appLaunchBookmarks) keyGestureController.systemRunning() testLooper.dispatchAll() @@ -1270,9 +1301,9 @@ class KeyGestureControllerTests { ) ), TestData( - "BACK + DPAD_DOWN -> TV Accessibility Chord", + "BACK + DPAD_DOWN -> Accessibility Chord(for TV)", intArrayOf(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN), - KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD, + KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD, intArrayOf(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN), 0, intArrayOf( @@ -1622,6 +1653,52 @@ class KeyGestureControllerTests { ) } + @Test + fun testAccessibilityShortcutChordPressed() { + setupKeyGestureController() + + sendKeys( + intArrayOf(KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN), + // Assuming this value is always greater than the accessibility shortcut timeout, which + // currently defaults to 3000ms + timeDelayMs = 10000 + ) + Mockito.verify(accessibilityShortcutController, times(1)).performAccessibilityShortcut() + } + + @Test + fun testAccessibilityTvShortcutChordPressed() { + setupKeyGestureController() + + sendKeys( + intArrayOf(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN), + timeDelayMs = 10000 + ) + Mockito.verify(accessibilityShortcutController, times(1)).performAccessibilityShortcut() + } + + @Test + fun testAccessibilityShortcutChordPressedForLessThanTimeout() { + setupKeyGestureController() + + sendKeys( + intArrayOf(KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN), + timeDelayMs = 0 + ) + Mockito.verify(accessibilityShortcutController, never()).performAccessibilityShortcut() + } + + @Test + fun testAccessibilityTvShortcutChordPressedForLessThanTimeout() { + setupKeyGestureController() + + sendKeys( + intArrayOf(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN), + timeDelayMs = 0 + ) + Mockito.verify(accessibilityShortcutController, never()).performAccessibilityShortcut() + } + private fun testKeyGestureInternal(test: TestData) { val handledEvents = mutableListOf<KeyGestureEvent>() val handler = KeyGestureHandler { event, _ -> @@ -1683,7 +1760,11 @@ class KeyGestureControllerTests { assertEquals("Test: $testName should not produce Key gesture", 0, handledEvents.size) } - private fun sendKeys(testKeys: IntArray, assertNotSentToApps: Boolean = false) { + private fun sendKeys( + testKeys: IntArray, + assertNotSentToApps: Boolean = false, + timeDelayMs: Long = 0 + ) { var metaState = 0 val now = SystemClock.uptimeMillis() for (key in testKeys) { @@ -1699,6 +1780,11 @@ class KeyGestureControllerTests { testLooper.dispatchAll() } + if (timeDelayMs > 0) { + testLooper.moveTimeForward(timeDelayMs) + testLooper.dispatchAll() + } + for (key in testKeys.reversed()) { val upEvent = KeyEvent( now, now, KeyEvent.ACTION_UP, key, 0 /*repeat*/, metaState, @@ -1742,9 +1828,5 @@ class KeyGestureControllerTests { override fun handleKeyGesture(event: AidlKeyGestureEvent, token: IBinder?): Boolean { return handler(event, token) } - - override fun isKeyGestureSupported(gestureType: Int): Boolean { - return true - } } } diff --git a/tests/testables/src/android/testing/TestableLooper.java b/tests/testables/src/android/testing/TestableLooper.java index 8cd89ce89e83..6b099450064f 100644 --- a/tests/testables/src/android/testing/TestableLooper.java +++ b/tests/testables/src/android/testing/TestableLooper.java @@ -75,16 +75,7 @@ public class TestableLooper { * Baklava introduces new {@link TestLooperManager} APIs that we can use instead of reflection. */ private static boolean isAtLeastBaklava() { - Method[] methods = TestLooperManager.class.getMethods(); - for (Method method : methods) { - if (method.getName().equals("peekWhen")) { - return true; - } - } - return false; - // TODO(shayba): delete the above, uncomment the below. - // SDK_INT has not yet ramped to Baklava in all 25Q2 builds. - // return Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA; + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA; } static { @@ -247,6 +238,36 @@ public class TestableLooper { while (processQueuedMessages() != 0) ; } + public long peekWhen() { + if (isAtLeastBaklava()) { + return peekWhenBaklava(); + } else { + return peekWhenLegacy(); + } + } + + private long peekWhenBaklava() { + Long when = mQueueWrapper.peekWhen(); + if (when != null) { + return when; + } else { + return 0; + } + } + + private long peekWhenLegacy() { + try { + Message msg = (Message) MESSAGE_QUEUE_MESSAGES_FIELD.get(mLooper.getQueue()); + if (msg != null) { + return msg.getWhen(); + } else { + return 0; + } + } catch (IllegalAccessException e) { + throw new RuntimeException("Access failed in TestableLooper: set - Message.when", e); + } + } + public void moveTimeForward(long milliSeconds) { if (isAtLeastBaklava()) { moveTimeForwardBaklava(milliSeconds); diff --git a/tests/utils/testutils/java/android/os/test/TestLooper.java b/tests/utils/testutils/java/android/os/test/TestLooper.java index 4d379e45a81a..bb54a26036db 100644 --- a/tests/utils/testutils/java/android/os/test/TestLooper.java +++ b/tests/utils/testutils/java/android/os/test/TestLooper.java @@ -68,16 +68,7 @@ public class TestLooper { * Baklava introduces new {@link TestLooperManager} APIs that we can use instead of reflection. */ private static boolean isAtLeastBaklava() { - Method[] methods = TestLooperManager.class.getMethods(); - for (Method method : methods) { - if (method.getName().equals("peekWhen")) { - return true; - } - } - return false; - // TODO(shayba): delete the above, uncomment the below. - // SDK_INT has not yet ramped to Baklava in all 25Q2 builds. - // return Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA; + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA; } static { diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h index 0d261abd728d..e51477c668dd 100644 --- a/tools/aapt2/Resource.h +++ b/tools/aapt2/Resource.h @@ -249,6 +249,8 @@ struct ResourceFile { // Flag std::optional<FeatureFlagAttribute> flag; + + bool uses_readwrite_feature_flags = false; }; /** diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp index 5435cba290fc..db7dddc49a99 100644 --- a/tools/aapt2/ResourceTable.cpp +++ b/tools/aapt2/ResourceTable.cpp @@ -664,6 +664,7 @@ bool ResourceTable::AddResource(NewResource&& res, android::IDiagnostics* diag) if (!config_value->value) { // Resource does not exist, add it now. config_value->value = std::move(res.value); + config_value->uses_readwrite_feature_flags = res.uses_readwrite_feature_flags; } else { // When validation is enabled, ensure that a resource cannot have multiple values defined for // the same configuration unless protected by flags. @@ -681,12 +682,14 @@ bool ResourceTable::AddResource(NewResource&& res, android::IDiagnostics* diag) ConfigKey{&res.config, res.product}, lt_config_key_ref()), util::make_unique<ResourceConfigValue>(res.config, res.product)); (*it)->value = std::move(res.value); + (*it)->uses_readwrite_feature_flags = res.uses_readwrite_feature_flags; break; } case CollisionResult::kTakeNew: // Take the incoming value. config_value->value = std::move(res.value); + config_value->uses_readwrite_feature_flags = res.uses_readwrite_feature_flags; break; case CollisionResult::kConflict: @@ -843,6 +846,12 @@ NewResourceBuilder& NewResourceBuilder::SetAllowMangled(bool allow_mangled) { return *this; } +NewResourceBuilder& NewResourceBuilder::SetUsesReadWriteFeatureFlags( + bool uses_readwrite_feature_flags) { + res_.uses_readwrite_feature_flags = uses_readwrite_feature_flags; + return *this; +} + NewResource NewResourceBuilder::Build() { return std::move(res_); } diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h index b0e185536d16..778b43adb50b 100644 --- a/tools/aapt2/ResourceTable.h +++ b/tools/aapt2/ResourceTable.h @@ -104,6 +104,9 @@ class ResourceConfigValue { // The actual Value. std::unique_ptr<Value> value; + // Whether the value uses read/write feature flags + bool uses_readwrite_feature_flags = false; + ResourceConfigValue(const android::ConfigDescription& config, android::StringPiece product) : config(config), product(product) { } @@ -284,6 +287,7 @@ struct NewResource { std::optional<AllowNew> allow_new; std::optional<StagedId> staged_id; bool allow_mangled = false; + bool uses_readwrite_feature_flags = false; }; struct NewResourceBuilder { @@ -297,6 +301,7 @@ struct NewResourceBuilder { NewResourceBuilder& SetAllowNew(AllowNew allow_new); NewResourceBuilder& SetStagedId(StagedId id); NewResourceBuilder& SetAllowMangled(bool allow_mangled); + NewResourceBuilder& SetUsesReadWriteFeatureFlags(bool uses_feature_flags); NewResource Build(); private: diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index 2a7921600477..755dbb6f8e42 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -673,11 +673,13 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv // Update the output format of this XML file. file_ref->type = XmlFileTypeForOutputFormat(options_.output_format); - bool result = table->AddResource(NewResourceBuilder(file.name) - .SetValue(std::move(file_ref), file.config) - .SetAllowMangled(true) - .Build(), - context_->GetDiagnostics()); + bool result = table->AddResource( + NewResourceBuilder(file.name) + .SetValue(std::move(file_ref), file.config) + .SetAllowMangled(true) + .SetUsesReadWriteFeatureFlags(doc->file.uses_readwrite_feature_flags) + .Build(), + context_->GetDiagnostics()); if (!result) { return false; } diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp index 2e20e8175213..bac871b8bdc3 100644 --- a/tools/aapt2/format/binary/BinaryResourceParser.cpp +++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp @@ -414,6 +414,8 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package, .SetId(res_id, OnIdConflict::CREATE_ENTRY) .SetAllowMangled(true); + res_builder.SetUsesReadWriteFeatureFlags(entry->uses_feature_flags()); + if (entry->flags() & ResTable_entry::FLAG_PUBLIC) { Visibility visibility{Visibility::Level::kPublic}; diff --git a/tools/aapt2/format/binary/ResEntryWriter.cpp b/tools/aapt2/format/binary/ResEntryWriter.cpp index 9dc205f4c1ba..0be392164453 100644 --- a/tools/aapt2/format/binary/ResEntryWriter.cpp +++ b/tools/aapt2/format/binary/ResEntryWriter.cpp @@ -199,6 +199,10 @@ void WriteEntry(const FlatEntry* entry, T* out_result, bool compact = false) { flags |= ResTable_entry::FLAG_WEAK; } + if (entry->uses_readwrite_feature_flags) { + flags |= ResTable_entry::FLAG_USES_FEATURE_FLAGS; + } + if constexpr (std::is_same_v<ResTable_entry_ext, T>) { flags |= ResTable_entry::FLAG_COMPLEX; } diff --git a/tools/aapt2/format/binary/ResEntryWriter.h b/tools/aapt2/format/binary/ResEntryWriter.h index c11598ec12f7..f54b29aa8f2a 100644 --- a/tools/aapt2/format/binary/ResEntryWriter.h +++ b/tools/aapt2/format/binary/ResEntryWriter.h @@ -38,6 +38,8 @@ struct FlatEntry { // The entry string pool index to the entry's name. uint32_t entry_key; + + bool uses_readwrite_feature_flags; }; // Pair of ResTable_entry and Res_value. These pairs are stored sequentially in values buffer. diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp index 1a82021bce71..50144ae816b6 100644 --- a/tools/aapt2/format/binary/TableFlattener.cpp +++ b/tools/aapt2/format/binary/TableFlattener.cpp @@ -502,7 +502,8 @@ class PackageFlattener { // Group values by configuration. for (auto& config_value : entry.values) { config_to_entry_list_map[config_value->config].push_back( - FlatEntry{&entry, config_value->value.get(), local_key_index}); + FlatEntry{&entry, config_value->value.get(), local_key_index, + config_value->uses_readwrite_feature_flags}); } } diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp index 0f1168514c4a..9156b96b67ec 100644 --- a/tools/aapt2/format/binary/TableFlattener_test.cpp +++ b/tools/aapt2/format/binary/TableFlattener_test.cpp @@ -1069,4 +1069,23 @@ TEST_F(TableFlattenerTest, FlattenTypeEntryWithNameCollapseInExemption) { testing::IsTrue()); } +TEST_F(TableFlattenerTest, UsesReadWriteFeatureFlagSerializesCorrectly) { + std::unique_ptr<ResourceTable> table = + test::ResourceTableBuilder() + .Add(NewResourceBuilder("com.app.a:color/foo") + .SetValue(util::make_unique<BinaryPrimitive>( + uint8_t(Res_value::TYPE_INT_COLOR_ARGB8), 0xffaabbcc)) + .SetUsesReadWriteFeatureFlags(true) + .SetId(0x7f020000) + .Build()) + .Build(); + ResTable res_table; + TableFlattenerOptions options; + ASSERT_TRUE(Flatten(context_.get(), options, table.get(), &res_table)); + + uint32_t flags; + ASSERT_TRUE(res_table.getResourceEntryFlags(0x7f020000, &flags)); + ASSERT_EQ(flags, ResTable_entry::FLAG_USES_FEATURE_FLAGS); +} + } // namespace aapt diff --git a/tools/aapt2/link/FlaggedResources_test.cpp b/tools/aapt2/link/FlaggedResources_test.cpp index dbef77615515..47a71fe36e9f 100644 --- a/tools/aapt2/link/FlaggedResources_test.cpp +++ b/tools/aapt2/link/FlaggedResources_test.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ +#include <regex> +#include <string> + #include "LoadedApk.h" #include "cmd/Dump.h" #include "io/StringStream.h" @@ -183,4 +186,49 @@ TEST_F(FlaggedResourcesTest, ReadWriteFlagInPathFails) { "Only read only flags may be used with resources: test.package.rwFlag")); } +TEST_F(FlaggedResourcesTest, ReadWriteFlagInXmlGetsFlagged) { + auto apk_path = file::BuildPath({android::base::GetExecutableDirectory(), "resapp.apk"}); + auto loaded_apk = LoadedApk::LoadApkFromPath(apk_path, &noop_diag); + + std::string output; + DumpChunksToString(loaded_apk.get(), &output); + + // The actual line looks something like: + // [ResTable_entry] id: 0x0000 name: layout1 keyIndex: 14 size: 8 flags: 0x0010 + // + // This regex matches that line and captures the name and the flag value for checking. + std::regex regex("[0-9a-zA-Z:_\\]\\[ ]+name: ([0-9a-zA-Z]+)[0-9a-zA-Z: ]+flags: (0x\\d{4})"); + std::smatch match; + + std::stringstream ss(output); + std::string line; + bool found = false; + int fields_flagged = 0; + while (std::getline(ss, line)) { + bool first_line = false; + if (line.contains("config: v36")) { + std::getline(ss, line); + first_line = true; + } + if (!line.contains("flags")) { + continue; + } + if (std::regex_search(line, match, regex) && (match.size() == 3)) { + unsigned int hex_value; + std::stringstream hex_ss; + hex_ss << std::hex << match[2]; + hex_ss >> hex_value; + if (hex_value & android::ResTable_entry::FLAG_USES_FEATURE_FLAGS) { + fields_flagged++; + if (first_line && match[1] == "layout1") { + found = true; + } + } + } + } + ASSERT_TRUE(found) << "No entry for layout1 at v36 with FLAG_USES_FEATURE_FLAGS bit set"; + // There should only be 1 entry that has the FLAG_USES_FEATURE_FLAGS bit of flags set to 1 + ASSERT_EQ(fields_flagged, 1); +} + } // namespace aapt diff --git a/tools/aapt2/link/FlaggedXmlVersioner.cpp b/tools/aapt2/link/FlaggedXmlVersioner.cpp index 75c6f17dcb51..8a3337c446cb 100644 --- a/tools/aapt2/link/FlaggedXmlVersioner.cpp +++ b/tools/aapt2/link/FlaggedXmlVersioner.cpp @@ -66,6 +66,28 @@ class AllDisabledFlagsVisitor : public xml::Visitor { bool had_flags_ = false; }; +// An xml visitor that goes through the a doc and determines if any elements are behind a flag. +class FindFlagsVisitor : public xml::Visitor { + public: + void Visit(xml::Element* node) override { + if (had_flags_) { + return; + } + auto* attr = node->FindAttribute(xml::kSchemaAndroid, xml::kAttrFeatureFlag); + if (attr != nullptr) { + had_flags_ = true; + return; + } + VisitChildren(node); + } + + bool HadFlags() const { + return had_flags_; + } + + bool had_flags_ = false; +}; + std::vector<std::unique_ptr<xml::XmlResource>> FlaggedXmlVersioner::Process(IAaptContext* context, xml::XmlResource* doc) { std::vector<std::unique_ptr<xml::XmlResource>> docs; @@ -74,15 +96,20 @@ std::vector<std::unique_ptr<xml::XmlResource>> FlaggedXmlVersioner::Process(IAap // Support for read/write flags was added in baklava so if the doc will only get used on // baklava or later we can just return the original doc. docs.push_back(doc->Clone()); + FindFlagsVisitor visitor; + doc->root->Accept(&visitor); + docs.back()->file.uses_readwrite_feature_flags = visitor.HadFlags(); } else { auto preBaklavaVersion = doc->Clone(); AllDisabledFlagsVisitor visitor; preBaklavaVersion->root->Accept(&visitor); + preBaklavaVersion->file.uses_readwrite_feature_flags = false; docs.push_back(std::move(preBaklavaVersion)); if (visitor.HadFlags()) { auto baklavaVersion = doc->Clone(); baklavaVersion->file.config.sdkVersion = SDK_BAKLAVA; + baklavaVersion->file.uses_readwrite_feature_flags = true; docs.push_back(std::move(baklavaVersion)); } } |